From f6cdd7eab53e7bac95f19cdb13527d4e9c7c0b3f Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 4 Nov 2025 17:29:16 +0100 Subject: [PATCH] Fix suggestion for the `cfg!` macro Signed-off-by: Jonathan Brouwer --- .../rustc_attr_parsing/src/attributes/cfg.rs | 9 +++--- compiler/rustc_attr_parsing/src/context.rs | 14 ++++++--- compiler/rustc_feature/src/builtin_attrs.rs | 31 ++++++++++++++----- compiler/rustc_feature/src/lib.rs | 7 +++-- tests/ui/macros/cfg.stderr | 4 +-- tests/ui/span/E0805.stderr | 2 +- 6 files changed, 46 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 47b46cd69d84c..84ce0b7e1ddf0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -2,7 +2,7 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, NodeId, ast, token}; use rustc_errors::{Applicability, PResult}; -use rustc_feature::{AttributeTemplate, Features, template}; +use rustc_feature::{AttrSuggestionStyle, AttributeTemplate, Features, template}; use rustc_hir::attrs::CfgEntry; use rustc_hir::{AttrPath, RustcVersion}; use rustc_parse::parser::{ForceCollect, Parser}; @@ -324,8 +324,8 @@ pub fn parse_cfg_attr( }) { Ok(r) => return Some(r), Err(e) => { - let suggestions = - CFG_ATTR_TEMPLATE.suggestions(Some(cfg_attr.style), sym::cfg_attr); + let suggestions = CFG_ATTR_TEMPLATE + .suggestions(AttrSuggestionStyle::Attribute(cfg_attr.style), sym::cfg_attr); e.with_span_suggestions( cfg_attr.span, "must be of the form", @@ -356,7 +356,8 @@ pub fn parse_cfg_attr( path: AttrPath::from_ast(&cfg_attr.get_normal_item().path), description: ParsedDescription::Attribute, reason, - suggestions: CFG_ATTR_TEMPLATE.suggestions(Some(cfg_attr.style), sym::cfg_attr), + suggestions: CFG_ATTR_TEMPLATE + .suggestions(AttrSuggestionStyle::Attribute(cfg_attr.style), sym::cfg_attr), }); } } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index a3473c675dd59..8512fece0fc03 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -6,7 +6,7 @@ use std::sync::LazyLock; use private::Sealed; use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId}; use rustc_errors::{Diag, Diagnostic, Level}; -use rustc_feature::AttributeTemplate; +use rustc_feature::{AttrSuggestionStyle, AttributeTemplate}; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId}; @@ -638,9 +638,15 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { } pub(crate) fn suggestions(&self) -> Vec { - // If the outer and inner spans are equal, we are parsing an attribute from `cfg_attr`, - // So don't display an attribute style in the suggestions - let style = (self.attr_span != self.inner_span).then_some(self.attr_style); + let style = match self.parsed_description { + // If the outer and inner spans are equal, we are parsing an embedded attribute + ParsedDescription::Attribute if self.attr_span == self.inner_span => { + AttrSuggestionStyle::EmbeddedAttribute + } + ParsedDescription::Attribute => AttrSuggestionStyle::Attribute(self.attr_style), + ParsedDescription::Macro => AttrSuggestionStyle::Macro, + }; + self.template.suggestions(style, &self.attr_path) } } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5dcb5df55720c..e85db258ad94b 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -132,28 +132,45 @@ pub struct AttributeTemplate { pub docs: Option<&'static str>, } +pub enum AttrSuggestionStyle { + /// The suggestion is styled for a normal attribute. + /// The `AttrStyle` determines whether this is an inner or outer attribute. + Attribute(AttrStyle), + /// The suggestion is styled for an attribute embedded into another attribute. + /// For example, attributes inside `#[cfg_attr(true, attr(...)]`. + EmbeddedAttribute, + /// The suggestion is styled for macros that are parsed with attribute parsers. + /// For example, the `cfg!(predicate)` macro. + Macro, +} + impl AttributeTemplate { pub fn suggestions( &self, - style: Option, + style: AttrSuggestionStyle, name: impl std::fmt::Display, ) -> Vec { - let mut suggestions = vec![]; - let (start, end) = match style { - Some(AttrStyle::Outer) => ("#[", "]"), - Some(AttrStyle::Inner) => ("#![", "]"), - None => ("", ""), + let (start, macro_call, end) = match style { + AttrSuggestionStyle::Attribute(AttrStyle::Outer) => ("#[", "", "]"), + AttrSuggestionStyle::Attribute(AttrStyle::Inner) => ("#![", "", "]"), + AttrSuggestionStyle::Macro => ("", "!", ""), + AttrSuggestionStyle::EmbeddedAttribute => ("", "", ""), }; + + let mut suggestions = vec![]; + if self.word { + debug_assert!(macro_call.is_empty(), "Macro suggestions use list style"); suggestions.push(format!("{start}{name}{end}")); } if let Some(descr) = self.list { for descr in descr { - suggestions.push(format!("{start}{name}({descr}){end}")); + suggestions.push(format!("{start}{name}{macro_call}({descr}){end}")); } } suggestions.extend(self.one_of.iter().map(|&word| format!("{start}{name}({word}){end}"))); if let Some(descr) = self.name_value_str { + debug_assert!(macro_call.is_empty(), "Macro suggestions use list style"); for descr in descr { suggestions.push(format!("{start}{name} = \"{descr}\"{end}")); } diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index dbc0daa3d8383..e53869a717f9d 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -135,9 +135,10 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option @@ -22,7 +22,7 @@ LL | cfg!(foo = 123); | ^^^^^^^^^^^---^ | | | | | expected a string literal here - | help: must be of the form: `cfg(predicate)` + | help: must be of the form: `cfg!(predicate)` | = note: for more information, visit diff --git a/tests/ui/span/E0805.stderr b/tests/ui/span/E0805.stderr index 58c0e31ce0840..0247e8d8ec9b4 100644 --- a/tests/ui/span/E0805.stderr +++ b/tests/ui/span/E0805.stderr @@ -5,7 +5,7 @@ LL | if cfg!(not()) { } | ^^^^^^^^--^ | | | | | expected a single argument here - | help: must be of the form: `cfg(predicate)` + | help: must be of the form: `cfg!(predicate)` | = note: for more information, visit