From b3718fe2f3162d1619270d45a09a5ac398bab487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 22 Feb 2025 03:48:48 +0000 Subject: [PATCH] Fix incorrect `cfg` structured suggestion Keep a span for the attribute *within* the square brackets as part of the `AttrKind`. ``` error: `cfg` is not followed by parentheses --> $DIR/cfg-attr-syntax-validation.rs:4:1 | LL | #[cfg = 10] | ^^^^^^^^^^^ | help: expected syntax is | LL - #[cfg = 10] LL + #[cfg(/* predicate */)] | ``` Noticed in https://github.com/rust-lang/rust/pull/137343#discussion_r1964310938. --- compiler/rustc_ast/src/ast.rs | 2 + compiler/rustc_ast/src/attr/mod.rs | 24 ++++-- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 1 + compiler/rustc_ast_pretty/src/pprust/state.rs | 2 + .../src/alloc_error_handler.rs | 2 +- .../src/assert/context.rs | 7 +- compiler/rustc_builtin_macros/src/autodiff.rs | 1 + .../src/deriving/clone.rs | 2 +- .../src/deriving/cmp/eq.rs | 6 +- .../src/deriving/cmp/ord.rs | 2 +- .../src/deriving/cmp/partial_eq.rs | 2 +- .../src/deriving/cmp/partial_ord.rs | 2 +- .../src/deriving/coerce_pointee.rs | 2 +- .../src/deriving/debug.rs | 2 +- .../src/deriving/default.rs | 2 +- .../src/deriving/generic/mod.rs | 2 +- .../rustc_builtin_macros/src/deriving/hash.rs | 2 +- .../src/global_allocator.rs | 2 +- .../src/proc_macro_harness.rs | 6 +- .../src/standard_library_imports.rs | 4 +- compiler/rustc_builtin_macros/src/test.rs | 15 ++-- .../rustc_builtin_macros/src/test_harness.rs | 7 +- compiler/rustc_expand/src/build.rs | 22 +++++- compiler/rustc_expand/src/config.rs | 27 +++++-- compiler/rustc_expand/src/errors.rs | 26 +++++-- compiler/rustc_parse/src/parser/attr.rs | 6 +- src/librustdoc/clean/types.rs | 27 +++++++ tests/rustdoc-ui/doc-cfg.stderr | 14 +++- tests/rustdoc-ui/invalid-cfg.stderr | 8 +- tests/ui/attributes/malformed-attrs.stderr | 7 +- .../cfg-attr-syntax-validation.rs | 15 +++- .../cfg-attr-syntax-validation.stderr | 75 +++++++++++++++++-- tests/ui/imports/unused-macro-use.stderr | 4 +- tests/ui/macros/macro-shadowing.stderr | 4 +- .../proc-macro/proc-macro-attributes.stderr | 16 ++-- .../rust-2018/macro-use-warned-against.stderr | 8 +- 37 files changed, 276 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3c576316f6230..ceed044c88d5f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3326,6 +3326,7 @@ impl NormalAttr { path: Path::from_ident(ident), args: AttrArgs::Empty, tokens: None, + span: ident.span, }, tokens: None, } @@ -3339,6 +3340,7 @@ pub struct AttrItem { pub args: AttrArgs, // Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`. pub tokens: Option, + pub span: Span, } impl AttrItem { diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 44865c493b3b4..d9af967e9dd09 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -231,7 +231,7 @@ impl Attribute { /// Extracts the MetaItem from inside this Attribute. pub fn meta(&self) -> Option { match &self.kind { - AttrKind::Normal(normal) => normal.item.meta(self.span), + AttrKind::Normal(normal) => normal.item.meta(), AttrKind::DocComment(..) => None, } } @@ -297,12 +297,12 @@ impl AttrItem { } } - pub fn meta(&self, span: Span) -> Option { + pub fn meta(&self) -> Option { Some(MetaItem { unsafety: Safety::Default, path: self.path.clone(), kind: self.meta_kind()?, - span, + span: self.span(), }) } @@ -644,8 +644,15 @@ fn mk_attr( path: Path, args: AttrArgs, span: Span, + inner_span: Span, ) -> Attribute { - mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span) + mk_attr_from_item( + g, + AttrItem { unsafety, path, args, tokens: None, span: inner_span }, + None, + style, + span, + ) } pub fn mk_attr_from_item( @@ -669,10 +676,11 @@ pub fn mk_attr_word( unsafety: Safety, name: Symbol, span: Span, + inner_span: Span, ) -> Attribute { let path = Path::from_ident(Ident::new(name, span)); let args = AttrArgs::Empty; - mk_attr(g, style, unsafety, path, args, span) + mk_attr(g, style, unsafety, path, args, span, inner_span) } pub fn mk_attr_nested_word( @@ -682,6 +690,7 @@ pub fn mk_attr_nested_word( outer: Symbol, inner: Symbol, span: Span, + inner_span: Span, ) -> Attribute { let inner_tokens = TokenStream::new(vec![TokenTree::Token( Token::from_ast_ident(Ident::new(inner, span)), @@ -694,7 +703,7 @@ pub fn mk_attr_nested_word( delim: Delimiter::Parenthesis, tokens: inner_tokens, }); - mk_attr(g, style, unsafety, path, attr_args, span) + mk_attr(g, style, unsafety, path, attr_args, span, inner_span) } pub fn mk_attr_name_value_str( @@ -704,6 +713,7 @@ pub fn mk_attr_name_value_str( name: Symbol, val: Symbol, span: Span, + inner_span: Span, ) -> Attribute { let lit = token::Lit::new(token::Str, escape_string_symbol(val), None); let expr = P(Expr { @@ -715,7 +725,7 @@ pub fn mk_attr_name_value_str( }); let path = Path::from_ident(Ident::new(name, span)); let args = AttrArgs::Eq { eq_span: span, expr }; - mk_attr(g, style, unsafety, path, args, span) + mk_attr(g, style, unsafety, path, args, span, inner_span) } pub fn filter_by_name(attrs: &[A], name: Symbol) -> impl Iterator { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 37fcc0d2167b2..42b7baf473c62 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1878,7 +1878,7 @@ macro_rules! common_visitor_and_walkers { match kind { AttrKind::Normal(normal) => { let NormalAttr { item, tokens: _ } = &$($mut)?**normal; - let AttrItem { unsafety: _, path, args, tokens: _ } = item; + let AttrItem { unsafety: _, path, args, tokens: _, span: _ } = item; try_visit!(vis.visit_path(path)); try_visit!(walk_attr_args(vis, args)); } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 8747e624a4a9e..4a66ff2cfe023 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1992,6 +1992,7 @@ impl<'hir> LoweringContext<'_, 'hir> { sym::allow, sym::unreachable_code, try_span, + try_span, ); let attrs: AttrVec = thin_vec![attr]; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index aff98c63bcb41..cbe3d7ed35f37 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -287,6 +287,7 @@ fn print_crate_inner<'a>( sym::feature, sym::prelude_import, DUMMY_SP, + DUMMY_SP, ); s.print_attribute(&fake_attr); @@ -300,6 +301,7 @@ fn print_crate_inner<'a>( Safety::Default, sym::no_std, DUMMY_SP, + DUMMY_SP, ); s.print_attribute(&fake_attr); } diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index e75bc944d7ec8..d3648db2ee7e1 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -92,7 +92,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span define_opaque: None, })); - let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)]; + let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span, span)]; let item = cx.item(span, attrs, kind); cx.stmt_item(sig_span, item) diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index ea7248ca5393a..1c02c71c5a325 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -112,7 +112,12 @@ impl<'cx, 'a> Context<'cx, 'a> { self.span, self.cx.item( self.span, - thin_vec![self.cx.attr_nested_word(sym::allow, sym::unused_imports, self.span)], + thin_vec![self.cx.attr_nested_word( + sym::allow, + sym::unused_imports, + self.span, + self.span + )], ItemKind::Use(UseTree { prefix: self.cx.path(self.span, self.cx.std_path(&[sym::asserting])), kind: UseTreeKind::Nested { diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index c784477833279..f118f6873c265 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -362,6 +362,7 @@ mod llvm_enzyme { path: ast::Path::from_ident(Ident::with_dummy_span(sym::inline)), args: ast::AttrArgs::Delimited(never_arg), tokens: None, + span, }; let inline_never_attr = P(ast::NormalAttr { item: inline_item, tokens: None }); let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 69f8c273797e4..66ea1c227d923 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -81,7 +81,7 @@ pub(crate) fn expand_deriving_clone( explicit_self: true, nonself_args: Vec::new(), ret_ty: Self_, - attributes: thin_vec![cx.attr_word(sym::inline, span)], + attributes: thin_vec![cx.attr_word(sym::inline, span, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: substructure, }], diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index eca79e4dc4897..7041ba8d1c9c1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -32,9 +32,9 @@ pub(crate) fn expand_deriving_eq( nonself_args: vec![], ret_ty: Unit, attributes: thin_vec![ - cx.attr_word(sym::inline, span), - cx.attr_nested_word(sym::doc, sym::hidden, span), - cx.attr_nested_word(sym::coverage, sym::off, span) + cx.attr_word(sym::inline, span, span), + cx.attr_nested_word(sym::doc, sym::hidden, span, span), + cx.attr_nested_word(sym::coverage, sym::off, span, span) ], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|a, b, c| { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 1ed44c20bc61e..ff93ed88a8b77 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -28,7 +28,7 @@ pub(crate) fn expand_deriving_ord( explicit_self: true, nonself_args: vec![(self_ref(), sym::other)], ret_ty: Path(path_std!(cmp::Ordering)), - attributes: thin_vec![cx.attr_word(sym::inline, span)], + attributes: thin_vec![cx.attr_word(sym::inline, span, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))), }], diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index b1d950b8d89de..cd636816664e7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -41,7 +41,7 @@ pub(crate) fn expand_deriving_partial_eq( explicit_self: true, nonself_args: vec![(self_ref(), sym::other)], ret_ty: Path(path_local!(bool)), - attributes: thin_vec![cx.attr_word(sym::inline, span)], + attributes: thin_vec![cx.attr_word(sym::inline, span, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|a, b, c| { BlockOrExpr::new_expr(get_substructure_equality_expr(a, b, c)) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 0a076dd670b34..9a1aee42bb94f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -47,7 +47,7 @@ pub(crate) fn expand_deriving_partial_ord( explicit_self: true, nonself_args: vec![(self_ref(), sym::other)], ret_ty, - attributes: thin_vec![cx.attr_word(sym::inline, span)], + attributes: thin_vec![cx.attr_word(sym::inline, span, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { cs_partial_cmp(cx, span, substr, discr_then_data) diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 6082e376435a7..37363c4894b77 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -98,7 +98,7 @@ pub(crate) fn expand_deriving_coerce_pointee( // Declare helper function that adds implementation blocks. // FIXME(dingxiangfei2009): Investigate the set of attributes on target struct to be propagated to impls - let attrs = thin_vec![cx.attr_word(sym::automatically_derived, span),]; + let attrs = thin_vec![cx.attr_word(sym::automatically_derived, span, span),]; // # Validity assertion which will be checked later in `rustc_hir_analysis::coherence::builtins`. { let trait_path = diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 8ab21986e68a0..48b314d1a1a5a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -32,7 +32,7 @@ pub(crate) fn expand_deriving_debug( explicit_self: true, nonself_args: vec![(fmtr, sym::f)], ret_ty: Path(path_std!(fmt::Result)), - attributes: thin_vec![cx.attr_word(sym::inline, span)], + attributes: thin_vec![cx.attr_word(sym::inline, span, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless, combine_substructure: combine_substructure(Box::new(|a, b, c| { diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 1fe567e23f455..c3a1f31745463 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -35,7 +35,7 @@ pub(crate) fn expand_deriving_default( explicit_self: false, nonself_args: Vec::new(), ret_ty: Self_, - attributes: thin_vec![cx.attr_word(sym::inline, span)], + attributes: thin_vec![cx.attr_word(sym::inline, span, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| { match substr.fields { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 8c3093acea450..4a8f6590b9246 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -785,7 +785,7 @@ impl<'a> TraitDef<'a> { let path = cx.path_all(self.span, false, vec![type_ident], self_params); let self_type = cx.ty_path(path); - let attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span),]; + let attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span, self.span)]; let opt_trait_ref = Some(trait_ref); cx.item( diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 6e6dbe19e4d1a..9db2c3ab1e918 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -33,7 +33,7 @@ pub(crate) fn expand_deriving_hash( explicit_self: true, nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)], ret_ty: Unit, - attributes: thin_vec![cx.attr_word(sym::inline, span)], + attributes: thin_vec![cx.attr_word(sym::inline, span, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|a, b, c| { hash_substructure(a, b, c) diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 4b1958bce3223..2d0106599d902 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -102,7 +102,7 @@ impl AllocFnFactory<'_, '_> { } fn attrs(&self) -> AttrVec { - thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)] + thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span, self.span)] } fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec) -> P { diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 42b7e0e06d1f3..46c4d895e3ce3 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -372,9 +372,9 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { cx.expr_array_ref(span, decls), ); decls_static.attrs.extend([ - cx.attr_word(sym::rustc_proc_macro_decls, span), - cx.attr_word(sym::used, span), - cx.attr_nested_word(sym::allow, sym::deprecated, span), + cx.attr_word(sym::rustc_proc_macro_decls, span, span), + cx.attr_word(sym::used, span, span), + cx.attr_nested_word(sym::allow, sym::deprecated, span, span), ]); let block = cx.expr_block( diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 682e7c9b17ae8..0796e816b6454 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -43,7 +43,7 @@ pub fn inject( let item = cx.item( span, - thin_vec![cx.attr_word(sym::macro_use, span)], + thin_vec![cx.attr_word(sym::macro_use, span, span)], ast::ItemKind::ExternCrate(None, Ident::new(name, ident_span)), ); @@ -67,7 +67,7 @@ pub fn inject( // Inject the relevant crate's prelude. let use_item = cx.item( span, - thin_vec![cx.attr_word(sym::prelude_import, span)], + thin_vec![cx.attr_word(sym::prelude_import, span, span)], ast::ItemKind::Use(ast::UseTree { prefix: cx.path(span, import_path), kind: ast::UseTreeKind::Glob, diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index b067578794b30..2e34574c3f6f4 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -69,7 +69,12 @@ pub(crate) fn expand_test_case( kind: ast::VisibilityKind::Public, tokens: None, }; - item.attrs.push(ecx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, sp)); + item.attrs.push(ecx.attr_name_value_str( + sym::rustc_test_marker, + test_path_symbol, + sp, + sp, + )); } _ => {} } @@ -200,7 +205,7 @@ pub(crate) fn expand_test_or_bench( // corresponding macro declaration in `core::macros`. let coverage_off = |mut expr: P| { assert_matches!(expr.kind, ast::ExprKind::Closure(_)); - expr.attrs.push(cx.attr_nested_word(sym::coverage, sym::off, sp)); + expr.attrs.push(cx.attr_nested_word(sym::coverage, sym::off, sp, sp)); expr }; @@ -272,11 +277,11 @@ pub(crate) fn expand_test_or_bench( sp, thin_vec![ // #[cfg(test)] - cx.attr_nested_word(sym::cfg, sym::test, attr_sp), + cx.attr_nested_word(sym::cfg, sym::test, attr_sp, attr_sp), // #[rustc_test_marker = "test_case_sort_key"] - cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp), + cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp, attr_sp), // #[doc(hidden)] - cx.attr_nested_word(sym::doc, sym::hidden, attr_sp), + cx.attr_nested_word(sym::doc, sym::hidden, attr_sp, attr_sp), ], // const $ident: test::TestDescAndFn = ast::ItemKind::Const( diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 111c85d49eb0d..715beb45654b0 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -208,6 +208,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { sym::allow, sym::dead_code, self.def_site, + self.def_site, ); item.attrs.retain(|attr| !attr.has_name(sym::rustc_main)); item.attrs.push(allow_dead_code); @@ -312,11 +313,11 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { ); // #[rustc_main] - let main_attr = ecx.attr_word(sym::rustc_main, sp); + let main_attr = ecx.attr_word(sym::rustc_main, sp, sp); // #[coverage(off)] - let coverage_attr = ecx.attr_nested_word(sym::coverage, sym::off, sp); + let coverage_attr = ecx.attr_nested_word(sym::coverage, sym::off, sp, sp); // #[doc(hidden)] - let doc_hidden_attr = ecx.attr_nested_word(sym::doc, sym::hidden, sp); + let doc_hidden_attr = ecx.attr_nested_word(sym::doc, sym::hidden, sp, sp); // pub fn main() { ... } let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(ThinVec::new())); diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 85683c1a03ff2..b47bc8fb49d76 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -734,15 +734,21 @@ impl<'a> ExtCtxt<'a> { } // Builds `#[name]`. - pub fn attr_word(&self, name: Symbol, span: Span) -> ast::Attribute { + pub fn attr_word(&self, name: Symbol, span: Span, inner_span: Span) -> ast::Attribute { let g = &self.sess.psess.attr_id_generator; - attr::mk_attr_word(g, ast::AttrStyle::Outer, ast::Safety::Default, name, span) + attr::mk_attr_word(g, ast::AttrStyle::Outer, ast::Safety::Default, name, span, inner_span) } // Builds `#[name = val]`. // // Note: `span` is used for both the identifier and the value. - pub fn attr_name_value_str(&self, name: Symbol, val: Symbol, span: Span) -> ast::Attribute { + pub fn attr_name_value_str( + &self, + name: Symbol, + val: Symbol, + span: Span, + inner_span: Span, + ) -> ast::Attribute { let g = &self.sess.psess.attr_id_generator; attr::mk_attr_name_value_str( g, @@ -751,11 +757,18 @@ impl<'a> ExtCtxt<'a> { name, val, span, + inner_span, ) } // Builds `#[outer(inner)]`. - pub fn attr_nested_word(&self, outer: Symbol, inner: Symbol, span: Span) -> ast::Attribute { + pub fn attr_nested_word( + &self, + outer: Symbol, + inner: Symbol, + span: Span, + inner_span: Span, + ) -> ast::Attribute { let g = &self.sess.psess.attr_id_generator; attr::mk_attr_nested_word( g, @@ -764,6 +777,7 @@ impl<'a> ExtCtxt<'a> { outer, inner, span, + inner_span, ) } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 170ac39d1ec34..7124bcab5b157 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, AttrKind, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, MetaItemInner, - NodeId, NormalAttr, + MetaItemKind, NodeId, NormalAttr, }; use rustc_attr_parsing as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; @@ -27,7 +27,7 @@ use tracing::instrument; use crate::errors::{ CrateNameInCfgAttr, CrateTypeInCfgAttr, FeatureNotAllowed, FeatureRemoved, FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute, MalformedFeatureAttributeHelp, - RemoveExprNotSupported, + NotFollowedByParens, RemoveExprNotSupported, }; /// A folder that strips out items that do not belong in the current configuration. @@ -405,11 +405,16 @@ impl<'a> StripUnconfigured<'a> { return (true, None); } }; + let sugg_span = match (&attr.kind, &meta_item.kind) { + (AttrKind::Normal(attr), MetaItemKind::Word) => attr.item.span.shrink_to_hi(), + (AttrKind::Normal(attr), _) => attr.item.span, + (_, _) => meta_item.span, + }; validate_attr::deny_builtin_meta_unsafety(&self.sess.psess, &meta_item); ( - parse_cfg(&meta_item, self.sess).is_none_or(|meta_item| { + parse_cfg(&meta_item, self.sess, sugg_span).is_none_or(|meta_item| { attr::cfg_matches(meta_item, &self.sess, self.lint_node_id, self.features) }), Some(meta_item), @@ -465,15 +470,25 @@ impl<'a> StripUnconfigured<'a> { } } -pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItemInner> { +pub fn parse_cfg<'a>( + meta_item: &'a MetaItem, + sess: &Session, + suggestion_span: Span, +) -> Option<&'a MetaItemInner> { let span = meta_item.span; match meta_item.meta_item_list() { None => { - sess.dcx().emit_err(InvalidCfg::NotFollowedByParens { span }); + sess.dcx().emit_err(InvalidCfg::NotFollowedByParens { + span, + suggestion: NotFollowedByParens { + lo: suggestion_span.shrink_to_lo(), + hi: suggestion_span.shrink_to_hi(), + }, + }); None } Some([]) => { - sess.dcx().emit_err(InvalidCfg::NoPredicate { span }); + sess.dcx().emit_err(InvalidCfg::NoPredicate { span, suggestion_span }); None } Some([_, .., l]) => { diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index fdbc65aff688c..c913d150c755d 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -213,27 +213,39 @@ pub(crate) struct RemoveExprNotSupported { pub span: Span, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + expand_invalid_cfg_expected_syntax, + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct NotFollowedByParens { + #[suggestion_part(code = "(")] + pub lo: Span, + #[suggestion_part(code = ")")] + pub hi: Span, +} + #[derive(Diagnostic)] pub(crate) enum InvalidCfg { #[diag(expand_invalid_cfg_no_parens)] NotFollowedByParens { #[primary_span] - #[suggestion( - expand_invalid_cfg_expected_syntax, - code = "cfg(/* predicate */)", - applicability = "has-placeholders" - )] span: Span, + #[subdiagnostic] + suggestion: NotFollowedByParens, }, #[diag(expand_invalid_cfg_no_predicate)] NoPredicate { #[primary_span] + span: Span, #[suggestion( expand_invalid_cfg_expected_syntax, code = "cfg(/* predicate */)", - applicability = "has-placeholders" + applicability = "has-placeholders", + style = "verbose" )] - span: Span, + suggestion_span: Span, }, #[diag(expand_invalid_cfg_multiple_predicates)] MultiplePredicates { diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 41d3889c44838..4946eb14c5221 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -297,6 +297,7 @@ impl<'a> Parser<'a> { // Attr items don't have attributes. self.collect_tokens(None, AttrWrapper::empty(), force_collect, |this, _empty_attrs| { + let lo = this.token.span; let is_unsafe = this.eat_keyword(exp!(Unsafe)); let unsafety = if is_unsafe { let unsafe_span = this.prev_token.span; @@ -311,8 +312,9 @@ impl<'a> Parser<'a> { if is_unsafe { this.expect(exp!(CloseParen))?; } + let span = lo.until(this.token.span); Ok(( - ast::AttrItem { unsafety, path, args, tokens: None }, + ast::AttrItem { unsafety, path, args, tokens: None, span }, Trailing::No, UsePreAttrPos::No, )) @@ -427,7 +429,7 @@ impl<'a> Parser<'a> { this.parse_attr_item(ForceCollect::No) }) .unwrap(); - Ok(attr_item.meta(attr_item.path.span).unwrap()) + Ok(attr_item.meta().unwrap()) } else { self.unexpected_any() }; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a05aab22f1e16..fdc77e0769630 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1099,6 +1099,33 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator Cfg::True }; + // for attr in attrs.clone() { + // // #[doc] + // if attr.doc_str().is_none() && attr.has_name(sym::doc) { + // // #[doc(...)] + // if let Some(list) = attr.meta_item_list() { + // for item in list { + // // #[doc(hidden)] + // if !item.has_name(sym::cfg) { + // continue; + // } + // // #[doc(cfg(...))] + // if let Some(cfg_mi) = item + // .meta_item() + // .and_then(|item| rustc_expand::config::parse_cfg(item, sess, item.span)) + // { + // match Cfg::parse(cfg_mi) { + // Ok(new_cfg) => cfg &= new_cfg, + // Err(e) => { + // sess.dcx().span_err(e.span, e.msg); + // } + // } + // } + // } + // } + // } + // } + // treat #[target_feature(enable = "feat")] attributes as if they were // #[doc(cfg(target_feature = "feat"))] attributes as well if let Some(features) = find_attr!(attrs, AttributeKind::TargetFeature(features, _) => features) diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr index 1233ee010de21..d24fa11e199b5 100644 --- a/tests/rustdoc-ui/doc-cfg.stderr +++ b/tests/rustdoc-ui/doc-cfg.stderr @@ -2,7 +2,12 @@ error: `cfg` predicate is not specified --> $DIR/doc-cfg.rs:3:7 | LL | #[doc(cfg(), cfg(foo, bar))] - | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^ + | +help: expected syntax is + | +LL | #[doc(cfg(/* predicate */), cfg(foo, bar))] + | +++++++++++++++ error: multiple `cfg` predicates are specified --> $DIR/doc-cfg.rs:3:23 @@ -14,7 +19,12 @@ error: `cfg` predicate is not specified --> $DIR/doc-cfg.rs:9:7 | LL | #[doc(cfg())] - | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^ + | +help: expected syntax is + | +LL | #[doc(cfg(/* predicate */))] + | +++++++++++++++ error: multiple `cfg` predicates are specified --> $DIR/doc-cfg.rs:10:16 diff --git a/tests/rustdoc-ui/invalid-cfg.stderr b/tests/rustdoc-ui/invalid-cfg.stderr index dae238b052b8a..b6ccfa91ee249 100644 --- a/tests/rustdoc-ui/invalid-cfg.stderr +++ b/tests/rustdoc-ui/invalid-cfg.stderr @@ -2,7 +2,13 @@ error: `cfg` is not followed by parentheses --> $DIR/invalid-cfg.rs:2:7 | LL | #[doc(cfg = "x")] - | ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^ + | +help: expected syntax is + | +LL - #[doc(cfg = "x")] +LL + #[doc(cfg(/* predicate */))] + | error: multiple `cfg` predicates are specified --> $DIR/invalid-cfg.rs:3:14 diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 2f7bf50ead5fd..5ca8c60aa83b7 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -2,7 +2,12 @@ error: `cfg` is not followed by parentheses --> $DIR/malformed-attrs.rs:102:1 | LL | #[cfg] - | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^ + | +help: expected syntax is + | +LL | #[cfg()] + | ++ error: malformed `cfg_attr` attribute input --> $DIR/malformed-attrs.rs:104:1 diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs index 47418b4e091b2..891b4113c131b 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -22,17 +22,28 @@ struct S7; #[cfg(a = 10)] //~ ERROR literal in `cfg` predicate value must be a string struct S8; -#[cfg(a = b"hi")] //~ ERROR literal in `cfg` predicate value must be a string +#[cfg(a = b"hi")] //~ ERROR literal in `cfg` predicate value must be a string struct S9; +#[cfg = a] //~ ERROR attribute value must be a literal +struct S10; + +#[cfg(a)] //~ WARN unexpected `cfg` condition name: `a` +struct S11; + macro_rules! generate_s10 { ($expr: expr) => { #[cfg(feature = $expr)] //~^ ERROR expected unsuffixed literal, found `expr` metavariable - struct S10; + struct S12; } } generate_s10!(concat!("nonexistent")); +mod m { + #![cfg] //~ ERROR `cfg` is not followed by parentheses + #![cfg = 10] //~ ERROR `cfg` is not followed by parentheses + #![cfg()] //~ ERROR `cfg` predicate is not specified +} fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index 66ce2ee98589d..aee55cbceae04 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -2,19 +2,34 @@ error: `cfg` is not followed by parentheses --> $DIR/cfg-attr-syntax-validation.rs:1:1 | LL | #[cfg] - | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^ + | +help: expected syntax is + | +LL | #[cfg()] + | ++ error: `cfg` is not followed by parentheses --> $DIR/cfg-attr-syntax-validation.rs:4:1 | LL | #[cfg = 10] - | ^^^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^^^ + | +help: expected syntax is + | +LL | #[(cfg = 10)] + | + + error: `cfg` predicate is not specified --> $DIR/cfg-attr-syntax-validation.rs:7:1 | LL | #[cfg()] - | ^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^ + | +help: expected syntax is + | +LL | #[cfg(/* predicate */)] + | +++++++++++++++ error: multiple `cfg` predicates are specified --> $DIR/cfg-attr-syntax-validation.rs:10:10 @@ -54,8 +69,47 @@ LL | #[cfg(a = b"hi")] | | | help: consider removing the prefix +error: attribute value must be a literal + --> $DIR/cfg-attr-syntax-validation.rs:28:9 + | +LL | #[cfg = a] + | ^ + +error: `cfg` is not followed by parentheses + --> $DIR/cfg-attr-syntax-validation.rs:45:5 + | +LL | #![cfg] + | ^^^^^^^ + | +help: expected syntax is + | +LL | #![cfg()] + | ++ + +error: `cfg` is not followed by parentheses + --> $DIR/cfg-attr-syntax-validation.rs:46:5 + | +LL | #![cfg = 10] + | ^^^^^^^^^^^^ + | +help: expected syntax is + | +LL | #![(cfg = 10)] + | + + + +error: `cfg` predicate is not specified + --> $DIR/cfg-attr-syntax-validation.rs:47:5 + | +LL | #![cfg()] + | ^^^^^^^^^ + | +help: expected syntax is + | +LL | #![cfg(/* predicate */)] + | +++++++++++++++ + error: expected unsuffixed literal, found `expr` metavariable - --> $DIR/cfg-attr-syntax-validation.rs:30:25 + --> $DIR/cfg-attr-syntax-validation.rs:36:25 | LL | #[cfg(feature = $expr)] | ^^^^^ @@ -65,7 +119,18 @@ LL | generate_s10!(concat!("nonexistent")); | = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 10 previous errors +warning: unexpected `cfg` condition name: `a` + --> $DIR/cfg-attr-syntax-validation.rs:31:7 + | +LL | #[cfg(a)] + | ^ help: found config with similar value: `target_feature = "a"` + | + = help: expected names are: `FALSE` and `test` and 31 more + = help: to expect this configuration use `--check-cfg=cfg(a)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +error: aborting due to 14 previous errors; 1 warning emitted Some errors have detailed explanations: E0537, E0565. For more information about an error, try `rustc --explain E0537`. diff --git a/tests/ui/imports/unused-macro-use.stderr b/tests/ui/imports/unused-macro-use.stderr index 7137a90e45956..fc5d5045fd6c3 100644 --- a/tests/ui/imports/unused-macro-use.stderr +++ b/tests/ui/imports/unused-macro-use.stderr @@ -1,8 +1,8 @@ error: unused `#[macro_use]` import - --> $DIR/unused-macro-use.rs:3:1 + --> $DIR/unused-macro-use.rs:3:3 | LL | #[macro_use] - | ^^^^^^^^^^^^ + | ^^^^^^^^^ | note: the lint level is defined here --> $DIR/unused-macro-use.rs:1:9 diff --git a/tests/ui/macros/macro-shadowing.stderr b/tests/ui/macros/macro-shadowing.stderr index a052b43ac10e4..77cc1afaf649f 100644 --- a/tests/ui/macros/macro-shadowing.stderr +++ b/tests/ui/macros/macro-shadowing.stderr @@ -1,8 +1,8 @@ error: `macro_two` is already in scope - --> $DIR/macro-shadowing.rs:12:5 + --> $DIR/macro-shadowing.rs:12:7 | LL | #[macro_use] - | ^^^^^^^^^^^^ + | ^^^^^^^^^ ... LL | m1!(); | ----- in this macro invocation diff --git a/tests/ui/proc-macro/proc-macro-attributes.stderr b/tests/ui/proc-macro/proc-macro-attributes.stderr index 140d879069040..3b681e1aeffa4 100644 --- a/tests/ui/proc-macro/proc-macro-attributes.stderr +++ b/tests/ui/proc-macro/proc-macro-attributes.stderr @@ -17,10 +17,10 @@ note: `B` could refer to the derive helper attribute defined here LL | #[derive(B)] | ^ note: `B` could also refer to the derive macro imported here - --> $DIR/proc-macro-attributes.rs:3:1 + --> $DIR/proc-macro-attributes.rs:3:3 | LL | #[macro_use] - | ^^^^^^^^^^^^ + | ^^^^^^^^^ error[E0659]: `B` is ambiguous --> $DIR/proc-macro-attributes.rs:10:3 @@ -35,10 +35,10 @@ note: `B` could refer to the derive helper attribute defined here LL | #[derive(B)] | ^ note: `B` could also refer to the derive macro imported here - --> $DIR/proc-macro-attributes.rs:3:1 + --> $DIR/proc-macro-attributes.rs:3:3 | LL | #[macro_use] - | ^^^^^^^^^^^^ + | ^^^^^^^^^ error[E0659]: `B` is ambiguous --> $DIR/proc-macro-attributes.rs:13:3 @@ -53,10 +53,10 @@ note: `B` could refer to the derive helper attribute defined here LL | #[derive(B)] | ^ note: `B` could also refer to the derive macro imported here - --> $DIR/proc-macro-attributes.rs:3:1 + --> $DIR/proc-macro-attributes.rs:3:3 | LL | #[macro_use] - | ^^^^^^^^^^^^ + | ^^^^^^^^^ error[E0659]: `B` is ambiguous --> $DIR/proc-macro-attributes.rs:16:3 @@ -71,10 +71,10 @@ note: `B` could refer to the derive helper attribute defined here LL | #[derive(B)] | ^ note: `B` could also refer to the derive macro imported here - --> $DIR/proc-macro-attributes.rs:3:1 + --> $DIR/proc-macro-attributes.rs:3:3 | LL | #[macro_use] - | ^^^^^^^^^^^^ + | ^^^^^^^^^ warning: derive helper attribute is used before it is introduced --> $DIR/proc-macro-attributes.rs:6:3 diff --git a/tests/ui/rust-2018/macro-use-warned-against.stderr b/tests/ui/rust-2018/macro-use-warned-against.stderr index 3ac1f12705170..c47827ab367e5 100644 --- a/tests/ui/rust-2018/macro-use-warned-against.stderr +++ b/tests/ui/rust-2018/macro-use-warned-against.stderr @@ -1,8 +1,8 @@ warning: applying the `#[macro_use]` attribute to an `extern crate` item is deprecated - --> $DIR/macro-use-warned-against.rs:7:1 + --> $DIR/macro-use-warned-against.rs:7:3 | LL | #[macro_use] - | ^^^^^^^^^^^^ + | ^^^^^^^^^ | = help: remove it and import macros at use sites with a `use` item instead note: the lint level is defined here @@ -12,10 +12,10 @@ LL | #![warn(macro_use_extern_crate, unused)] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused `#[macro_use]` import - --> $DIR/macro-use-warned-against.rs:9:1 + --> $DIR/macro-use-warned-against.rs:9:3 | LL | #[macro_use] - | ^^^^^^^^^^^^ + | ^^^^^^^^^ | note: the lint level is defined here --> $DIR/macro-use-warned-against.rs:5:33