From 454c600004035776e87e80312ffcfa0b5645b44a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 29 Jul 2024 14:26:16 -0400 Subject: [PATCH 01/11] Detect non-lifetime binder params shadowing item params --- compiler/rustc_resolve/src/late.rs | 20 ++++----- tests/crashes/119716-2.rs | 2 +- ...icates-of-no-entry-found-for-key-119275.rs | 7 +-- ...es-of-no-entry-found-for-key-119275.stderr | 15 +++++-- .../traits/non_lifetime_binders/shadowed.rs | 18 ++++++++ .../non_lifetime_binders/shadowed.stderr | 44 +++++++++++++++++++ 6 files changed, 89 insertions(+), 17 deletions(-) create mode 100644 tests/ui/traits/non_lifetime_binders/shadowed.rs create mode 100644 tests/ui/traits/non_lifetime_binders/shadowed.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7e5fd82b80cee..f844930ad265e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2671,17 +2671,17 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Store all seen lifetimes names from outer scopes. let mut seen_lifetimes = FxHashSet::default(); - // We also can't shadow bindings from the parent item - if let RibKind::AssocItem = kind { - let mut add_bindings_for_ns = |ns| { - let parent_rib = self.ribs[ns] - .iter() - .rfind(|r| matches!(r.kind, RibKind::Item(..))) - .expect("associated item outside of an item"); + // We also can't shadow bindings from associated parent items. + for ns in [ValueNS, TypeNS] { + for parent_rib in self.ribs[ns].iter().rev() { seen_bindings.extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span))); - }; - add_bindings_for_ns(ValueNS); - add_bindings_for_ns(TypeNS); + + // Break at mod level, to account for nested items which are + // allowed to shadow generic param names. + if matches!(parent_rib.kind, RibKind::Module(..)) { + break; + } + } } // Forbid shadowing lifetime bindings diff --git a/tests/crashes/119716-2.rs b/tests/crashes/119716-2.rs index 9cdc4417f5ba9..47bffb5c1de0d 100644 --- a/tests/crashes/119716-2.rs +++ b/tests/crashes/119716-2.rs @@ -1,4 +1,4 @@ //@ known-bug: #119716 #![feature(non_lifetime_binders)] trait Trait {} -fn f() -> impl for Trait> {} +fn f() -> impl for Trait> {} diff --git a/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.rs b/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.rs index 4ba696f4ae080..9f20cf0857947 100644 --- a/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.rs +++ b/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.rs @@ -9,9 +9,10 @@ fn bug(&self) where for [(); COT::BYTES]:, //~^ ERROR only lifetime parameters can be used in this context - //~^^ ERROR defaults for generic parameters are not allowed in `for<...>` binders - //~^^^ ERROR defaults for generic parameters are not allowed in `for<...>` binders - //~^^^^ ERROR failed to resolve: use of undeclared type `COT` + //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders + //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders + //~| ERROR failed to resolve: use of undeclared type `COT` + //~| ERROR the name `N` is already used for a generic parameter in this item's generic parameters { } diff --git a/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.stderr b/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.stderr index ee0ec38ab0631..6037e685e44d7 100644 --- a/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.stderr +++ b/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.stderr @@ -6,6 +6,15 @@ LL | fn bug(&self) | = note: associated functions are those in `impl` or `trait` definitions +error[E0403]: the name `N` is already used for a generic parameter in this item's generic parameters + --> $DIR/ice-predicates-of-no-entry-found-for-key-119275.rs:10:15 + | +LL | fn bug(&self) + | - first use of `N` +... +LL | for [(); COT::BYTES]:, + | ^ already used + error[E0412]: cannot find type `Nat` in this scope --> $DIR/ice-predicates-of-no-entry-found-for-key-119275.rs:6:17 | @@ -40,7 +49,7 @@ error[E0433]: failed to resolve: use of undeclared type `COT` LL | for [(); COT::BYTES]:, | ^^^ use of undeclared type `COT` -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0412, E0433, E0658. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0403, E0412, E0433, E0658. +For more information about an error, try `rustc --explain E0403`. diff --git a/tests/ui/traits/non_lifetime_binders/shadowed.rs b/tests/ui/traits/non_lifetime_binders/shadowed.rs new file mode 100644 index 0000000000000..1c480e3940b89 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/shadowed.rs @@ -0,0 +1,18 @@ +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +fn function() where for (): Sized {} +//~^ ERROR the name `T` is already used for a generic parameter + +struct Struct(T) where for (): Sized; +//~^ ERROR the name `T` is already used for a generic parameter + +impl Struct { + fn method() where for (): Sized {} + //~^ ERROR the name `T` is already used for a generic parameter +} + +fn repeated() where for (): Sized {} +//~^ ERROR the name `T` is already used for a generic parameter + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/shadowed.stderr b/tests/ui/traits/non_lifetime_binders/shadowed.stderr new file mode 100644 index 0000000000000..59a073aefc961 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/shadowed.stderr @@ -0,0 +1,44 @@ +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters + --> $DIR/shadowed.rs:4:28 + | +LL | fn function() where for (): Sized {} + | - ^ already used + | | + | first use of `T` + +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters + --> $DIR/shadowed.rs:7:31 + | +LL | struct Struct(T) where for (): Sized; + | - ^ already used + | | + | first use of `T` + +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters + --> $DIR/shadowed.rs:11:27 + | +LL | impl Struct { + | - first use of `T` +LL | fn method() where for (): Sized {} + | ^ already used + +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters + --> $DIR/shadowed.rs:15:28 + | +LL | fn repeated() where for (): Sized {} + | - ^ already used + | | + | first use of `T` + +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/shadowed.rs:1:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 4 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0403`. From d280b8ca14edea616af39f0f0642f1aeb6714243 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 29 Jul 2024 00:51:33 +0200 Subject: [PATCH 02/11] CI: rfl: build the generated doctests We were already generating the doctests, which should already catch most issues with our hack around `--test-builder` and `--no-run`. However, we were not building the result of that transformation, thus build it for completeness and to ensure the hack may not have produced something completely broken. In the worst case, we can revert it. Signed-off-by: Miguel Ojeda --- src/ci/docker/scripts/rfl-build.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index 3acc09e0b9b1a..4e3079b35cac6 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -65,4 +65,5 @@ make -C linux LLVM=1 -j$(($(nproc) + 1)) \ make -C linux LLVM=1 -j$(($(nproc) + 1)) \ samples/rust/rust_minimal.o \ samples/rust/rust_print.o \ - drivers/net/phy/ax88796b_rust.o + drivers/net/phy/ax88796b_rust.o \ + rust/doctests_kernel_generated.o From 77cc18fd79073beada6dcd1e392be7996683503d Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 29 Jul 2024 23:03:26 +0200 Subject: [PATCH 03/11] CI: rfl: build the documentation Since the `rfl` CI job has not had almost any issue for some weeks, it is a good time to try to increase a bit the scope of what it tests. The kernel does not use any particular `rustdoc` unstable issue (apart from the doctests ones) so far, so in principle it should not introduce extra issues here, and may be a good extra test case for Rust. In addition, it may help to test new unstable features in the future. In the worst case, we can revert it. Signed-off-by: Miguel Ojeda --- src/ci/docker/scripts/rfl-build.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index 4e3079b35cac6..d690aac27fae6 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -67,3 +67,6 @@ make -C linux LLVM=1 -j$(($(nproc) + 1)) \ samples/rust/rust_print.o \ drivers/net/phy/ax88796b_rust.o \ rust/doctests_kernel_generated.o + +make -C linux LLVM=1 -j$(($(nproc) + 1)) \ + rustdoc From e4076e34f8215cff65c4deaff4ba7fbda20d2a7f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 29 Jul 2024 21:21:15 -0400 Subject: [PATCH 04/11] Mark Parser::eat/check methods as must_use --- .../rustc_builtin_macros/src/pattern_type.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 5 +++-- compiler/rustc_parse/src/parser/generics.rs | 3 ++- compiler/rustc_parse/src/parser/item.rs | 7 ++++--- compiler/rustc_parse/src/parser/mod.rs | 19 +++++++++++++++---- compiler/rustc_parse/src/parser/path.rs | 3 ++- tests/crashes/123809.rs | 2 +- tests/ui/type/pattern_types/missing-is.rs | 8 ++++++++ tests/ui/type/pattern_types/missing-is.stderr | 8 ++++++++ 9 files changed, 44 insertions(+), 13 deletions(-) create mode 100644 tests/ui/type/pattern_types/missing-is.rs create mode 100644 tests/ui/type/pattern_types/missing-is.stderr diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index 87187125541b2..869d203f68eba 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -24,7 +24,7 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P let mut parser = cx.new_parser_from_tts(stream); let ty = parser.parse_ty()?; - parser.eat_keyword(sym::is); + parser.expect_keyword(sym::is)?; let pat = parser.parse_pat_no_top_alt(None, None)?; Ok((ty, pat)) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index a242dc5cd582d..a4d9d97045d2a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3153,7 +3153,8 @@ impl<'a> Parser<'a> { if !require_comma { arm_body = Some(expr); - this.eat(&token::Comma); + // Eat a comma if it exists, though. + let _ = this.eat(&token::Comma); Ok(Recovered::No) } else if let Some((span, guar)) = this.parse_arm_body_missing_braces(&expr, arrow_span) @@ -3654,7 +3655,7 @@ impl<'a> Parser<'a> { fields.push(f); } self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore); - self.eat(&token::Comma); + let _ = self.eat(&token::Comma); } } } diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index a67e3d05551db..9124c15707de5 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -178,7 +178,8 @@ impl<'a> Parser<'a> { span: this.prev_token.span, }); - this.eat(&token::Comma); + // Eat a trailing comma, if it exists. + let _ = this.eat(&token::Comma); } let param = if this.check_lifetime() { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 68da055494528..baa5eb2df635d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1192,13 +1192,14 @@ impl<'a> Parser<'a> { mut safety: Safety, ) -> PResult<'a, ItemInfo> { let abi = self.parse_abi(); // ABI? + // FIXME: This recovery should be tested better. if safety == Safety::Default && self.token.is_keyword(kw::Unsafe) && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Brace)) { self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err().emit(); safety = Safety::Unsafe(self.token.span); - self.eat_keyword(kw::Unsafe); + let _ = self.eat_keyword(kw::Unsafe); } let module = ast::ForeignMod { safety, @@ -1759,7 +1760,7 @@ impl<'a> Parser<'a> { } } } - self.eat(&token::CloseDelim(Delimiter::Brace)); + self.expect(&token::CloseDelim(Delimiter::Brace))?; } else { let token_str = super::token_descr(&self.token); let where_str = if parsed_where { "" } else { "`where`, or " }; @@ -1902,7 +1903,7 @@ impl<'a> Parser<'a> { if let Some(_guar) = guar { // Handle a case like `Vec>,` where we can continue parsing fields // after the comma - self.eat(&token::Comma); + let _ = self.eat(&token::Comma); // `check_trailing_angle_brackets` already emitted a nicer error, as // proven by the presence of `_guar`. We can continue parsing. diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 26ee5bfdee42c..e01f605722b72 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -547,6 +547,7 @@ impl<'a> Parser<'a> { } #[inline] + #[must_use] fn check_noexpect(&self, tok: &TokenKind) -> bool { self.token == *tok } @@ -556,6 +557,7 @@ impl<'a> Parser<'a> { /// the main purpose of this function is to reduce the cluttering of the suggestions list /// which using the normal eat method could introduce in some cases. #[inline] + #[must_use] fn eat_noexpect(&mut self, tok: &TokenKind) -> bool { let is_present = self.check_noexpect(tok); if is_present { @@ -566,6 +568,7 @@ impl<'a> Parser<'a> { /// Consumes a token 'tok' if it exists. Returns whether the given token was present. #[inline] + #[must_use] pub fn eat(&mut self, tok: &TokenKind) -> bool { let is_present = self.check(tok); if is_present { @@ -577,12 +580,14 @@ impl<'a> Parser<'a> { /// If the next token is the given keyword, returns `true` without eating it. /// An expectation is also added for diagnostics purposes. #[inline] + #[must_use] fn check_keyword(&mut self, kw: Symbol) -> bool { self.expected_tokens.push(TokenType::Keyword(kw)); self.token.is_keyword(kw) } #[inline] + #[must_use] fn check_keyword_case(&mut self, kw: Symbol, case: Case) -> bool { if self.check_keyword(kw) { return true; @@ -602,6 +607,7 @@ impl<'a> Parser<'a> { /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes. // Public for rustc_builtin_macros and rustfmt usage. #[inline] + #[must_use] pub fn eat_keyword(&mut self, kw: Symbol) -> bool { if self.check_keyword(kw) { self.bump(); @@ -615,6 +621,7 @@ impl<'a> Parser<'a> { /// If the case differs (and is ignored) an error is issued. /// This is useful for recovery. #[inline] + #[must_use] fn eat_keyword_case(&mut self, kw: Symbol, case: Case) -> bool { if self.eat_keyword(kw) { return true; @@ -636,6 +643,7 @@ impl<'a> Parser<'a> { /// Otherwise, returns `false`. No expectation is added. // Public for rustc_builtin_macros usage. #[inline] + #[must_use] pub fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool { if self.token.is_keyword(kw) { self.bump(); @@ -648,7 +656,7 @@ impl<'a> Parser<'a> { /// If the given word is not a keyword, signals an error. /// If the next token is not the given word, signals an error. /// Otherwise, eats it. - fn expect_keyword(&mut self, kw: Symbol) -> PResult<'a, ()> { + pub fn expect_keyword(&mut self, kw: Symbol) -> PResult<'a, ()> { if !self.eat_keyword(kw) { self.unexpected() } else { Ok(()) } } @@ -1025,8 +1033,11 @@ impl<'a> Parser<'a> { f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, (ThinVec, Trailing)> { let (val, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; - if matches!(recovered, Recovered::No) { - self.eat(ket); + if matches!(recovered, Recovered::No) && !self.eat(ket) { + self.dcx().span_delayed_bug( + self.token.span, + "recovered but `parse_seq_to_before_end` did not give us the ket token", + ); } Ok((val, trailing)) } @@ -1250,7 +1261,7 @@ impl<'a> Parser<'a> { if pat { self.psess.gated_spans.gate(sym::inline_const_pat, span); } - self.eat_keyword(kw::Const); + self.expect_keyword(kw::Const)?; let (attrs, blk) = self.parse_inner_attrs_and_block()?; let anon_const = AnonConst { id: DUMMY_NODE_ID, diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index c5111226d3783..70d2c98d4f1bd 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -313,7 +313,8 @@ impl<'a> Parser<'a> { } // Generic arguments are found - `<`, `(`, `::<` or `::(`. - self.eat(&token::PathSep); + // First, eat `::` if it exists. + let _ = self.eat(&token::PathSep); let lo = self.token.span; let args = if self.eat_lt() { // `<'a, T, A = U>` diff --git a/tests/crashes/123809.rs b/tests/crashes/123809.rs index c7a633aed018c..75abe6dc0cd83 100644 --- a/tests/crashes/123809.rs +++ b/tests/crashes/123809.rs @@ -1,4 +1,4 @@ //@ known-bug: #123809 -type Positive = std::pat::pattern_type!(std::pat:: is 0..); +type Positive = std::pat::pattern_type!(std::pat is 0..); pub fn main() {} diff --git a/tests/ui/type/pattern_types/missing-is.rs b/tests/ui/type/pattern_types/missing-is.rs new file mode 100644 index 0000000000000..2fbcc1908efcb --- /dev/null +++ b/tests/ui/type/pattern_types/missing-is.rs @@ -0,0 +1,8 @@ +#![feature(core_pattern_type, core_pattern_types)] + +use std::pat::pattern_type; + +fn main() { + let x: pattern_type!(i32 0..1); + //~^ ERROR expected one of `!`, `(`, `+`, `::`, `<`, or `is`, found `0` +} diff --git a/tests/ui/type/pattern_types/missing-is.stderr b/tests/ui/type/pattern_types/missing-is.stderr new file mode 100644 index 0000000000000..8ed654fe9071a --- /dev/null +++ b/tests/ui/type/pattern_types/missing-is.stderr @@ -0,0 +1,8 @@ +error: expected one of `!`, `(`, `+`, `::`, `<`, or `is`, found `0` + --> $DIR/missing-is.rs:6:30 + | +LL | let x: pattern_type!(i32 0..1); + | ^ expected one of `!`, `(`, `+`, `::`, `<`, or `is` + +error: aborting due to 1 previous error + From d8bc8761a5bb8456c0b7940434b3b3b4f0ed035c Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Tue, 2 Jul 2024 23:52:16 -0500 Subject: [PATCH 05/11] Deny unsafe on more builtin attributes --- .../src/cfg_accessible.rs | 2 + compiler/rustc_builtin_macros/src/derive.rs | 2 + compiler/rustc_builtin_macros/src/util.rs | 2 + compiler/rustc_expand/src/config.rs | 16 +- compiler/rustc_parse/src/validate_attr.rs | 148 +++++++++++------- .../unsafe/derive-unsafe-attributes.rs | 3 + .../unsafe/derive-unsafe-attributes.stderr | 10 +- .../unsafe/extraneous-unsafe-attributes.rs | 31 ++++ .../extraneous-unsafe-attributes.stderr | 66 ++++++++ .../unsafe/proc-unsafe-attributes.rs | 27 ++++ .../unsafe/proc-unsafe-attributes.stderr | 58 +++++++ 11 files changed, 307 insertions(+), 58 deletions(-) create mode 100644 tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs create mode 100644 tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr create mode 100644 tests/ui/attributes/unsafe/proc-unsafe-attributes.rs create mode 100644 tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index 2d4a93776bb66..006b6aa823fbf 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -47,11 +47,13 @@ impl MultiItemModifier for Expander { ) -> ExpandResult, Annotatable> { let template = AttributeTemplate { list: Some("path"), ..Default::default() }; validate_attr::check_builtin_meta_item( + &ecx.ecfg.features, &ecx.sess.psess, meta_item, ast::AttrStyle::Outer, sym::cfg_accessible, template, + true, ); let Some(path) = validate_input(ecx, meta_item) else { diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 03970a48638a0..c540ff4e1de82 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -38,11 +38,13 @@ impl MultiItemModifier for Expander { let template = AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() }; validate_attr::check_builtin_meta_item( + features, &sess.psess, meta_item, ast::AttrStyle::Outer, sym::derive, template, + true, ); let mut resolutions = match &meta_item.kind { diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index 65b50736c5555..73cc8ff547d51 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -17,11 +17,13 @@ pub(crate) fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaI // All the built-in macro attributes are "words" at the moment. let template = AttributeTemplate { word: true, ..Default::default() }; validate_attr::check_builtin_meta_item( + &ecx.ecfg.features, &ecx.sess.psess, meta_item, AttrStyle::Outer, name, template, + true, ); } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 756290be0a813..d46ec7a9ac0fe 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -8,7 +8,7 @@ use rustc_ast::tokenstream::{ use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NodeId}; use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; -use rustc_feature::{Features, ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES}; +use rustc_feature::{AttributeSafety, Features, ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES}; use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::validate_attr; use rustc_session::parse::feature_err; @@ -263,6 +263,13 @@ impl<'a> StripUnconfigured<'a> { /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec { + validate_attr::check_attribute_safety( + self.features.unwrap_or(&Features::default()), + &self.sess.psess, + AttributeSafety::Normal, + &cfg_attr, + ); + let Some((cfg_predicate, expanded_attrs)) = rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess) else { @@ -385,6 +392,13 @@ impl<'a> StripUnconfigured<'a> { return (true, None); } }; + + validate_attr::deny_builtin_meta_unsafety( + self.features.unwrap_or(&Features::default()), + &self.sess.psess, + &meta_item, + ); + ( parse_cfg(&meta_item, self.sess).map_or(true, |meta_item| { attr::cfg_matches(meta_item, &self.sess, self.lint_node_id, self.features) diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 356bc9a410d6b..af2db17184086 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -26,76 +26,35 @@ pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) { let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); let attr_item = attr.get_normal_item(); - let is_unsafe_attr = attr_info.is_some_and(|attr| attr.safety == AttributeSafety::Unsafe); - - if features.unsafe_attributes { - if is_unsafe_attr { - if let ast::Safety::Default = attr_item.unsafety { - let path_span = attr_item.path.span; - - // If the `attr_item`'s span is not from a macro, then just suggest - // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the - // `unsafe(`, `)` right after and right before the opening and closing - // square bracket respectively. - let diag_span = if attr_item.span().can_be_used_for_suggestions() { - attr_item.span() - } else { - attr.span - .with_lo(attr.span.lo() + BytePos(2)) - .with_hi(attr.span.hi() - BytePos(1)) - }; - - if attr.span.at_least_rust_2024() { - psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe { - span: path_span, - suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion { - left: diag_span.shrink_to_lo(), - right: diag_span.shrink_to_hi(), - }, - }); - } else { - psess.buffer_lint( - UNSAFE_ATTR_OUTSIDE_UNSAFE, - path_span, - ast::CRATE_NODE_ID, - BuiltinLintDiag::UnsafeAttrOutsideUnsafe { - attribute_name_span: path_span, - sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), - }, - ); - } - } - } else { - if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { - psess.dcx().emit_err(errors::InvalidAttrUnsafe { - span: unsafe_span, - name: attr_item.path.clone(), - }); - } - } - } + // All non-builtin attributes are considered safe + let safety = attr_info.map(|x| x.safety).unwrap_or(AttributeSafety::Normal); + check_attribute_safety(features, psess, safety, attr); // Check input tokens for built-in and key-value attributes. match attr_info { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => { match parse_meta(psess, attr) { - Ok(meta) => check_builtin_meta_item(psess, &meta, attr.style, *name, *template), + // Don't check safety again, we just did that + Ok(meta) => check_builtin_meta_item( + features, psess, &meta, attr.style, *name, *template, false, + ), Err(err) => { err.emit(); } } } - _ if let AttrArgs::Eq(..) = attr_item.args => { - // All key-value attributes are restricted to meta-item syntax. - match parse_meta(psess, attr) { - Ok(_) => {} - Err(err) => { - err.emit(); + _ => { + if let AttrArgs::Eq(..) = attr_item.args { + // All key-value attributes are restricted to meta-item syntax. + match parse_meta(psess, attr) { + Ok(_) => {} + Err(err) => { + err.emit(); + } } } } - _ => {} } } @@ -198,12 +157,85 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte } } +pub fn check_attribute_safety( + features: &Features, + psess: &ParseSess, + safety: AttributeSafety, + attr: &Attribute, +) { + if features.unsafe_attributes { + let attr_item = attr.get_normal_item(); + + if safety == AttributeSafety::Unsafe { + if let ast::Safety::Default = attr_item.unsafety { + let path_span = attr_item.path.span; + + // If the `attr_item`'s span is not from a macro, then just suggest + // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the + // `unsafe(`, `)` right after and right before the opening and closing + // square bracket respectively. + let diag_span = if attr_item.span().can_be_used_for_suggestions() { + attr_item.span() + } else { + attr.span + .with_lo(attr.span.lo() + BytePos(2)) + .with_hi(attr.span.hi() - BytePos(1)) + }; + + if attr.span.at_least_rust_2024() { + psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe { + span: path_span, + suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion { + left: diag_span.shrink_to_lo(), + right: diag_span.shrink_to_hi(), + }, + }); + } else { + psess.buffer_lint( + UNSAFE_ATTR_OUTSIDE_UNSAFE, + path_span, + ast::CRATE_NODE_ID, + BuiltinLintDiag::UnsafeAttrOutsideUnsafe { + attribute_name_span: path_span, + sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), + }, + ); + } + } + } else { + if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { + psess.dcx().emit_err(errors::InvalidAttrUnsafe { + span: unsafe_span, + name: attr_item.path.clone(), + }); + } + } + } +} + +// Called by `check_builtin_meta_item` and code that manually denies +// `unsafe(...)` in `cfg` +pub fn deny_builtin_meta_unsafety(features: &Features, psess: &ParseSess, meta: &MetaItem) { + // This only supports denying unsafety right now - making builtin attributes + // support unsafety will requite us to thread the actual `Attribute` through + // for the nice diagnostics. + if features.unsafe_attributes { + if let Safety::Unsafe(unsafe_span) = meta.unsafety { + psess + .dcx() + .emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: meta.path.clone() }); + } + } +} + pub fn check_builtin_meta_item( + features: &Features, psess: &ParseSess, meta: &MetaItem, style: ast::AttrStyle, name: Symbol, template: AttributeTemplate, + deny_unsafety: bool, ) { // Some special attributes like `cfg` must be checked // before the generic check, so we skip them here. @@ -212,6 +244,10 @@ pub fn check_builtin_meta_item( if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) { emit_malformed_attribute(psess, style, meta.span, name, template); } + + if deny_unsafety { + deny_builtin_meta_unsafety(features, psess, meta); + } } fn emit_malformed_attribute( diff --git a/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs b/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs index 774ce86c0960c..7f0d6a0cf8b91 100644 --- a/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs @@ -3,4 +3,7 @@ #[derive(unsafe(Debug))] //~ ERROR: traits in `#[derive(...)]` don't accept `unsafe(...)` struct Foo; +#[unsafe(derive(Debug))] //~ ERROR: is not an unsafe attribute +struct Bar; + fn main() {} diff --git a/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr index fc0daf16790a8..22010c61b5f52 100644 --- a/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr @@ -4,5 +4,13 @@ error: traits in `#[derive(...)]` don't accept `unsafe(...)` LL | #[derive(unsafe(Debug))] | ^^^^^^ -error: aborting due to 1 previous error +error: `derive` is not an unsafe attribute + --> $DIR/derive-unsafe-attributes.rs:6:3 + | +LL | #[unsafe(derive(Debug))] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: aborting due to 2 previous errors diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs new file mode 100644 index 0000000000000..0181add843bcd --- /dev/null +++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs @@ -0,0 +1,31 @@ +//@ edition: 2024 +//@ compile-flags: -Zunstable-options +#![feature(unsafe_attributes)] + +#[unsafe(cfg(any()))] //~ ERROR: is not an unsafe attribute +fn a() {} + +#[unsafe(cfg_attr(any(), allow(dead_code)))] //~ ERROR: is not an unsafe attribute +fn b() {} + +#[unsafe(test)] //~ ERROR: is not an unsafe attribute +fn aa() {} + +#[unsafe(ignore = "test")] //~ ERROR: is not an unsafe attribute +fn bb() {} + +#[unsafe(should_panic(expected = "test"))] //~ ERROR: is not an unsafe attribute +fn cc() {} + +#[unsafe(macro_use)] //~ ERROR: is not an unsafe attribute +mod inner { + #[unsafe(macro_export)] //~ ERROR: is not an unsafe attribute + macro_rules! m { + () => {}; + } +} + +#[unsafe(used)] //~ ERROR: is not an unsafe attribute +static FOO: usize = 0; + +fn main() {} diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr new file mode 100644 index 0000000000000..a2e56087d1615 --- /dev/null +++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr @@ -0,0 +1,66 @@ +error: `cfg` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:5:3 + | +LL | #[unsafe(cfg(any()))] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: `cfg_attr` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:8:3 + | +LL | #[unsafe(cfg_attr(any(), allow(dead_code)))] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: `test` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:11:3 + | +LL | #[unsafe(test)] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: `ignore` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:14:3 + | +LL | #[unsafe(ignore = "test")] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: `should_panic` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:17:3 + | +LL | #[unsafe(should_panic(expected = "test"))] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: `macro_use` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:20:3 + | +LL | #[unsafe(macro_use)] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: `macro_export` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:22:7 + | +LL | #[unsafe(macro_export)] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: `used` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:28:3 + | +LL | #[unsafe(used)] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: aborting due to 8 previous errors + diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs new file mode 100644 index 0000000000000..caf6c6dc8ffde --- /dev/null +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs @@ -0,0 +1,27 @@ +#![feature(unsafe_attributes)] + +#[unsafe(proc_macro)] +//~^ ERROR: is not an unsafe attribute +//~| ERROR attribute is only usable with crates of the `proc-macro` crate type +pub fn a() {} + + +#[unsafe(proc_macro_derive(Foo))] +//~^ ERROR: is not an unsafe attribute +//~| ERROR attribute is only usable with crates of the `proc-macro` crate type +pub fn b() {} + +#[proc_macro_derive(unsafe(Foo))] +//~^ ERROR attribute is only usable with crates of the `proc-macro` crate type +pub fn c() {} + +#[unsafe(proc_macro_attribute)] +//~^ ERROR: is not an unsafe attribute +//~| ERROR attribute is only usable with crates of the `proc-macro` crate type +pub fn d() {} + +#[unsafe(allow(dead_code))] +//~^ ERROR: is not an unsafe attribute +pub fn e() {} + +fn main() {} diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr new file mode 100644 index 0000000000000..346d2c2e9ae69 --- /dev/null +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr @@ -0,0 +1,58 @@ +error: `proc_macro` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:3:3 + | +LL | #[unsafe(proc_macro)] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: `proc_macro_derive` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:9:3 + | +LL | #[unsafe(proc_macro_derive(Foo))] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: `proc_macro_attribute` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:18:3 + | +LL | #[unsafe(proc_macro_attribute)] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: `allow` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:23:3 + | +LL | #[unsafe(allow(dead_code))] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type + --> $DIR/proc-unsafe-attributes.rs:3:1 + | +LL | #[unsafe(proc_macro)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type + --> $DIR/proc-unsafe-attributes.rs:9:1 + | +LL | #[unsafe(proc_macro_derive(Foo))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type + --> $DIR/proc-unsafe-attributes.rs:14:1 + | +LL | #[proc_macro_derive(unsafe(Foo))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type + --> $DIR/proc-unsafe-attributes.rs:18:1 + | +LL | #[unsafe(proc_macro_attribute)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + From 8eaf51bccdd05e587710a41c2a2c4f29e5d6bab8 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Tue, 9 Jul 2024 19:06:49 -0500 Subject: [PATCH 06/11] Add toggle for `parse_meta_item` unsafe parsing This makes it possible for the `unsafe(...)` syntax to only be valid at the top level, and the `NestedMetaItem`s will automatically reject `unsafe(...)`. --- compiler/rustc_builtin_macros/messages.ftl | 3 - compiler/rustc_builtin_macros/src/cfg.rs | 3 +- compiler/rustc_builtin_macros/src/derive.rs | 13 +-- compiler/rustc_builtin_macros/src/errors.rs | 7 -- compiler/rustc_expand/src/config.rs | 4 +- compiler/rustc_interface/src/interface.rs | 5 +- compiler/rustc_parse/messages.ftl | 1 + compiler/rustc_parse/src/errors.rs | 1 + compiler/rustc_parse/src/parser/attr.rs | 21 ++++- compiler/rustc_parse/src/validate_attr.rs | 82 +++++++++---------- .../unsafe/derive-unsafe-attributes.rs | 8 +- .../unsafe/derive-unsafe-attributes.stderr | 59 +++++++++++-- .../unsafe/double-unsafe-attributes.stderr | 2 +- .../extraneous-unsafe-attributes.stderr | 16 ++-- .../unsafe/proc-unsafe-attributes.rs | 10 +++ .../unsafe/proc-unsafe-attributes.stderr | 77 +++++++++++++++-- .../ui/attributes/unsafe/unsafe-attributes.rs | 9 ++ .../unsafe/unsafe-safe-attribute.stderr | 2 +- .../unsafe-safe-attribute_diagnostic.stderr | 2 +- 19 files changed, 229 insertions(+), 96 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index a30ab236213a0..ae3cce40f5daa 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -115,9 +115,6 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values .suggestion = remove the value -builtin_macros_derive_unsafe_path = traits in `#[derive(...)]` don't accept `unsafe(...)` - .suggestion = remove the `unsafe(...)` - builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead .custom = use `std::env::var({$var_expr})` to read the variable at run time diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index ceb62230ece96..de198115fa00b 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -6,6 +6,7 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_errors::PResult; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; +use rustc_parse::parser::attr::AllowLeadingUnsafe; use rustc_span::Span; use {rustc_ast as ast, rustc_attr as attr}; @@ -42,7 +43,7 @@ fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span })); } - let cfg = p.parse_meta_item()?; + let cfg = p.parse_meta_item(AllowLeadingUnsafe::Yes)?; let _ = p.eat(&token::Comma); diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index c540ff4e1de82..57bddf0ab60ad 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -1,5 +1,5 @@ use rustc_ast as ast; -use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, Safety, StmtKind}; +use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; use rustc_expand::base::{ Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier, }; @@ -62,7 +62,6 @@ impl MultiItemModifier for Expander { // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the // paths. report_path_args(sess, meta); - report_unsafe_args(sess, meta); meta.path.clone() }) .map(|path| DeriveResolution { @@ -162,13 +161,3 @@ fn report_path_args(sess: &Session, meta: &ast::MetaItem) { } } } - -fn report_unsafe_args(sess: &Session, meta: &ast::MetaItem) { - match meta.unsafety { - Safety::Unsafe(span) => { - sess.dcx().emit_err(errors::DeriveUnsafePath { span }); - } - Safety::Default => {} - Safety::Safe(_) => unreachable!(), - } -} diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 0a4f07709c7fd..93fc9bcb9d206 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -297,13 +297,6 @@ pub(crate) struct DerivePathArgsValue { pub(crate) span: Span, } -#[derive(Diagnostic)] -#[diag(builtin_macros_derive_unsafe_path)] -pub(crate) struct DeriveUnsafePath { - #[primary_span] - pub(crate) span: Span, -} - #[derive(Diagnostic)] #[diag(builtin_macros_no_default_variant)] #[help] diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index d46ec7a9ac0fe..f6bf9f5e89f2f 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -8,7 +8,9 @@ use rustc_ast::tokenstream::{ use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NodeId}; use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; -use rustc_feature::{AttributeSafety, Features, ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES}; +use rustc_feature::{ + AttributeSafety, Features, ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES, +}; use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::validate_attr; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 886b043af2460..04e2b7d45dc93 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -15,6 +15,7 @@ use rustc_middle::ty; use rustc_middle::ty::CurrentGcx; use rustc_middle::util::Providers; use rustc_parse::new_parser_from_source_str; +use rustc_parse::parser::attr::AllowLeadingUnsafe; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::print_query_stack; use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName}; @@ -67,7 +68,7 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec) -> Cfg { } match new_parser_from_source_str(&psess, filename, s.to_string()) { - Ok(mut parser) => match parser.parse_meta_item() { + Ok(mut parser) => match parser.parse_meta_item(AllowLeadingUnsafe::No) { Ok(meta_item) if parser.token == token::Eof => { if meta_item.path.segments.len() != 1 { error!("argument key must be an identifier"); @@ -173,7 +174,7 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec) -> Ch } }; - let meta_item = match parser.parse_meta_item() { + let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::Yes) { Ok(meta_item) if parser.token == token::Eof => meta_item, Ok(..) => expected_error(), Err(err) => { diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 391a57917768d..e13306b9d9fe2 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -365,6 +365,7 @@ parse_inner_doc_comment_not_permitted = expected outer doc comment .sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style parse_invalid_attr_unsafe = `{$name}` is not an unsafe attribute + .label = this is not an unsafe attribute .suggestion = remove the `unsafe(...)` .note = extraneous unsafe is not allowed in attributes diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 1076280370815..e5b0dc804a5e8 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3188,6 +3188,7 @@ pub(crate) struct DotDotRangeAttribute { #[note] pub struct InvalidAttrUnsafe { #[primary_span] + #[label] pub span: Span, pub name: Path, } diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 12b9414d1f760..f34ef071e21ec 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -31,6 +31,12 @@ enum OuterAttributeType { Attribute, } +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum AllowLeadingUnsafe { + Yes, + No, +} + impl<'a> Parser<'a> { /// Parses attributes that appear before an item. pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> { @@ -332,7 +338,7 @@ impl<'a> Parser<'a> { /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> { - let cfg_predicate = self.parse_meta_item()?; + let cfg_predicate = self.parse_meta_item(AllowLeadingUnsafe::No)?; self.expect(&token::Comma)?; // Presumably, the majority of the time there will only be one attr. @@ -368,7 +374,10 @@ impl<'a> Parser<'a> { /// MetaItem = SimplePath ( '=' UNSUFFIXED_LIT | '(' MetaSeq? ')' )? ; /// MetaSeq = MetaItemInner (',' MetaItemInner)* ','? ; /// ``` - pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { + pub fn parse_meta_item( + &mut self, + unsafe_allowed: AllowLeadingUnsafe, + ) -> PResult<'a, ast::MetaItem> { // We can't use `maybe_whole` here because it would bump in the `None` // case, which we don't want. if let token::Interpolated(nt) = &self.token.kind @@ -384,7 +393,11 @@ impl<'a> Parser<'a> { } let lo = self.token.span; - let is_unsafe = self.eat_keyword(kw::Unsafe); + let is_unsafe = if unsafe_allowed == AllowLeadingUnsafe::Yes { + self.eat_keyword(kw::Unsafe) + } else { + false + }; let unsafety = if is_unsafe { let unsafe_span = self.prev_token.span; self.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span); @@ -427,7 +440,7 @@ impl<'a> Parser<'a> { Err(err) => err.cancel(), // we provide a better error below } - match self.parse_meta_item() { + match self.parse_meta_item(AllowLeadingUnsafe::No) { Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)), Err(err) => err.cancel(), // we provide a better error below } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index af2db17184086..a64c00f3b6cbc 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -163,53 +163,53 @@ pub fn check_attribute_safety( safety: AttributeSafety, attr: &Attribute, ) { - if features.unsafe_attributes { - let attr_item = attr.get_normal_item(); + if !features.unsafe_attributes { + return; + } - if safety == AttributeSafety::Unsafe { - if let ast::Safety::Default = attr_item.unsafety { - let path_span = attr_item.path.span; + let attr_item = attr.get_normal_item(); - // If the `attr_item`'s span is not from a macro, then just suggest - // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the - // `unsafe(`, `)` right after and right before the opening and closing - // square bracket respectively. - let diag_span = if attr_item.span().can_be_used_for_suggestions() { - attr_item.span() - } else { - attr.span - .with_lo(attr.span.lo() + BytePos(2)) - .with_hi(attr.span.hi() - BytePos(1)) - }; + if safety == AttributeSafety::Unsafe { + if let ast::Safety::Default = attr_item.unsafety { + let path_span = attr_item.path.span; - if attr.span.at_least_rust_2024() { - psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe { - span: path_span, - suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion { - left: diag_span.shrink_to_lo(), - right: diag_span.shrink_to_hi(), - }, - }); - } else { - psess.buffer_lint( - UNSAFE_ATTR_OUTSIDE_UNSAFE, - path_span, - ast::CRATE_NODE_ID, - BuiltinLintDiag::UnsafeAttrOutsideUnsafe { - attribute_name_span: path_span, - sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), - }, - ); - } - } - } else { - if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { - psess.dcx().emit_err(errors::InvalidAttrUnsafe { - span: unsafe_span, - name: attr_item.path.clone(), + // If the `attr_item`'s span is not from a macro, then just suggest + // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the + // `unsafe(`, `)` right after and right before the opening and closing + // square bracket respectively. + let diag_span = if attr_item.span().can_be_used_for_suggestions() { + attr_item.span() + } else { + attr.span.with_lo(attr.span.lo() + BytePos(2)).with_hi(attr.span.hi() - BytePos(1)) + }; + + if attr.span.at_least_rust_2024() { + psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe { + span: path_span, + suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion { + left: diag_span.shrink_to_lo(), + right: diag_span.shrink_to_hi(), + }, }); + } else { + psess.buffer_lint( + UNSAFE_ATTR_OUTSIDE_UNSAFE, + path_span, + ast::CRATE_NODE_ID, + BuiltinLintDiag::UnsafeAttrOutsideUnsafe { + attribute_name_span: path_span, + sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), + }, + ); } } + } else { + if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { + psess.dcx().emit_err(errors::InvalidAttrUnsafe { + span: unsafe_span, + name: attr_item.path.clone(), + }); + } } } diff --git a/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs b/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs index 7f0d6a0cf8b91..b8edb4aab907b 100644 --- a/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs @@ -1,6 +1,12 @@ #![feature(unsafe_attributes)] -#[derive(unsafe(Debug))] //~ ERROR: traits in `#[derive(...)]` don't accept `unsafe(...)` +#[derive(unsafe(Debug))] +//~^ ERROR: expected identifier, found keyword `unsafe` +//~| ERROR: traits in `#[derive(...)]` don't accept arguments +//~| ERROR: expected identifier, found keyword `unsafe` +//~| ERROR: expected identifier, found keyword `unsafe` +//~| ERROR: cannot find derive macro `r#unsafe` in this scope +//~| ERROR: cannot find derive macro `r#unsafe` in this scope struct Foo; #[unsafe(derive(Debug))] //~ ERROR: is not an unsafe attribute diff --git a/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr index 22010c61b5f52..c40a5512fd5cd 100644 --- a/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr @@ -1,16 +1,65 @@ -error: traits in `#[derive(...)]` don't accept `unsafe(...)` +error: expected identifier, found keyword `unsafe` --> $DIR/derive-unsafe-attributes.rs:3:10 | LL | #[derive(unsafe(Debug))] - | ^^^^^^ + | ^^^^^^ expected identifier, found keyword + | +help: escape `unsafe` to use it as an identifier + | +LL | #[derive(r#unsafe(Debug))] + | ++ + +error: traits in `#[derive(...)]` don't accept arguments + --> $DIR/derive-unsafe-attributes.rs:3:16 + | +LL | #[derive(unsafe(Debug))] + | ^^^^^^^ help: remove the arguments error: `derive` is not an unsafe attribute - --> $DIR/derive-unsafe-attributes.rs:6:3 + --> $DIR/derive-unsafe-attributes.rs:12:3 | LL | #[unsafe(derive(Debug))] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes -error: aborting due to 2 previous errors +error: expected identifier, found keyword `unsafe` + --> $DIR/derive-unsafe-attributes.rs:3:10 + | +LL | #[derive(unsafe(Debug))] + | ^^^^^^ expected identifier, found keyword + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: escape `unsafe` to use it as an identifier + | +LL | #[derive(r#unsafe(Debug))] + | ++ + +error: expected identifier, found keyword `unsafe` + --> $DIR/derive-unsafe-attributes.rs:3:10 + | +LL | #[derive(unsafe(Debug))] + | ^^^^^^ expected identifier, found keyword + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: escape `unsafe` to use it as an identifier + | +LL | #[derive(r#unsafe(Debug))] + | ++ + +error: cannot find derive macro `r#unsafe` in this scope + --> $DIR/derive-unsafe-attributes.rs:3:10 + | +LL | #[derive(unsafe(Debug))] + | ^^^^^^ + +error: cannot find derive macro `r#unsafe` in this scope + --> $DIR/derive-unsafe-attributes.rs:3:10 + | +LL | #[derive(unsafe(Debug))] + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 7 previous errors diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr index ea82bac6df07b..950b2636993c1 100644 --- a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr @@ -13,7 +13,7 @@ error: `r#unsafe` is not an unsafe attribute --> $DIR/double-unsafe-attributes.rs:3:3 | LL | #[unsafe(unsafe(no_mangle))] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr index a2e56087d1615..f39074b613d40 100644 --- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr @@ -2,7 +2,7 @@ error: `cfg` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:5:3 | LL | #[unsafe(cfg(any()))] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes @@ -10,7 +10,7 @@ error: `cfg_attr` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:8:3 | LL | #[unsafe(cfg_attr(any(), allow(dead_code)))] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes @@ -18,7 +18,7 @@ error: `test` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:11:3 | LL | #[unsafe(test)] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes @@ -26,7 +26,7 @@ error: `ignore` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:14:3 | LL | #[unsafe(ignore = "test")] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes @@ -34,7 +34,7 @@ error: `should_panic` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:17:3 | LL | #[unsafe(should_panic(expected = "test"))] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes @@ -42,7 +42,7 @@ error: `macro_use` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:20:3 | LL | #[unsafe(macro_use)] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes @@ -50,7 +50,7 @@ error: `macro_export` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:22:7 | LL | #[unsafe(macro_export)] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes @@ -58,7 +58,7 @@ error: `used` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:28:3 | LL | #[unsafe(used)] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs index caf6c6dc8ffde..f29a5b3252b0a 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs @@ -13,6 +13,7 @@ pub fn b() {} #[proc_macro_derive(unsafe(Foo))] //~^ ERROR attribute is only usable with crates of the `proc-macro` crate type +//~| ERROR: expected identifier, found keyword `unsafe` pub fn c() {} #[unsafe(proc_macro_attribute)] @@ -24,4 +25,13 @@ pub fn d() {} //~^ ERROR: is not an unsafe attribute pub fn e() {} +#[unsafe(allow(unsafe(dead_code)))] +//~^ ERROR: is not an unsafe attribute +//~| ERROR: malformed lint attribute input +//~| ERROR: malformed lint attribute input +//~| ERROR: expected identifier, found keyword `unsafe` +//~| ERROR: malformed lint attribute input +//~| ERROR: malformed lint attribute input +pub fn f() {} + fn main() {} diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr index 346d2c2e9ae69..79d34d458bd6c 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr @@ -1,8 +1,22 @@ +error[E0452]: malformed lint attribute input + --> $DIR/proc-unsafe-attributes.rs:28:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^^^^^^^^^^^^ bad attribute argument + +error[E0452]: malformed lint attribute input + --> $DIR/proc-unsafe-attributes.rs:28:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^^^^^^^^^^^^ bad attribute argument + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: `proc_macro` is not an unsafe attribute --> $DIR/proc-unsafe-attributes.rs:3:3 | LL | #[unsafe(proc_macro)] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes @@ -10,26 +24,56 @@ error: `proc_macro_derive` is not an unsafe attribute --> $DIR/proc-unsafe-attributes.rs:9:3 | LL | #[unsafe(proc_macro_derive(Foo))] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes +error: expected identifier, found keyword `unsafe` + --> $DIR/proc-unsafe-attributes.rs:14:21 + | +LL | #[proc_macro_derive(unsafe(Foo))] + | ^^^^^^ expected identifier, found keyword + | +help: escape `unsafe` to use it as an identifier + | +LL | #[proc_macro_derive(r#unsafe(Foo))] + | ++ + error: `proc_macro_attribute` is not an unsafe attribute - --> $DIR/proc-unsafe-attributes.rs:18:3 + --> $DIR/proc-unsafe-attributes.rs:19:3 | LL | #[unsafe(proc_macro_attribute)] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes error: `allow` is not an unsafe attribute - --> $DIR/proc-unsafe-attributes.rs:23:3 + --> $DIR/proc-unsafe-attributes.rs:24:3 | LL | #[unsafe(allow(dead_code))] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes +error: `allow` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:28:3 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: expected identifier, found keyword `unsafe` + --> $DIR/proc-unsafe-attributes.rs:28:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^ expected identifier, found keyword + | +help: escape `unsafe` to use it as an identifier + | +LL | #[unsafe(allow(r#unsafe(dead_code)))] + | ++ + error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type --> $DIR/proc-unsafe-attributes.rs:3:1 | @@ -49,10 +93,27 @@ LL | #[proc_macro_derive(unsafe(Foo))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/proc-unsafe-attributes.rs:18:1 + --> $DIR/proc-unsafe-attributes.rs:19:1 | LL | #[unsafe(proc_macro_attribute)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error[E0452]: malformed lint attribute input + --> $DIR/proc-unsafe-attributes.rs:28:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^^^^^^^^^^^^ bad attribute argument + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0452]: malformed lint attribute input + --> $DIR/proc-unsafe-attributes.rs:28:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^^^^^^^^^^^^ bad attribute argument + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 15 previous errors +For more information about this error, try `rustc --explain E0452`. diff --git a/tests/ui/attributes/unsafe/unsafe-attributes.rs b/tests/ui/attributes/unsafe/unsafe-attributes.rs index e7620a18048e4..5aaaa512be9cd 100644 --- a/tests/ui/attributes/unsafe/unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/unsafe-attributes.rs @@ -4,4 +4,13 @@ #[unsafe(no_mangle)] fn a() {} +#[unsafe(export_name = "foo")] +fn b() {} + +#[unsafe(link_section = ".example_section")] +static VAR1: u32 = 1; + +#[cfg_attr(any(), unsafe(no_mangle))] +static VAR2: u32 = 1; + fn main() {} diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr index 0602af34e4f64..584b0ea797d0a 100644 --- a/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr +++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr @@ -2,7 +2,7 @@ error: `repr` is not an unsafe attribute --> $DIR/unsafe-safe-attribute.rs:3:3 | LL | #[unsafe(repr(C))] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr index 584dacf4d8c91..26b5e4e37b931 100644 --- a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr +++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr @@ -2,7 +2,7 @@ error: `diagnostic::on_unimplemented` is not an unsafe attribute --> $DIR/unsafe-safe-attribute_diagnostic.rs:3:3 | LL | #[unsafe(diagnostic::on_unimplemented( - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes From dadf3d2a970999ee0d7a0f97045acc70919d751e Mon Sep 17 00:00:00 2001 From: aissata Date: Tue, 30 Jul 2024 08:16:47 +0200 Subject: [PATCH 07/11] the output in stderr expects panic-unwind --- tests/ui/backtrace/synchronized-panic-handler.rs | 1 + tests/ui/backtrace/synchronized-panic-handler.run.stderr | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/ui/backtrace/synchronized-panic-handler.rs b/tests/ui/backtrace/synchronized-panic-handler.rs index 00eb249da1dd5..29431ae3c458a 100644 --- a/tests/ui/backtrace/synchronized-panic-handler.rs +++ b/tests/ui/backtrace/synchronized-panic-handler.rs @@ -3,6 +3,7 @@ //@ edition:2021 //@ exec-env:RUST_BACKTRACE=0 //@ needs-threads +//@ needs-unwind use std::thread; const PANIC_MESSAGE: &str = "oops oh no woe is me"; diff --git a/tests/ui/backtrace/synchronized-panic-handler.run.stderr b/tests/ui/backtrace/synchronized-panic-handler.run.stderr index b7c815a94c868..8a06d00ea5998 100644 --- a/tests/ui/backtrace/synchronized-panic-handler.run.stderr +++ b/tests/ui/backtrace/synchronized-panic-handler.run.stderr @@ -1,5 +1,5 @@ -thread '' panicked at $DIR/synchronized-panic-handler.rs:10:5: +thread '' panicked at $DIR/synchronized-panic-handler.rs:11:5: oops oh no woe is me note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread '' panicked at $DIR/synchronized-panic-handler.rs:10:5: +thread '' panicked at $DIR/synchronized-panic-handler.rs:11:5: oops oh no woe is me From cc7e7bc0964ed29963bb3c455f2b89c9e06c5a87 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Jul 2024 12:12:41 +0200 Subject: [PATCH 08/11] cargo-miri: better error when we seem to run inside bootstrap but something is wrong --- src/tools/miri/cargo-miri/src/setup.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs index fe67aad465cdd..0cf6f1a375cdf 100644 --- a/src/tools/miri/cargo-miri/src/setup.rs +++ b/src/tools/miri/cargo-miri/src/setup.rs @@ -100,7 +100,10 @@ pub fn setup( // for target crates. let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); if env::var_os("RUSTC_STAGE").is_some() { - assert!(env::var_os("RUSTC").is_some()); + assert!( + env::var_os("RUSTC").is_some() && env::var_os("RUSTC_WRAPPER").is_some(), + "cargo-miri setup is running inside rustc bootstrap but RUSTC or RUST_WRAPPER is not set" + ); command.env("RUSTC_REAL", &cargo_miri_path); } else { command.env("RUSTC", &cargo_miri_path); From 58bfd98bafef799b032d5facaeec888f990c071b Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 30 Jul 2024 09:55:36 +0200 Subject: [PATCH 09/11] make `///` doc comments compatible with naked functions --- compiler/rustc_passes/src/check_attr.rs | 6 ++++++ tests/ui/asm/naked-functions.rs | 3 +++ 2 files changed, 9 insertions(+) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index e0cf65d3f9830..c845cd36ff1e6 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -460,6 +460,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => { for other_attr in attrs { + // this covers "sugared doc comments" of the form `/// ...` + // it does not cover `#[doc = "..."]`, which is handled below + if other_attr.is_doc_comment() { + continue; + } + if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) { self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { span: other_attr.span, diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 6d335ac2def1e..cb1e5c325c239 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -239,6 +239,9 @@ pub unsafe extern "C" fn compatible_target_feature() { } #[doc = "foo bar baz"] +/// a doc comment +// a normal comment +#[doc(alias = "ADocAlias")] #[naked] pub unsafe extern "C" fn compatible_doc_attributes() { asm!("", options(noreturn, raw)); From 4776ac0f885044685c6f6127632f42522a88c05d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 30 Jul 2024 10:10:36 -0400 Subject: [PATCH 10/11] Suppress must_use on eat calls in rustfmt --- src/tools/rustfmt/src/parse/macros/lazy_static.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tools/rustfmt/src/parse/macros/lazy_static.rs b/src/tools/rustfmt/src/parse/macros/lazy_static.rs index 7baac247e2229..b6de5f8691c25 100644 --- a/src/tools/rustfmt/src/parse/macros/lazy_static.rs +++ b/src/tools/rustfmt/src/parse/macros/lazy_static.rs @@ -33,15 +33,17 @@ pub(crate) fn parse_lazy_static( } while parser.token.kind != TokenKind::Eof { // Parse a `lazy_static!` item. + // FIXME: These `eat_*` calls should be converted to `parse_or` to avoid + // silently formatting malformed lazy-statics. let vis = parse_or!(parse_visibility, rustc_parse::parser::FollowedByType::No); - parser.eat_keyword(kw::Static); - parser.eat_keyword(kw::Ref); + let _ = parser.eat_keyword(kw::Static); + let _ = parser.eat_keyword(kw::Ref); let id = parse_or!(parse_ident); - parser.eat(&TokenKind::Colon); + let _ = parser.eat(&TokenKind::Colon); let ty = parse_or!(parse_ty); - parser.eat(&TokenKind::Eq); + let _ = parser.eat(&TokenKind::Eq); let expr = parse_or!(parse_expr); - parser.eat(&TokenKind::Semi); + let _ = parser.eat(&TokenKind::Semi); result.push((vis, id, ty, expr)); } From b1b48dc58480cc6c36ba88f842144a8190aa589c Mon Sep 17 00:00:00 2001 From: "A. Wilcox" Date: Tue, 30 Jul 2024 09:35:12 -0500 Subject: [PATCH 11/11] tidy: Fix quote in error message --- src/tools/tidy/src/error_codes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index 8ddacc07c6fd9..e2d1b85797ffe 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -319,7 +319,7 @@ fn check_error_codes_tests( if !found_code { verbose_print!( verbose, - "warning: Error code {code}`` has a UI test file, but doesn't contain its own error code!" + "warning: Error code `{code}` has a UI test file, but doesn't contain its own error code!" ); } }