diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index e57f8da26769b..94000454caaa4 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1067,7 +1067,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_attribute(&mut self, attr: &Attribute) { - validate_attr::check_attr(&self.sess.psess, attr, self.lint_node_id); + validate_attr::check_attr(&self.sess.psess, attr); } fn visit_ty(&mut self, ty: &'a Ty) { diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index a8aa63bd05ee6..bd228315b2c95 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -1,3 +1,5 @@ +use std::convert::identity; + use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, NodeId, ast, token}; @@ -353,7 +355,7 @@ pub fn parse_cfg_attr( span, attr_span: cfg_attr.span, template: CFG_ATTR_TEMPLATE, - path: AttrPath::from_ast(&cfg_attr.get_normal_item().path), + path: AttrPath::from_ast(&cfg_attr.get_normal_item().path, identity), description: ParsedDescription::Attribute, reason, suggestions: CFG_ATTR_TEMPLATE @@ -398,6 +400,7 @@ fn parse_cfg_attr_internal<'a>( .into_boxed_slice(), span: attribute.span, }, + Some(attribute.get_normal_item().unsafety), ParsedDescription::Attribute, pred_span, CRATE_NODE_ID, diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs index 8006fb963b198..0c0915558089e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs @@ -63,6 +63,7 @@ pub fn parse_cfg_select( segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(), span: cfg_span, }, + None, ParsedDescription::Macro, cfg_span, lint_node_id, diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index b7a6a1ef6d667..87e29b7b0de6e 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use rustc_ast as ast; -use rustc_ast::{AttrStyle, NodeId}; +use rustc_ast::{AttrStyle, NodeId, Safety}; use rustc_errors::DiagCtxtHandle; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; @@ -146,6 +146,7 @@ impl<'sess> AttributeParser<'sess, Early> { normal_attr.item.span(), attr.style, path.get_attribute_path(), + Some(normal_attr.item.unsafety), ParsedDescription::Attribute, target_span, target_node_id, @@ -165,6 +166,7 @@ impl<'sess> AttributeParser<'sess, Early> { inner_span: Span, attr_style: AttrStyle, attr_path: AttrPath, + attr_safety: Option, parsed_description: ParsedDescription, target_span: Span, target_node_id: NodeId, @@ -181,14 +183,24 @@ impl<'sess> AttributeParser<'sess, Early> { sess, stage: Early { emit_errors }, }; + let mut emit_lint = |lint| { + crate::lints::emit_attribute_lint(&lint, sess); + }; + if let Some(safety) = attr_safety { + parser.check_attribute_safety( + &attr_path, + inner_span, + safety, + &mut emit_lint, + target_node_id, + ) + } let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext { shared: SharedContext { cx: &mut parser, target_span, target_id: target_node_id, - emit_lint: &mut |lint| { - crate::lints::emit_attribute_lint(&lint, sess); - }, + emit_lint: &mut emit_lint, }, attr_span, inner_span, @@ -288,6 +300,15 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { // } ast::AttrKind::Normal(n) => { attr_paths.push(PathParser(Cow::Borrowed(&n.item.path))); + let attr_path = AttrPath::from_ast(&n.item.path, lower_span); + + self.check_attribute_safety( + &attr_path, + lower_span(n.item.span()), + n.item.unsafety, + &mut emit_lint, + target_id, + ); let parts = n.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); @@ -301,7 +322,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { ) else { continue; }; - let path = parser.path(); let args = parser.args(); for accept in accepts { let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { @@ -312,11 +332,11 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { emit_lint: &mut emit_lint, }, attr_span: lower_span(attr.span), - inner_span: lower_span(attr.get_normal_item().span()), + inner_span: lower_span(n.item.span()), attr_style: attr.style, parsed_description: ParsedDescription::Attribute, template: &accept.template, - attr_path: path.get_attribute_path(), + attr_path: attr_path.clone(), }; (accept.accept_fn)(&mut cx, args); @@ -341,7 +361,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { // ); attributes.push(Attribute::Unparsed(Box::new(AttrItem { - path: AttrPath::from_ast(&n.item.path), + path: attr_path.clone(), args: self.lower_attr_args(&n.item.args, lower_span), id: HashIgnoredAttrId { attr_id: attr.id }, style: attr.style, diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 046cca4c742b0..7a7f2555287a2 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -98,6 +98,7 @@ mod interface; pub mod parser; mod lints; +mod safety; mod session_diagnostics; mod target_checking; pub mod validate_attr; diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index 3a2a370466961..a23884d7f71eb 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -98,5 +98,17 @@ pub fn emit_attribute_lint(lint: &AttributeLint, lint_emi }, ) } + &AttributeLintKind::UnsafeAttrOutsideUnsafe { + attribute_name_span, + sugg_spans: (left, right), + } => lint_emitter.emit_node_span_lint( + rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE, + *id, + *span, + session_diagnostics::UnsafeAttrOutsideUnsafeLint { + span: attribute_name_span, + suggestion: session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion { left, right }, + }, + ), } } diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs new file mode 100644 index 0000000000000..ff385bf13aaa9 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/safety.rs @@ -0,0 +1,116 @@ +use rustc_ast::Safety; +use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP}; +use rustc_hir::AttrPath; +use rustc_hir::lints::{AttributeLint, AttributeLintKind}; +use rustc_span::{Span, sym}; + +use crate::context::Stage; +use crate::{AttributeParser, ShouldEmit}; + +impl<'sess, S: Stage> AttributeParser<'sess, S> { + pub fn check_attribute_safety( + &mut self, + attr_path: &AttrPath, + attr_span: Span, + attr_safety: Safety, + emit_lint: &mut impl FnMut(AttributeLint), + target_id: S::Id, + ) { + if matches!(self.stage.should_emit(), ShouldEmit::Nothing) { + return; + } + + let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0].name); + if let Some(name) = name + && [sym::cfg_trace, sym::cfg_attr_trace].contains(&name) + { + return; + } + + // FIXME: We should retrieve this information from the attribute parsers instead of from `BUILTIN_ATTRIBUTE_MAP` + let builtin_attr_info = name.and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)); + let builtin_attr_safety = builtin_attr_info.map(|x| x.safety); + + match (builtin_attr_safety, attr_safety) { + // - Unsafe builtin attribute + // - User wrote `#[unsafe(..)]`, which is permitted on any edition + (Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => { + // OK + } + + // - Unsafe builtin attribute + // - User did not write `#[unsafe(..)]` + (Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => { + let path_span = attr_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 = attr_span; + + // Attributes can be safe in earlier editions, and become unsafe in later ones. + // + // Use the span of the attribute's name to determine the edition: the span of the + // attribute as a whole may be inaccurate if it was emitted by a macro. + // + // See https://github.com/rust-lang/rust/issues/142182. + let emit_error = match unsafe_since { + None => true, + Some(unsafe_since) => path_span.edition() >= unsafe_since, + }; + + if emit_error { + self.stage.emit_err( + self.sess, + crate::session_diagnostics::UnsafeAttrOutsideUnsafe { + span: path_span, + suggestion: + crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion { + left: diag_span.shrink_to_lo(), + right: diag_span.shrink_to_hi(), + }, + }, + ); + } else { + emit_lint(AttributeLint { + id: target_id, + span: path_span, + kind: AttributeLintKind::UnsafeAttrOutsideUnsafe { + attribute_name_span: path_span, + sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), + }, + }) + } + } + + // - Normal builtin attribute + // - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes + (None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => { + self.stage.emit_err( + self.sess, + crate::session_diagnostics::InvalidAttrUnsafe { + span: unsafe_span, + name: attr_path.clone(), + }, + ); + } + + // - Normal builtin attribute + // - No explicit `#[unsafe(..)]` written. + (None | Some(AttributeSafety::Normal), Safety::Default) => { + // OK + } + + ( + Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None, + Safety::Safe(..), + ) => { + self.sess.dcx().span_delayed_bug( + attr_span, + "`check_attribute_safety` does not expect `Safety::Safe` on attributes", + ); + } + } + } +} diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 8d783503f7be0..f94f0867451f0 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -1,6 +1,6 @@ use std::num::IntErrorKind; -use rustc_ast::{self as ast, Path}; +use rustc_ast::{self as ast}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, @@ -790,7 +790,7 @@ pub(crate) struct InvalidAttrUnsafe { #[primary_span] #[label] pub span: Span, - pub name: Path, + pub name: AttrPath, } #[derive(Diagnostic)] @@ -803,6 +803,15 @@ pub(crate) struct UnsafeAttrOutsideUnsafe { pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, } +#[derive(LintDiagnostic)] +#[diag(attr_parsing_unsafe_attr_outside_unsafe)] +pub(crate) struct UnsafeAttrOutsideUnsafeLint { + #[label] + pub span: Span, + #[subdiagnostic] + pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, +} + #[derive(Subdiagnostic)] #[multipart_suggestion( attr_parsing_unsafe_attr_outside_unsafe_suggestion, diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index 4065fe7ce1735..c57e0baea05f6 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -1,25 +1,26 @@ //! Meta-syntax validation logic of attributes for post-expansion. +use std::convert::identity; use std::slice; use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{ - self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, NodeId, - Path, Safety, + self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety, }; -use rustc_errors::{Applicability, DiagCtxtHandle, FatalError, PResult}; -use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; +use rustc_errors::{Applicability, FatalError, PResult}; +use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; +use rustc_hir::AttrPath; use rustc_parse::parse_in; use rustc_session::errors::report_lit_error; use rustc_session::lint::BuiltinLintDiag; -use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE}; +use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_session::parse::ParseSess; use rustc_span::{Span, Symbol, sym}; use crate::{AttributeParser, Late, session_diagnostics as errors}; -pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) { +pub fn check_attr(psess: &ParseSess, attr: &Attribute) { if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace) { return; @@ -27,9 +28,6 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) { let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); - let builtin_attr_safety = builtin_attr_info.map(|x| x.safety); - check_attribute_safety(psess, builtin_attr_safety, attr, id); - // Check input tokens for built-in and key-value attributes. match builtin_attr_info { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. @@ -150,101 +148,6 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte } } -pub fn check_attribute_safety( - psess: &ParseSess, - builtin_attr_safety: Option, - attr: &Attribute, - id: NodeId, -) { - let attr_item = attr.get_normal_item(); - match (builtin_attr_safety, attr_item.unsafety) { - // - Unsafe builtin attribute - // - User wrote `#[unsafe(..)]`, which is permitted on any edition - (Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => { - // OK - } - - // - Unsafe builtin attribute - // - User did not write `#[unsafe(..)]` - (Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => { - 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 = attr_item.span(); - - // Attributes can be safe in earlier editions, and become unsafe in later ones. - // - // Use the span of the attribute's name to determine the edition: the span of the - // attribute as a whole may be inaccurate if it was emitted by a macro. - // - // See https://github.com/rust-lang/rust/issues/142182. - let emit_error = match unsafe_since { - None => true, - Some(unsafe_since) => path_span.edition() >= unsafe_since, - }; - - if emit_error { - 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, - id, - BuiltinLintDiag::UnsafeAttrOutsideUnsafe { - attribute_name_span: path_span, - sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), - }, - ); - } - } - - // - Normal builtin attribute - // - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes - (None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => { - psess.dcx().emit_err(errors::InvalidAttrUnsafe { - span: unsafe_span, - name: attr_item.path.clone(), - }); - } - - // - Normal builtin attribute - // - No explicit `#[unsafe(..)]` written. - (None | Some(AttributeSafety::Normal), Safety::Default) => { - // OK - } - - ( - Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None, - Safety::Safe(..), - ) => { - psess.dcx().span_delayed_bug( - attr_item.span(), - "`check_attribute_safety` does not expect `Safety::Safe` on attributes", - ); - } - } -} - -// Called by `check_builtin_meta_item` and code that manually denies -// `unsafe(...)` in `cfg` -pub fn deny_builtin_meta_unsafety(diag: DiagCtxtHandle<'_>, unsafety: Safety, name: &Path) { - // 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 let Safety::Unsafe(unsafe_span) = unsafety { - diag.emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: name.clone() }); - } -} - pub fn check_builtin_meta_item( psess: &ParseSess, meta: &MetaItem, @@ -258,8 +161,11 @@ pub fn check_builtin_meta_item( emit_malformed_attribute(psess, style, meta.span, name, template); } - if deny_unsafety { - deny_builtin_meta_unsafety(psess.dcx(), meta.unsafety, &meta.path); + if deny_unsafety && let Safety::Unsafe(unsafe_span) = meta.unsafety { + psess.dcx().emit_err(errors::InvalidAttrUnsafe { + span: unsafe_span, + name: AttrPath::from_ast(&meta.path, identity), + }); } } diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 5ca4fff948788..b24e3065622d2 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -54,6 +54,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result 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.sess.psess, - Some(AttributeSafety::Normal), - &cfg_attr, - ast::CRATE_NODE_ID, - ); - // A trace attribute left in AST in place of the original `cfg_attr` attribute. // It can later be used by lints or other diagnostics. let trace_attr = attr_into_trace(cfg_attr.clone(), sym::cfg_attr_trace); @@ -421,13 +412,6 @@ impl<'a> StripUnconfigured<'a> { node: NodeId, emit_errors: ShouldEmit, ) -> EvalConfigResult { - // Unsafety check needs to be done explicitly here because this attribute will be removed before the normal check - deny_builtin_meta_unsafety( - self.sess.dcx(), - attr.get_normal_item().unsafety, - &rustc_ast::Path::from_ident(attr.ident().unwrap()), - ); - let Some(cfg) = AttributeParser::parse_single( self.sess, attr, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 6d048c120a211..20fb321307ac5 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -2158,11 +2158,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let mut span: Option = None; while let Some(attr) = attrs.next() { rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features); - validate_attr::check_attr( - &self.cx.sess.psess, - attr, - self.cx.current_expansion.lint_node_id, - ); + validate_attr::check_attr(&self.cx.sess.psess, attr); AttributeParser::parse_limited_all( self.cx.sess, slice::from_ref(attr), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 8f297677ff852..94c47b06e6353 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1193,10 +1193,15 @@ impl IntoDiagArg for AttrPath { } impl AttrPath { - pub fn from_ast(path: &ast::Path) -> Self { + pub fn from_ast(path: &ast::Path, lower_span: impl Copy + Fn(Span) -> Span) -> Self { AttrPath { - segments: path.segments.iter().map(|i| i.ident).collect::>().into_boxed_slice(), - span: path.span, + segments: path + .segments + .iter() + .map(|i| Ident { name: i.ident.name, span: lower_span(i.ident.span) }) + .collect::>() + .into_boxed_slice(), + span: lower_span(path.span), } } } diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index 8563937f70d3c..a4c60fd2cc1ad 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -62,4 +62,8 @@ pub enum AttributeLintKind { target: Target, target_span: Span, }, + UnsafeAttrOutsideUnsafe { + attribute_name_span: Span, + sugg_spans: (Span, Span), + }, } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index bf721154d73be..75e7af4c11733 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -890,10 +890,6 @@ lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::` -lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe - .label = usage of unsafe attribute -lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` - lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´ lint_untranslatable_diag = diagnostics should be created using translatable messages diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index e376d7d2ab883..87ccd114ee97e 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -283,16 +283,6 @@ pub fn decorate_builtin_lint( BuiltinLintDiag::UnusedQualifications { removal_span } => { lints::UnusedQualifications { removal_span }.decorate_lint(diag); } - BuiltinLintDiag::UnsafeAttrOutsideUnsafe { - attribute_name_span, - sugg_spans: (left, right), - } => { - lints::UnsafeAttrOutsideUnsafe { - span: attribute_name_span, - suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }, - } - .decorate_lint(diag); - } BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span: lt_span, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0687490645d3f..6568aa6fd5aa4 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2880,27 +2880,6 @@ pub(crate) struct AssociatedConstElidedLifetime { pub lifetimes_in_scope: MultiSpan, } -#[derive(LintDiagnostic)] -#[diag(lint_unsafe_attr_outside_unsafe)] -pub(crate) struct UnsafeAttrOutsideUnsafe { - #[label] - pub span: Span, - #[subdiagnostic] - pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion( - lint_unsafe_attr_outside_unsafe_suggestion, - applicability = "machine-applicable" -)] -pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { - #[suggestion_part(code = "unsafe(")] - pub left: Span, - #[suggestion_part(code = ")")] - pub right: Span, -} - #[derive(LintDiagnostic)] #[diag(lint_static_mut_refs_lint)] pub(crate) struct RefOfMutStatic<'a> { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 326fdaf9cec92..abdc41eb57c21 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -687,10 +687,6 @@ pub enum BuiltinLintDiag { /// The span of the unnecessarily-qualified path to remove. removal_span: Span, }, - UnsafeAttrOutsideUnsafe { - attribute_name_span: Span, - sugg_spans: (Span, Span), - }, AssociatedConstElidedLifetime { elided: bool, span: Span, diff --git a/tests/incremental/hashes/function_interfaces.rs b/tests/incremental/hashes/function_interfaces.rs index e58ee1a6d4e4b..5b03f9ed6c679 100644 --- a/tests/incremental/hashes/function_interfaces.rs +++ b/tests/incremental/hashes/function_interfaces.rs @@ -279,7 +279,7 @@ pub fn no_mangle() {} #[rustc_clean(cfg = "cfail3")] #[rustc_clean(cfg = "cfail5")] #[rustc_clean(cfg = "cfail6")] -#[no_mangle] +#[unsafe(no_mangle)] pub fn no_mangle() {} // Linkage --------------------------------------------------------------------- diff --git a/tests/incremental/hashes/inherent_impls.rs b/tests/incremental/hashes/inherent_impls.rs index ebcab178f209b..75c0939fbfcde 100644 --- a/tests/incremental/hashes/inherent_impls.rs +++ b/tests/incremental/hashes/inherent_impls.rs @@ -5,6 +5,7 @@ // and make sure that the hash has changed, then change nothing between rev2 and // rev3 and make sure that the hash has not changed. +//@ edition: 2024 //@ build-pass (FIXME(62277): could be check-pass?) //@ revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 //@ compile-flags: -Z query-dep-graph -O @@ -649,7 +650,7 @@ impl Foo { //-------------------------- //-------------------------- //-------------------------- - //---------- + //------------------ pub fn add_no_mangle_to_method(&self) { } } @@ -663,7 +664,7 @@ impl Foo { #[rustc_clean(cfg="cfail3")] #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] - #[no_mangle] + #[unsafe(no_mangle)] pub fn add_no_mangle_to_method(&self) { } } diff --git a/tests/incremental/hashes/statics.rs b/tests/incremental/hashes/statics.rs index cd394ed866e9f..94548eeef7fd1 100644 --- a/tests/incremental/hashes/statics.rs +++ b/tests/incremental/hashes/statics.rs @@ -66,7 +66,7 @@ static STATIC_NO_MANGLE: u8 = 0; #[rustc_clean(cfg="cfail3")] #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] -#[no_mangle] +#[unsafe(no_mangle)] static STATIC_NO_MANGLE: u8 = 0; diff --git a/tests/incremental/hashes/trait_impls.rs b/tests/incremental/hashes/trait_impls.rs index 03ca672af1316..d4ac69a8b55de 100644 --- a/tests/incremental/hashes/trait_impls.rs +++ b/tests/incremental/hashes/trait_impls.rs @@ -569,7 +569,7 @@ impl AddNoMangleToMethod for Foo { // ------------------------- // ------------------------- // ------------------------- - // --------- + // ----------------- fn add_no_mangle_to_method(&self) { } } @@ -583,7 +583,7 @@ impl AddNoMangleToMethod for Foo { #[rustc_clean(cfg="cfail3")] #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] - #[no_mangle] + #[unsafe(no_mangle)] fn add_no_mangle_to_method(&self) { } } diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr index 0825cf794083d..8ab945e0f182e 100644 --- a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr @@ -9,6 +9,12 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(r#unsafe(no_mangle))] | ++ +error: cannot find attribute `r#unsafe` in this scope + --> $DIR/double-unsafe-attributes.rs:1:10 + | +LL | #[unsafe(unsafe(no_mangle))] + | ^^^^^^ + error: `r#unsafe` is not an unsafe attribute --> $DIR/double-unsafe-attributes.rs:1:3 | @@ -17,11 +23,5 @@ LL | #[unsafe(unsafe(no_mangle))] | = note: extraneous unsafe is not allowed in attributes -error: cannot find attribute `r#unsafe` in this scope - --> $DIR/double-unsafe-attributes.rs:1:10 - | -LL | #[unsafe(unsafe(no_mangle))] - | ^^^^^^ - error: aborting due to 3 previous errors diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr index 94edb263a6afe..4527cf676f78a 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr @@ -12,46 +12,6 @@ LL | #[unsafe(allow(unsafe(dead_code)))] | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: `proc_macro` is not an unsafe attribute - --> $DIR/proc-unsafe-attributes.rs:1:3 - | -LL | #[unsafe(proc_macro)] - | ^^^^^^ this is not an unsafe attribute - | - = note: extraneous unsafe is not allowed in attributes - -error: `proc_macro_derive` is not an unsafe attribute - --> $DIR/proc-unsafe-attributes.rs:7:3 - | -LL | #[unsafe(proc_macro_derive(Foo))] - | ^^^^^^ this is not an unsafe attribute - | - = 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)] - | ^^^^^^ 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 - | -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:27: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:27:16 | @@ -103,6 +63,22 @@ LL | #[unsafe(allow(unsafe(dead_code)))] | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: `proc_macro` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:1:3 + | +LL | #[unsafe(proc_macro)] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `proc_macro_derive` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:7: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:12:21 | @@ -132,6 +108,30 @@ LL - #[proc_macro_derive(unsafe(Foo))] LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | +error: `proc_macro_attribute` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:18: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 + | +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:27:3 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + error[E0452]: malformed lint attribute input --> $DIR/proc-unsafe-attributes.rs:27:16 | diff --git a/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.rs b/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.rs new file mode 100644 index 0000000000000..c7d7b712925dc --- /dev/null +++ b/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.rs @@ -0,0 +1,10 @@ +// This is a regression test for https://github.com/rust-lang/rust/issues/148453 +// We want the `cannot find attribute` error to appear before `is not an unsafe attribute` +//@ edition: 2024 + +#[unsafe(does_not_exist)] +//~^ ERROR cannot find attribute +//~| ERROR is not an unsafe attribute +fn aa() {} + +fn main() {} diff --git a/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.stderr b/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.stderr new file mode 100644 index 0000000000000..42d9425ed31fa --- /dev/null +++ b/tests/ui/attributes/unsafe/unsafe-nonexistent-attribute.stderr @@ -0,0 +1,16 @@ +error: cannot find attribute `does_not_exist` in this scope + --> $DIR/unsafe-nonexistent-attribute.rs:5:10 + | +LL | #[unsafe(does_not_exist)] + | ^^^^^^^^^^^^^^ + +error: `does_not_exist` is not an unsafe attribute + --> $DIR/unsafe-nonexistent-attribute.rs:5:3 + | +LL | #[unsafe(does_not_exist)] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: aborting due to 2 previous errors + diff --git a/tests/ui/ffi-attrs/ffi_const.stderr b/tests/ui/ffi-attrs/ffi_const.stderr index f3be925431836..af54486e433ca 100644 --- a/tests/ui/ffi-attrs/ffi_const.stderr +++ b/tests/ui/ffi-attrs/ffi_const.stderr @@ -1,14 +1,3 @@ -error: unsafe attribute used without unsafe - --> $DIR/ffi_const.rs:16:7 - | -LL | #[ffi_const] - | ^^^^^^^^^ usage of unsafe attribute - | -help: wrap the attribute in `unsafe(...)` - | -LL | #[unsafe(ffi_const)] - | +++++++ + - error: `#[ffi_const]` attribute cannot be used on functions --> $DIR/ffi_const.rs:4:1 | @@ -33,5 +22,16 @@ LL | #[unsafe(ffi_const)] | = help: `#[ffi_const]` can only be applied to foreign functions +error: unsafe attribute used without unsafe + --> $DIR/ffi_const.rs:16:7 + | +LL | #[ffi_const] + | ^^^^^^^^^ usage of unsafe attribute + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(ffi_const)] + | +++++++ + + error: aborting due to 4 previous errors diff --git a/tests/ui/ffi-attrs/ffi_pure.stderr b/tests/ui/ffi-attrs/ffi_pure.stderr index da1eae975ac2d..11e9199b40f4b 100644 --- a/tests/ui/ffi-attrs/ffi_pure.stderr +++ b/tests/ui/ffi-attrs/ffi_pure.stderr @@ -1,14 +1,3 @@ -error: unsafe attribute used without unsafe - --> $DIR/ffi_pure.rs:16:7 - | -LL | #[ffi_pure] - | ^^^^^^^^ usage of unsafe attribute - | -help: wrap the attribute in `unsafe(...)` - | -LL | #[unsafe(ffi_pure)] - | +++++++ + - error: `#[ffi_pure]` attribute cannot be used on functions --> $DIR/ffi_pure.rs:4:1 | @@ -33,5 +22,16 @@ LL | #[unsafe(ffi_pure)] | = help: `#[ffi_pure]` can only be applied to foreign functions +error: unsafe attribute used without unsafe + --> $DIR/ffi_pure.rs:16:7 + | +LL | #[ffi_pure] + | ^^^^^^^^ usage of unsafe attribute + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(ffi_pure)] + | +++++++ + + error: aborting due to 4 previous errors