diff --git a/Cargo.lock b/Cargo.lock index 0f6368e4497cb..e117397bd11b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4010,6 +4010,7 @@ dependencies = [ name = "rustc_feature" version = "0.0.0" dependencies = [ + "rustc_ast", "rustc_data_structures", "rustc_hir", "rustc_span", diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index f838f73838499..4c5616084cb0b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -327,8 +327,11 @@ pub fn parse_cfg_attr( }) { Ok(r) => return Some(r), Err(e) => { - let suggestions = CFG_ATTR_TEMPLATE - .suggestions(AttrSuggestionStyle::Attribute(cfg_attr.style), sym::cfg_attr); + let suggestions = CFG_ATTR_TEMPLATE.suggestions( + AttrSuggestionStyle::Attribute(cfg_attr.style), + cfg_attr.get_normal_item().unsafety, + sym::cfg_attr, + ); e.with_span_suggestions( cfg_attr.span, "must be of the form", @@ -360,8 +363,11 @@ pub fn parse_cfg_attr( description: ParsedDescription::Attribute, reason, suggestions: session_diagnostics::AttributeParseErrorSuggestions::CreatedByTemplate( - CFG_ATTR_TEMPLATE - .suggestions(AttrSuggestionStyle::Attribute(cfg_attr.style), sym::cfg_attr), + CFG_ATTR_TEMPLATE.suggestions( + AttrSuggestionStyle::Attribute(cfg_attr.style), + cfg_attr.get_normal_item().unsafety, + sym::cfg_attr, + ), ), }); } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 81cd32faea127..750fe10a483fc 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -5,7 +5,7 @@ use std::mem; use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; -use rustc_ast::{AttrStyle, MetaItemLit}; +use rustc_ast::{AttrStyle, MetaItemLit, Safety}; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan}; use rustc_feature::{AttrSuggestionStyle, AttributeTemplate}; @@ -357,6 +357,9 @@ pub struct AcceptContext<'f, 'sess> { /// Used in reporting errors to give a hint to users what the attribute *should* look like. pub(crate) template: &'f AttributeTemplate, + /// The safety attribute (if any) applied to the attribute. + pub(crate) attr_safety: Safety, + /// The name of the attribute we're currently accepting. pub(crate) attr_path: AttrPath, } @@ -873,7 +876,7 @@ impl<'a, 'f, 'sess: 'f> AttributeDiagnosticContext<'a, 'f, 'sess> { ParsedDescription::Macro => AttrSuggestionStyle::Macro, }; - self.template.suggestions(style, &self.attr_path) + self.template.suggestions(style, self.attr_safety, &self.attr_path) } } @@ -1064,7 +1067,7 @@ impl<'a, 'f, 'sess: 'f> AttributeDiagnosticContext<'a, 'f, 'sess> { ParsedDescription::Macro => AttrSuggestionStyle::Macro, }; - self.template.suggestions(style, &self.attr_path) + self.template.suggestions(style, self.attr_safety, &self.attr_path) } /// Error that a string literal was expected. /// You can optionally give the literal you did find (which you found not to be a string literal) diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 8260663850344..4a0ad63c0c053 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -234,6 +234,7 @@ impl<'sess> AttributeParser<'sess> { attr_style, parsed_description, template, + attr_safety: attr_safety.unwrap_or(Safety::Default), attr_path, }; parse_fn(&mut cx, args) @@ -404,6 +405,7 @@ impl<'sess> AttributeParser<'sess> { attr_style: attr.style, parsed_description: ParsedDescription::Attribute, template: &accept.template, + attr_safety: n.item.unsafety, attr_path: attr_path.clone(), }; diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml index a4746ac455c1d..3cd88cc4bc116 100644 --- a/compiler/rustc_feature/Cargo.toml +++ b/compiler/rustc_feature/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 58bf12855ad6e..34e94497c8a66 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -3,6 +3,7 @@ use std::sync::LazyLock; use AttributeGate::*; +use rustc_ast::ast::Safety; use rustc_data_structures::fx::FxHashMap; use rustc_hir::AttrStyle; use rustc_span::{Symbol, sym}; @@ -118,6 +119,7 @@ impl AttributeTemplate { pub fn suggestions( &self, style: AttrSuggestionStyle, + safety: Safety, name: impl std::fmt::Display, ) -> Vec { let (start, macro_call, end) = match style { @@ -129,20 +131,32 @@ impl AttributeTemplate { let mut suggestions = vec![]; + let (safety_start, safety_end) = match safety { + Safety::Unsafe(_) => ("unsafe(", ")"), + _ => ("", ""), + }; + if self.word { debug_assert!(macro_call.is_empty(), "Macro suggestions use list style"); - suggestions.push(format!("{start}{name}{end}")); + suggestions.push(format!("{start}{safety_start}{name}{safety_end}{end}")); } if let Some(descr) = self.list { for descr in descr { - suggestions.push(format!("{start}{name}{macro_call}({descr}){end}")); + suggestions.push(format!( + "{start}{safety_start}{name}{macro_call}({descr}){safety_end}{end}" + )); } } - suggestions.extend(self.one_of.iter().map(|&word| format!("{start}{name}({word}){end}"))); + suggestions.extend( + self.one_of + .iter() + .map(|&word| format!("{start}{safety_start}{name}({word}){safety_end}{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}")); + suggestions + .push(format!("{start}{safety_start}{name} = \"{descr}\"{safety_end}{end}")); } } suggestions.sort(); diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 784cbb38aaedd..4c9673bf80562 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -159,9 +159,8 @@ LL | #[unsafe(export_name)] | help: must be of the form | -LL - #[unsafe(export_name)] -LL + #[export_name = "name"] - | +LL | #[unsafe(export_name = "name")] + | ++++++++ error: `rustc_allow_const_fn_unstable` expects a list of feature names --> $DIR/malformed-attrs.rs:31:1 @@ -330,7 +329,7 @@ LL | #[unsafe(naked())] help: must be of the form | LL - #[unsafe(naked())] -LL + #[naked] +LL + #[unsafe(naked)] | error[E0565]: malformed `track_caller` attribute input @@ -651,7 +650,7 @@ LL | #[unsafe(ffi_pure = 1)] help: must be of the form | LL - #[unsafe(ffi_pure = 1)] -LL + #[ffi_pure] +LL + #[unsafe(ffi_pure)] | error[E0539]: malformed `link_ordinal` attribute input @@ -677,7 +676,7 @@ LL | #[unsafe(ffi_const = 1)] help: must be of the form | LL - #[unsafe(ffi_const = 1)] -LL + #[ffi_const] +LL + #[unsafe(ffi_const)] | error[E0539]: malformed `linkage` attribute input