diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index bddb50568d41b..46b1d771c2ff9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -489,6 +489,7 @@ pub struct Crate { /// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct MetaItem { + pub unsafety: Unsafe, pub path: Path, pub kind: MetaItemKind, pub span: Span, @@ -2792,7 +2793,12 @@ pub struct NormalAttr { impl NormalAttr { pub fn from_ident(ident: Ident) -> Self { Self { - item: AttrItem { path: Path::from_ident(ident), args: AttrArgs::Empty, tokens: None }, + item: AttrItem { + unsafety: Unsafe::No, + path: Path::from_ident(ident), + args: AttrArgs::Empty, + tokens: None, + }, tokens: None, } } @@ -2800,6 +2806,7 @@ impl NormalAttr { #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct AttrItem { + pub unsafety: Unsafe, pub path: Path, pub args: AttrArgs, pub tokens: Option, diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 5e3fc7e335775..bee2e8bb4ca43 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -1,6 +1,8 @@ //! Functions dealing with attributes and meta items. -use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute}; +use crate::ast::{ + AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, Unsafe, +}; use crate::ast::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit}; use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NormalAttr}; use crate::ast::{Path, PathSegment, DUMMY_NODE_ID}; @@ -227,7 +229,12 @@ impl AttrItem { } pub fn meta(&self, span: Span) -> Option { - Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span }) + Some(MetaItem { + unsafety: Unsafe::No, + path: self.path.clone(), + kind: self.meta_kind()?, + span, + }) } pub fn meta_kind(&self) -> Option { @@ -357,7 +364,8 @@ impl MetaItem { _ => path.span.hi(), }; let span = path.span.with_hi(hi); - Some(MetaItem { path, kind, span }) + // FIX THIS LATER + Some(MetaItem { unsafety: Unsafe::No, path, kind, span }) } } @@ -547,11 +555,12 @@ pub fn mk_doc_comment( pub fn mk_attr( g: &AttrIdGenerator, style: AttrStyle, + unsafety: Unsafe, path: Path, args: AttrArgs, span: Span, ) -> Attribute { - mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span) + mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span) } pub fn mk_attr_from_item( @@ -569,15 +578,22 @@ pub fn mk_attr_from_item( } } -pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute { +pub fn mk_attr_word( + g: &AttrIdGenerator, + style: AttrStyle, + unsafety: Unsafe, + name: Symbol, + span: Span, +) -> Attribute { let path = Path::from_ident(Ident::new(name, span)); let args = AttrArgs::Empty; - mk_attr(g, style, path, args, span) + mk_attr(g, style, unsafety, path, args, span) } pub fn mk_attr_nested_word( g: &AttrIdGenerator, style: AttrStyle, + unsafety: Unsafe, outer: Symbol, inner: Symbol, span: Span, @@ -593,12 +609,13 @@ pub fn mk_attr_nested_word( delim: Delimiter::Parenthesis, tokens: inner_tokens, }); - mk_attr(g, style, path, attr_args, span) + mk_attr(g, style, unsafety, path, attr_args, span) } pub fn mk_attr_name_value_str( g: &AttrIdGenerator, style: AttrStyle, + unsafety: Unsafe, name: Symbol, val: Symbol, span: Span, @@ -613,7 +630,7 @@ pub fn mk_attr_name_value_str( }); let path = Path::from_ident(Ident::new(name, span)); let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr)); - mk_attr(g, style, path, args, span) + mk_attr(g, style, unsafety, path, args, span) } pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index c4e49d7dbea44..f5edf0e6ecf2d 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -646,8 +646,10 @@ pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { let Attribute { kind, id: _, style: _, span } = attr; match kind { AttrKind::Normal(normal) => { - let NormalAttr { item: AttrItem { path, args, tokens }, tokens: attr_tokens } = - &mut **normal; + let NormalAttr { + item: AttrItem { unsafety: _, path, args, tokens }, + tokens: attr_tokens, + } = &mut **normal; vis.visit_path(path); visit_attr_args(args, vis); visit_lazy_tts(tokens, vis); @@ -677,7 +679,7 @@ pub fn noop_visit_meta_list_item(li: &mut NestedMetaItem, vis: &m } pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { - let MetaItem { path: _, kind, span } = mi; + let MetaItem { unsafety: _, path: _, kind, span } = mi; match kind { MetaItemKind::Word => {} MetaItemKind::List(mis) => visit_thin_vec(mis, |mi| vis.visit_meta_list_item(mi)), @@ -840,7 +842,7 @@ pub fn visit_nonterminal(nt: &mut token::Nonterminal, vis: &mut T token::NtLifetime(ident) => vis.visit_ident(ident), token::NtLiteral(expr) => vis.visit_expr(expr), token::NtMeta(item) => { - let AttrItem { path, args, tokens } = item.deref_mut(); + let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut(); vis.visit_path(path); visit_attr_args(args, vis); visit_lazy_tts(tokens, vis); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 2305cc07795db..30d16e3ec6db1 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1790,6 +1790,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let attr = attr::mk_attr_nested_word( &self.tcx.sess.psess.attr_id_generator, AttrStyle::Outer, + Unsafe::No, sym::allow, sym::unreachable_code, self.lower_span(span), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c5b5acf7f32d8..7e3c607534ad3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -908,6 +908,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let kind = match attr.kind { AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr { item: AttrItem { + unsafety: normal.item.unsafety, path: normal.item.path.clone(), args: self.lower_attr_args(&normal.item.args), tokens: None, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 70a3ccb0f4402..a7b94e59ed9be 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -570,6 +570,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(postfix_match, "postfix match is experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental"); gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental"); + gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental"); if !visitor.features.never_patterns { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 293e65ce87265..a59f4d72c9c4c 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -16,7 +16,7 @@ use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{Comment, CommentStyle}; use rustc_ast::util::parser; -use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind}; +use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind, Unsafe}; use rustc_ast::{attr, BindingMode, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term}; use rustc_ast::{GenericArg, GenericBound, SelfKind}; use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; @@ -245,6 +245,7 @@ pub fn print_crate<'a>( let fake_attr = attr::mk_attr_nested_word( g, ast::AttrStyle::Inner, + Unsafe::No, sym::feature, sym::prelude_import, DUMMY_SP, @@ -255,7 +256,8 @@ pub fn print_crate<'a>( // root, so this is not needed, and actually breaks things. if edition.is_rust_2015() { // `#![no_std]` - let fake_attr = attr::mk_attr_word(g, ast::AttrStyle::Inner, sym::no_std, DUMMY_SP); + let fake_attr = + attr::mk_attr_word(g, ast::AttrStyle::Inner, Unsafe::No, sym::no_std, DUMMY_SP); s.print_attribute(&fake_attr); } } diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index ada82e45712d8..ea7c27735343a 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -16,7 +16,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { ); let start_span = parser.token.span; - let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) { + let AttrItem { unsafety, path, args, tokens: _ } = match parser.parse_attr_item(false) { Ok(ai) => ai, Err(err) => { err.emit(); @@ -32,6 +32,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { krate.attrs.push(mk_attr( &psess.attr_id_generator, AttrStyle::Inner, + unsafety, path, args, start_span.to(end_span), diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index a2015445b42c9..d9bf124c435b7 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -202,6 +202,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { let allow_dead_code = attr::mk_attr_nested_word( &self.sess.psess.attr_id_generator, ast::AttrStyle::Outer, + ast::Unsafe::No, sym::allow, sym::dead_code, self.def_site, diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 83f120525bc5f..3b9b53e11c44a 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -690,7 +690,7 @@ impl<'a> ExtCtxt<'a> { // Builds `#[name]`. pub fn attr_word(&self, name: Symbol, span: Span) -> ast::Attribute { let g = &self.sess.psess.attr_id_generator; - attr::mk_attr_word(g, ast::AttrStyle::Outer, name, span) + attr::mk_attr_word(g, ast::AttrStyle::Outer, ast::Unsafe::No, name, span) } // Builds `#[name = val]`. @@ -698,12 +698,12 @@ impl<'a> ExtCtxt<'a> { // 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 { let g = &self.sess.psess.attr_id_generator; - attr::mk_attr_name_value_str(g, ast::AttrStyle::Outer, name, val, span) + attr::mk_attr_name_value_str(g, ast::AttrStyle::Outer, ast::Unsafe::No, name, val, span) } // Builds `#[outer(inner)]`. pub fn attr_nested_word(&self, outer: Symbol, inner: Symbol, span: Span) -> ast::Attribute { let g = &self.sess.psess.attr_id_generator; - attr::mk_attr_nested_word(g, ast::AttrStyle::Outer, outer, inner, span) + attr::mk_attr_nested_word(g, ast::AttrStyle::Outer, ast::Unsafe::No, outer, inner, span) } } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 6029caa965c0b..0c5e767b42bb8 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -774,7 +774,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> { if let SyntaxExtensionKind::Derive(..) = ext { self.gate_proc_macro_input(&item); } - let meta = ast::MetaItem { kind: MetaItemKind::Word, span, path }; + // FIX THIS LATER + let meta = ast::MetaItem { + unsafety: ast::Unsafe::No, + kind: MetaItemKind::Word, + span, + path, + }; let items = match expander.expand(self.cx, span, &meta, item, is_const) { ExpandResult::Ready(items) => items, ExpandResult::Retry(item) => { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 4f62323231a73..285b9394b5ce9 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -59,6 +59,17 @@ pub enum AttributeType { CrateLevel, } +#[derive(Copy, Clone, PartialEq, Debug)] +#[allow(dead_code)] +pub enum AttributeSafety { + /// Normal attribute that does not need `#[unsafe(...)]` + Normal, + + /// Unsafe attribute that requires safety obligations + /// to be discharged + Unsafe, +} + #[derive(Clone, Copy)] pub enum AttributeGate { /// Is gated by a given feature gate, reason @@ -177,6 +188,18 @@ macro_rules! ungated { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, + safety: AttributeSafety::Normal, + template: $tpl, + gate: Ungated, + duplicates: $duplicates, + } + }; + (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => { + BuiltinAttribute { + name: sym::$attr, + encode_cross_crate: $encode_cross_crate, + type_: $typ, + safety: AttributeSafety::Unsafe, template: $tpl, gate: Ungated, duplicates: $duplicates, @@ -190,6 +213,7 @@ macro_rules! gated { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, + safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), @@ -200,6 +224,29 @@ macro_rules! gated { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, + safety: AttributeSafety::Normal, + template: $tpl, + duplicates: $duplicates, + gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)), + } + }; + (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => { + BuiltinAttribute { + name: sym::$attr, + encode_cross_crate: $encode_cross_crate, + type_: $typ, + safety: AttributeSafety::Unsafe, + template: $tpl, + duplicates: $duplicates, + gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), + } + }; + (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { + BuiltinAttribute { + name: sym::$attr, + encode_cross_crate: $encode_cross_crate, + type_: $typ, + safety: AttributeSafety::Unsafe, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)), @@ -228,6 +275,7 @@ macro_rules! rustc_attr { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, + safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)), @@ -258,6 +306,7 @@ pub struct BuiltinAttribute { /// Otherwise, it can only be used in the local crate. pub encode_cross_crate: EncodeCrossCrate, pub type_: AttributeType, + pub safety: AttributeSafety, pub template: AttributeTemplate, pub duplicates: AttributeDuplicates, pub gate: AttributeGate, @@ -375,9 +424,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No), - ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), - ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), - ungated!(no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), + ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), + ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), + ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No), ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes), @@ -851,6 +900,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. encode_cross_crate: EncodeCrossCrate::Yes, type_: Normal, + safety: AttributeSafety::Normal, template: template!(NameValueStr: "name"), duplicates: ErrorFollowing, gate: Gated( diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 9641d336c3f3c..d35de94864421 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -628,6 +628,7 @@ declare_features! ( /// Allows unnamed fields of struct and union type (incomplete, unnamed_fields, "1.74.0", Some(49804)), /// Allows unsized fn parameters. + (unstable, unsafe_attributes, "CURRENT_RUSTC_VERSION", Some(123757)), (unstable, unsized_fn_params, "1.49.0", Some(48055)), /// Allows unsized rvalues at arguments and parameters. (incomplete, unsized_locals, "1.30.0", Some(48055)), diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index ab5f51eedc307..c46f9dde92a07 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -10,7 +10,7 @@ use rustc_ast as ast; use rustc_ast::attr; use rustc_ast::token::{self, Delimiter}; use rustc_errors::{codes::*, Diag, PResult}; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, symbol::kw, BytePos, Span}; use thin_vec::ThinVec; use tracing::debug; @@ -255,9 +255,23 @@ impl<'a> Parser<'a> { maybe_whole!(self, NtMeta, |attr| attr.into_inner()); let do_parse = |this: &mut Self| { + let is_unsafe = this.eat_keyword(kw::Unsafe); + let unsafety = if is_unsafe { + let unsafe_span = this.prev_token.span; + this.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span); + this.expect(&token::OpenDelim(Delimiter::Parenthesis))?; + + ast::Unsafe::Yes(unsafe_span) + } else { + ast::Unsafe::No + }; + let path = this.parse_path(PathStyle::Mod)?; let args = this.parse_attr_args()?; - Ok(ast::AttrItem { path, args, tokens: None }) + if is_unsafe { + this.expect(&token::CloseDelim(Delimiter::Parenthesis))?; + } + Ok(ast::AttrItem { unsafety, path, args, tokens: None }) }; // Attr items don't have attributes if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) } @@ -377,10 +391,25 @@ impl<'a> Parser<'a> { } let lo = self.token.span; + let is_unsafe = self.eat_keyword(kw::Unsafe); + let unsafety = if is_unsafe { + let unsafe_span = self.prev_token.span; + self.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span); + self.expect(&token::OpenDelim(Delimiter::Parenthesis))?; + + ast::Unsafe::Yes(unsafe_span) + } else { + ast::Unsafe::No + }; + let path = self.parse_path(PathStyle::Mod)?; let kind = self.parse_meta_item_kind()?; + if is_unsafe { + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; + } let span = lo.to(self.prev_token.span); - Ok(ast::MetaItem { path, kind, span }) + + Ok(ast::MetaItem { unsafety, path, kind, span }) } pub(crate) fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index f88edf29dcebe..62efa7c1f7c6f 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -41,6 +41,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> { let item = attr.get_normal_item(); Ok(MetaItem { + unsafety: item.unsafety, span: attr.span, path: item.path.clone(), kind: match &item.args { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 46bae1c1e9894..b7b08e2e81d2a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1934,6 +1934,7 @@ symbols! { unreachable_display, unreachable_macro, unrestricted_attribute_tokens, + unsafe_attributes, unsafe_block_in_unsafe_fn, unsafe_cell, unsafe_cell_raw_get, diff --git a/tests/ui/feature-gates/feature-gate-unsafe-attributes.rs b/tests/ui/feature-gates/feature-gate-unsafe-attributes.rs new file mode 100644 index 0000000000000..9eba415dda0e5 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsafe-attributes.rs @@ -0,0 +1,8 @@ +#[unsafe(no_mangle)] //~ ERROR [E0658] +extern "C" fn foo() { + +} + +fn main() { + foo(); +} diff --git a/tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr b/tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr new file mode 100644 index 0000000000000..dfcea756b02b6 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr @@ -0,0 +1,13 @@ +error[E0658]: `#[unsafe()]` markers for attributes are experimental + --> $DIR/feature-gate-unsafe-attributes.rs:1:3 + | +LL | #[unsafe(no_mangle)] + | ^^^^^^ + | + = note: see issue #123757 for more information + = help: add `#![feature(unsafe_attributes)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`.