Remove AttributeSafety from BUILTIN_ATTRIBUTES

This commit is contained in:
Jonathan Brouwer
2026-04-04 14:49:19 +02:00
parent 9620eae30a
commit 6236ddec5a
14 changed files with 180 additions and 400 deletions
@@ -19,6 +19,7 @@
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
use thin_vec::ThinVec;
use crate::attributes::AttributeSafety;
use crate::context::{AcceptContext, ShouldEmit, Stage};
use crate::parser::{
AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser,
@@ -410,6 +411,7 @@ fn parse_cfg_attr_internal<'a>(
attribute.style,
AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span },
Some(attribute.get_normal_item().unsafety),
AttributeSafety::Normal,
ParsedDescription::Attribute,
pred_span,
lint_node_id,
@@ -12,6 +12,7 @@
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
use crate::attributes::AttributeSafety;
use crate::parser::{AllowExprMetavar, MetaItemOrLitParser};
use crate::{AttributeParser, ParsedDescription, ShouldEmit, errors, parse_cfg_entry};
@@ -105,6 +106,7 @@ pub fn parse_cfg_select(
AttrStyle::Inner,
AttrPath { segments: vec![sym::cfg_select].into_boxed_slice(), span: cfg_span },
None,
AttributeSafety::Normal,
ParsedDescription::Macro,
cfg_span,
lint_node_id,
@@ -1,7 +1,9 @@
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy};
use rustc_session::parse::feature_err;
use rustc_span::edition::Edition::Edition2024;
use super::prelude::*;
use crate::attributes::AttributeSafety;
use crate::session_diagnostics::{
NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector,
ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
@@ -103,6 +105,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
const PATH: &[rustc_span::Symbol] = &[sym::export_name];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Static),
Allow(Target::Fn),
@@ -220,6 +223,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
this.span = Some(cx.attr_span);
}
})];
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -340,6 +344,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for TrackCallerParser {
impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
const PATH: &[Symbol] = &[sym::no_mangle];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Fn),
Allow(Target::Static),
@@ -542,6 +547,7 @@ fn extend(
impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
type Item = (Symbol, Span);
const PATH: &[Symbol] = &[sym::force_target_feature];
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
features: items,
attr_span: span,
@@ -5,11 +5,13 @@
use rustc_session::Session;
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
use rustc_session::parse::feature_err;
use rustc_span::edition::Edition::Edition2024;
use rustc_span::kw;
use rustc_target::spec::{Arch, BinaryFormat};
use super::prelude::*;
use super::util::parse_single_integer;
use crate::attributes::AttributeSafety;
use crate::attributes::cfg::parse_cfg_entry;
use crate::session_diagnostics::{
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
@@ -463,6 +465,7 @@ fn parse_link_import_name_type<S: Stage>(
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
const PATH: &[Symbol] = &[sym::link_section];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Static),
Allow(Target::Fn),
@@ -508,6 +511,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for ExportStableParser {
impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
const PATH: &[Symbol] = &[sym::ffi_const];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
}
@@ -516,6 +520,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
const PATH: &[Symbol] = &[sym::ffi_pure];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
}
@@ -18,6 +18,7 @@
use rustc_feature::{AttributeTemplate, template};
use rustc_hir::attrs::AttributeKind;
use rustc_span::edition::Edition;
use rustc_span::{Span, Symbol};
use thin_vec::ThinVec;
@@ -97,6 +98,7 @@ pub(crate) trait AttributeParser<S: Stage>: Default + 'static {
/// If an attribute has this symbol, the `accept` function will be called on it.
const ATTRIBUTES: AcceptMapping<Self, S>;
const ALLOWED_TARGETS: AllowedTargets;
const SAFETY: AttributeSafety = AttributeSafety::Normal;
/// The parser has gotten a chance to accept the attributes on an item,
/// here it can produce an attribute.
@@ -127,6 +129,7 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
/// Configures what to do when when the same attribute is
/// applied more than once on the same syntax node.
const ON_DUPLICATE: OnDuplicate<S>;
const SAFETY: AttributeSafety = AttributeSafety::Normal;
const ALLOWED_TARGETS: AllowedTargets;
@@ -165,6 +168,7 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
},
)];
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
const SAFETY: AttributeSafety = T::SAFETY;
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
Some(self.1?.0)
@@ -217,6 +221,18 @@ fn exec<P: SingleAttributeParser<S>>(
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum AttributeSafety {
/// Normal attribute that does not need `#[unsafe(...)]`
Normal,
/// Unsafe attribute that requires safety obligations to be discharged.
///
/// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
/// is less than the one stored in `unsafe_since`. This handles attributes that were safe in
/// earlier editions, but become unsafe in later ones.
Unsafe { unsafe_since: Option<Edition> },
}
/// An even simpler version of [`SingleAttributeParser`]:
/// now automatically check that there are no arguments provided to the attribute.
///
@@ -226,6 +242,7 @@ pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static {
const PATH: &[Symbol];
const ON_DUPLICATE: OnDuplicate<S>;
const ALLOWED_TARGETS: AllowedTargets;
const SAFETY: AttributeSafety = AttributeSafety::Normal;
/// Create the [`AttributeKind`] given attribute's [`Span`].
const CREATE: fn(Span) -> AttributeKind;
@@ -242,6 +259,7 @@ fn default() -> Self {
impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for WithoutArgs<T, S> {
const PATH: &[Symbol] = T::PATH;
const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE;
const SAFETY: AttributeSafety = T::SAFETY;
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
const TEMPLATE: AttributeTemplate = template!(Word);
@@ -271,6 +289,7 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
/// For example, individual representations from `#[repr(...)]` attributes into an `AttributeKind::Repr(x)`,
/// where `x` is a vec of these individual reprs.
const CONVERT: ConvertFn<Self::Item>;
const SAFETY: AttributeSafety = AttributeSafety::Normal;
const ALLOWED_TARGETS: AllowedTargets;
@@ -312,6 +331,7 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S
group.items.extend(T::extend(cx, args))
})];
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
const SAFETY: AttributeSafety = T::SAFETY;
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
if let Some(first_span) = self.first_span {
+3 -1
View File
@@ -59,7 +59,7 @@
use crate::attributes::test_attrs::*;
use crate::attributes::traits::*;
use crate::attributes::transparency::*;
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
use crate::attributes::{AttributeParser as _, AttributeSafety, Combine, Single, WithoutArgs};
use crate::parser::{ArgParser, MetaItemOrLitParser, RefPathParser};
use crate::session_diagnostics::{
AttributeParseError, AttributeParseErrorReason, AttributeParseErrorSuggestions,
@@ -76,6 +76,7 @@ pub(super) struct GroupTypeInnerAccept<S: Stage> {
pub(super) template: AttributeTemplate,
pub(super) accept_fn: AcceptFn<S>,
pub(super) allowed_targets: AllowedTargets,
pub(super) safety: AttributeSafety,
pub(super) finalizer: FinalizeFn<S>,
}
@@ -126,6 +127,7 @@ mod late {
accept_fn(s, cx, args)
})
}),
safety: <$names as crate::attributes::AttributeParser<$stage>>::SAFETY,
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
finalizer: Box::new(|cx| {
let state = STATE_OBJECT.take();
+27 -8
View File
@@ -12,6 +12,7 @@
use rustc_session::lint::LintId;
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use crate::attributes::AttributeSafety;
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser};
@@ -135,6 +136,7 @@ pub fn parse_single<T>(
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
template: &AttributeTemplate,
allow_expr_metavar: AllowExprMetavar,
expected_safety: AttributeSafety,
) -> Option<T> {
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
panic!("parse_single called on a doc attr")
@@ -157,6 +159,7 @@ pub fn parse_single<T>(
attr.style,
path,
Some(normal_attr.item.unsafety),
expected_safety,
ParsedDescription::Attribute,
target_span,
target_node_id,
@@ -178,6 +181,7 @@ pub fn parse_single_args<T, I>(
attr_style: AttrStyle,
attr_path: AttrPath,
attr_safety: Option<Safety>,
expected_safety: AttributeSafety,
parsed_description: ParsedDescription,
target_span: Span,
target_node_id: NodeId,
@@ -199,7 +203,13 @@ pub fn parse_single_args<T, I>(
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
};
if let Some(safety) = attr_safety {
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
parser.check_attribute_safety(
&attr_path,
inner_span,
safety,
expected_safety,
&mut emit_lint,
)
}
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
shared: SharedContext {
@@ -314,17 +324,18 @@ pub fn parse_attribute_list(
}
};
self.check_attribute_safety(
&attr_path,
lower_span(n.item.span()),
n.item.unsafety,
&mut emit_lint,
);
let parts =
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
if let Some(accept) = S::parsers().accepters.get(parts.as_slice()) {
self.check_attribute_safety(
&attr_path,
lower_span(n.item.span()),
n.item.unsafety,
accept.safety,
&mut emit_lint,
);
let Some(args) = ArgParser::from_attr_args(
args,
&parts,
@@ -397,6 +408,14 @@ pub fn parse_attribute_list(
span: attr_span,
};
self.check_attribute_safety(
&attr_path,
lower_span(n.item.span()),
n.item.unsafety,
AttributeSafety::Normal,
&mut emit_lint,
);
if !matches!(self.stage.should_emit(), ShouldEmit::Nothing)
&& target == Target::Crate
{
+1
View File
@@ -106,6 +106,7 @@
mod target_checking;
pub mod validate_attr;
pub use attributes::AttributeSafety;
pub use attributes::cfg::{
CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry,
};
+8 -16
View File
@@ -1,12 +1,12 @@
use rustc_ast::Safety;
use rustc_errors::MultiSpan;
use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir::AttrPath;
use rustc_hir::lints::AttributeLintKind;
use rustc_session::lint::LintId;
use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE;
use rustc_span::Span;
use crate::attributes::AttributeSafety;
use crate::context::Stage;
use crate::{AttributeParser, ShouldEmit};
@@ -16,28 +16,23 @@ pub fn check_attribute_safety(
attr_path: &AttrPath,
attr_span: Span,
attr_safety: Safety,
expected_safety: AttributeSafety,
emit_lint: &mut impl FnMut(LintId, MultiSpan, AttributeLintKind),
) {
if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
return;
}
let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0]);
// 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) {
match (expected_safety, attr_safety) {
// - Unsafe builtin attribute
// - User wrote `#[unsafe(..)]`, which is permitted on any edition
(Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => {
(AttributeSafety::Unsafe { .. }, Safety::Unsafe(..)) => {
// OK
}
// - Unsafe builtin attribute
// - User did not write `#[unsafe(..)]`
(Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => {
(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
@@ -96,7 +91,7 @@ pub fn check_attribute_safety(
// - Normal builtin attribute
// - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes
(None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
(AttributeSafety::Normal, Safety::Unsafe(unsafe_span)) => {
self.stage.emit_err(
self.sess,
crate::session_diagnostics::InvalidAttrUnsafe {
@@ -108,14 +103,11 @@ pub fn check_attribute_safety(
// - Normal builtin attribute
// - No explicit `#[unsafe(..)]` written.
(None | Some(AttributeSafety::Normal), Safety::Default) => {
(AttributeSafety::Normal, Safety::Default) => {
// OK
}
(
Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
Safety::Safe(..),
) => {
(_, Safety::Safe(..)) => {
self.sess.dcx().span_delayed_bug(
attr_span,
"`check_attribute_safety` does not expect `Safety::Safe` on attributes",
+3 -1
View File
@@ -6,7 +6,8 @@
use rustc_ast::{AttrStyle, token};
use rustc_attr_parsing::parser::{AllowExprMetavar, MetaItemOrLitParser};
use rustc_attr_parsing::{
self as attr, AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry,
self as attr, AttributeParser, AttributeSafety, CFG_TEMPLATE, ParsedDescription, ShouldEmit,
parse_cfg_entry,
};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_hir::attrs::CfgEntry;
@@ -53,6 +54,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
AttrStyle::Inner,
AttrPath { segments: vec![sym::cfg].into_boxed_slice(), span },
None,
AttributeSafety::Normal,
ParsedDescription::Macro,
span,
cx.current_expansion.lint_node_id,
+3 -2
View File
@@ -12,8 +12,8 @@
};
use rustc_attr_parsing::parser::AllowExprMetavar;
use rustc_attr_parsing::{
self as attr, AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry,
parse_cfg,
self as attr, AttributeParser, AttributeSafety, CFG_TEMPLATE, EvalConfigResult, ShouldEmit,
eval_config_entry, parse_cfg,
};
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_errors::msg;
@@ -398,6 +398,7 @@ pub(crate) fn cfg_true(&self, attr: &Attribute, emit_errors: ShouldEmit) -> Eval
parse_cfg,
&CFG_TEMPLATE,
AllowExprMetavar::Yes,
AttributeSafety::Normal,
) else {
// Cfg attribute was not parsable, give up
return EvalConfigResult::True;
+3 -2
View File
@@ -15,8 +15,8 @@
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::parser::AllowExprMetavar;
use rustc_attr_parsing::{
AttributeParser, CFG_TEMPLATE, Early, EvalConfigResult, ShouldEmit, eval_config_entry,
parse_cfg, validate_attr,
AttributeParser, AttributeSafety, CFG_TEMPLATE, Early, EvalConfigResult, ShouldEmit,
eval_config_entry, parse_cfg, validate_attr,
};
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -2331,6 +2331,7 @@ fn expand_cfg_true(
parse_cfg,
&CFG_TEMPLATE,
AllowExprMetavar::Yes,
AttributeSafety::Normal,
) else {
// Cfg attribute was not parsable, give up
return EvalConfigResult::True;
+96 -369
View File
@@ -5,7 +5,6 @@
use AttributeGate::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::AttrStyle;
use rustc_span::edition::Edition;
use rustc_span::{Symbol, sym};
use crate::Features;
@@ -67,23 +66,6 @@ pub fn find_gated_cfg(pred: impl Fn(Symbol) -> bool) -> Option<&'static GatedCfg
GATED_CFGS.iter().find(|(cfg_sym, ..)| pred(*cfg_sym))
}
// If you change this, please modify `src/doc/unstable-book` as well. You must
// move that documentation into the relevant place in the other docs, and
// remove the chapter on the flag.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum AttributeSafety {
/// Normal attribute that does not need `#[unsafe(...)]`
Normal,
/// Unsafe attribute that requires safety obligations to be discharged.
///
/// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
/// is less than the one stored in `unsafe_since`. This handles attributes that were safe in
/// earlier editions, but become unsafe in later ones.
Unsafe { unsafe_since: Option<Edition> },
}
#[derive(Clone, Debug, Copy)]
pub enum AttributeGate {
/// A gated attribute which requires a feature gate to be enabled.
@@ -205,54 +187,15 @@ macro_rules! template {
}
macro_rules! ungated {
(unsafe($edition:ident) $attr:ident $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
safety: AttributeSafety::Unsafe { unsafe_since: Some(Edition::$edition) },
gate: Ungated,
}
};
(unsafe $attr:ident $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
safety: AttributeSafety::Unsafe { unsafe_since: None },
gate: Ungated,
}
};
($attr:ident $(,)?) => {
BuiltinAttribute { name: sym::$attr, safety: AttributeSafety::Normal, gate: Ungated }
BuiltinAttribute { name: sym::$attr, gate: Ungated }
};
}
macro_rules! gated {
(unsafe $attr:ident, $gate:ident, $message:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
safety: AttributeSafety::Unsafe { unsafe_since: None },
gate: Gated {
feature: sym::$gate,
message: $message,
check: Features::$gate,
notes: &[],
},
}
};
(unsafe $attr:ident, $message:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
safety: AttributeSafety::Unsafe { unsafe_since: None },
gate: Gated {
feature: sym::$attr,
message: $message,
check: Features::$attr,
notes: &[],
},
}
};
($attr:ident, $gate:ident, $message:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
safety: AttributeSafety::Normal,
gate: Gated {
feature: sym::$gate,
message: $message,
@@ -264,7 +207,6 @@ macro_rules! gated {
($attr:ident, $message:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
safety: AttributeSafety::Normal,
gate: Gated {
feature: sym::$attr,
message: $message,
@@ -289,7 +231,6 @@ macro_rules! rustc_attr {
($attr:ident $(, $notes:expr)* $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
safety: AttributeSafety::Normal,
gate: Gated {
feature: sym::rustc_attrs,
message: "use of an internal attribute",
@@ -299,7 +240,7 @@ macro_rules! rustc_attr {
stringify!($attr),
"]` attribute is an internal implementation detail that will never be stable"),
$($notes),*
]
]
},
}
};
@@ -313,7 +254,6 @@ macro_rules! experimental {
pub struct BuiltinAttribute {
pub name: Symbol,
pub safety: AttributeSafety,
pub gate: AttributeGate,
}
@@ -348,10 +288,7 @@ pub struct BuiltinAttribute {
ungated!(forbid),
ungated!(deny),
ungated!(must_use),
gated!(
must_not_suspend,
experimental!(must_not_suspend)
),
gated!(must_not_suspend, experimental!(must_not_suspend)),
ungated!(deprecated),
// Crate properties:
@@ -366,222 +303,103 @@ pub struct BuiltinAttribute {
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
gated!(rustc_align, fn_align, experimental!(rustc_align)),
gated!(rustc_align_static, static_align, experimental!(rustc_align_static)),
ungated!(
unsafe(Edition2024) export_name,
),
ungated!(
unsafe(Edition2024) link_section,
),
ungated!(
unsafe(Edition2024) no_mangle,
),
ungated!(
used,
),
ungated!(
link_ordinal,
),
ungated!(
unsafe naked,
),
ungated!(export_name),
ungated!(link_section),
ungated!(no_mangle),
ungated!(used),
ungated!(link_ordinal),
ungated!(naked),
// See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details.
rustc_attr!(
rustc_pass_indirectly_in_non_rustic_abis,
"types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic ABIs"
),
rustc_attr!(rustc_pass_indirectly_in_non_rustic_abis, "types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic ABIs"),
// Limits:
ungated!(
recursion_limit,
),
ungated!(
type_length_limit,
),
gated!(
move_size_limit,
large_assignments, experimental!(move_size_limit)
),
ungated!(recursion_limit),
ungated!(type_length_limit),
gated!(move_size_limit, large_assignments, experimental!(move_size_limit)),
// Entry point:
ungated!(
no_main,
),
ungated!(no_main),
// Modules, prelude, and resolution:
ungated!(
path,
),
ungated!(
no_std,
),
ungated!(
no_implicit_prelude,
),
ungated!(
non_exhaustive,
),
ungated!(path),
ungated!(no_std),
ungated!(no_implicit_prelude),
ungated!(non_exhaustive),
// Runtime
ungated!(
windows_subsystem,
),
ungated!( // RFC 2070
panic_handler,
),
ungated!(windows_subsystem),
ungated!(panic_handler), // RFC 2070
// Code generation:
ungated!(
inline,
),
ungated!(
cold,
),
ungated!(
no_builtins,
),
ungated!(
target_feature,
),
ungated!(
track_caller,
),
ungated!(
instruction_set,
),
gated!(
unsafe force_target_feature,
effective_target_features, experimental!(force_target_feature)
),
gated!(
sanitize,
sanitize, experimental!(sanitize),
),
gated!(
coverage,
coverage_attribute, experimental!(coverage)
),
ungated!(inline),
ungated!(cold),
ungated!(no_builtins),
ungated!(target_feature),
ungated!(track_caller),
ungated!(instruction_set),
gated!(force_target_feature, effective_target_features, experimental!(force_target_feature)),
gated!(sanitize, sanitize, experimental!(sanitize)),
gated!(coverage, coverage_attribute, experimental!(coverage)),
ungated!(
doc,
),
ungated!(doc),
// Debugging
ungated!(
debugger_visualizer,
),
ungated!(
collapse_debuginfo,
),
ungated!(debugger_visualizer),
ungated!(collapse_debuginfo),
// ==========================================================================
// Unstable attributes:
// ==========================================================================
// Linking:
gated!(
export_stable,
experimental!(export_stable)
),
gated!(export_stable, experimental!(export_stable)),
// Testing:
gated!(
test_runner,
custom_test_frameworks,
"custom test frameworks are an unstable feature",
),
gated!(test_runner, custom_test_frameworks, "custom test frameworks are an unstable feature"),
gated!(
reexport_test_harness_main,
custom_test_frameworks,
"custom test frameworks are an unstable feature",
),
gated!(reexport_test_harness_main, custom_test_frameworks, "custom test frameworks are an unstable feature"),
// RFC #1268
gated!(
marker,
marker_trait_attr, experimental!(marker)
),
gated!(
thread_local,
"`#[thread_local]` is an experimental feature, and does not currently handle destructors",
),
gated!(
no_core,
experimental!(no_core)
),
gated!(marker, marker_trait_attr, experimental!(marker)),
gated!(thread_local, "`#[thread_local]` is an experimental feature, and does not currently handle destructors"),
gated!(no_core, experimental!(no_core)),
// RFC 2412
gated!(
optimize,
optimize_attribute, experimental!(optimize)
),
gated!(optimize, optimize_attribute, experimental!(optimize)),
gated!(
unsafe ffi_pure,
experimental!(ffi_pure)
),
gated!(
unsafe ffi_const,
experimental!(ffi_const)
),
gated!(
register_tool,
experimental!(register_tool),
),
gated!(ffi_pure, experimental!(ffi_pure)),
gated!(ffi_const, experimental!(ffi_const)),
gated!(register_tool, experimental!(register_tool)),
// `#[cfi_encoding = ""]`
gated!(
cfi_encoding,
experimental!(cfi_encoding)
),
gated!(cfi_encoding, experimental!(cfi_encoding)),
// `#[coroutine]` attribute to be applied to closures to make them coroutines instead
gated!(
coroutine,
coroutines, experimental!(coroutine)
),
gated!(coroutine, coroutines, experimental!(coroutine)),
// RFC 3543
// `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]`
gated!(
patchable_function_entry,
experimental!(patchable_function_entry)
),
gated!(patchable_function_entry, experimental!(patchable_function_entry)),
// The `#[loop_match]` and `#[const_continue]` attributes are part of the
// lang experiment for RFC 3720 tracked in:
//
// - https://github.com/rust-lang/rust/issues/132306
gated!(
const_continue,
loop_match, experimental!(const_continue)
),
gated!(
loop_match,
loop_match, experimental!(loop_match)
),
gated!(const_continue, loop_match, experimental!(const_continue)),
gated!(loop_match, loop_match, experimental!(loop_match)),
// The `#[pin_v2]` attribute is part of the `pin_ergonomics` experiment
// that allows structurally pinning, tracked in:
//
// - https://github.com/rust-lang/rust/issues/130494
gated!(
pin_v2,
pin_ergonomics, experimental!(pin_v2),
),
gated!(pin_v2, pin_ergonomics, experimental!(pin_v2)),
// ==========================================================================
// Internal attributes: Stability, deprecation, and unsafe:
// ==========================================================================
ungated!(
feature,
),
ungated!(feature),
// DuplicatesOk since it has its own validation
ungated!(
stable,
),
ungated!(
unstable,
),
ungated!(stable),
ungated!(unstable),
ungated!(unstable_feature_bound),
ungated!(unstable_removed),
ungated!(rustc_const_unstable),
@@ -636,24 +454,12 @@ pub struct BuiltinAttribute {
// Internal attributes: Runtime related:
// ==========================================================================
rustc_attr!(
rustc_allocator,
),
rustc_attr!(
rustc_nounwind,
),
rustc_attr!(
rustc_reallocator,
),
rustc_attr!(
rustc_deallocator,
),
rustc_attr!(
rustc_allocator_zeroed,
),
rustc_attr!(
rustc_allocator_zeroed_variant,
),
rustc_attr!(rustc_allocator),
rustc_attr!(rustc_nounwind),
rustc_attr!(rustc_reallocator),
rustc_attr!(rustc_deallocator),
rustc_attr!(rustc_allocator_zeroed),
rustc_attr!(rustc_allocator_zeroed_variant),
gated!(
default_lib_allocator,
allocator_internals, experimental!(default_lib_allocator),
@@ -720,49 +526,31 @@ pub struct BuiltinAttribute {
rustc_on_unimplemented,
"see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute"
),
rustc_attr!(
rustc_confusables,
),
rustc_attr!(rustc_confusables),
// Enumerates "identity-like" conversion methods to suggest on type mismatch.
rustc_attr!(
rustc_conversion_suggestion,
),
rustc_attr!(rustc_conversion_suggestion),
// Prevents field reads in the marked trait or method to be considered
// during dead code analysis.
rustc_attr!(
rustc_trivial_field_reads,
),
rustc_attr!(rustc_trivial_field_reads),
// Used by the `rustc::potential_query_instability` lint to warn methods which
// might not be stable during incremental compilation.
rustc_attr!(
rustc_lint_query_instability,
),
rustc_attr!(rustc_lint_query_instability),
// Used by the `rustc::untracked_query_information` lint to warn methods which
// might not be stable during incremental compilation.
rustc_attr!(
rustc_lint_untracked_query_information,
),
rustc_attr!(rustc_lint_untracked_query_information),
// Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions`
// types (as well as any others in future).
rustc_attr!(
rustc_lint_opt_ty,
),
rustc_attr!(rustc_lint_opt_ty),
// Used by the `rustc::bad_opt_access` lint on fields
// types (as well as any others in future).
rustc_attr!(
rustc_lint_opt_deny_field_access,
),
rustc_attr!(rustc_lint_opt_deny_field_access),
// ==========================================================================
// Internal attributes, Const related:
// ==========================================================================
rustc_attr!(
rustc_promotable,
),
rustc_attr!(
rustc_legacy_const_generics,
),
rustc_attr!(rustc_promotable),
rustc_attr!(rustc_legacy_const_generics),
// Do not const-check this function's body. It will always get replaced during CTFE via `hook_special_const_fn`.
rustc_attr!(
rustc_do_not_const_check,
@@ -873,7 +661,6 @@ pub struct BuiltinAttribute {
BuiltinAttribute {
name: sym::rustc_diagnostic_item,
safety: AttributeSafety::Normal,
gate: Gated {
feature: sym::rustc_attrs,
message: "use of an internal attribute",
@@ -961,99 +748,39 @@ pub struct BuiltinAttribute {
// ==========================================================================
rustc_attr!(TEST, rustc_effective_visibility),
rustc_attr!(
TEST, rustc_dump_inferred_outlives,
),
rustc_attr!(
TEST, rustc_capture_analysis,
),
rustc_attr!(
TEST, rustc_insignificant_dtor,
),
rustc_attr!(
TEST, rustc_no_implicit_bounds,
),
rustc_attr!(
TEST, rustc_strict_coherence,
),
rustc_attr!(
TEST, rustc_dump_variances,
),
rustc_attr!(
TEST, rustc_dump_variances_of_opaques,
),
rustc_attr!(
TEST, rustc_dump_hidden_type_of_opaques,
),
rustc_attr!(
TEST, rustc_dump_layout,
),
rustc_attr!(
TEST, rustc_abi,
),
rustc_attr!(
TEST, rustc_regions,
),
rustc_attr!(
TEST, rustc_delayed_bug_from_inside_query,
),
rustc_attr!(
TEST, rustc_dump_user_args,
),
rustc_attr!(
TEST, rustc_evaluate_where_clauses,
),
rustc_attr!(
TEST, rustc_if_this_changed,
),
rustc_attr!(
TEST, rustc_then_this_would_need,
),
rustc_attr!(
TEST, rustc_clean,
),
rustc_attr!(
TEST, rustc_partition_reused,
),
rustc_attr!(
TEST, rustc_partition_codegened,
),
rustc_attr!(
TEST, rustc_expected_cgu_reuse,
),
rustc_attr!(
TEST, rustc_dump_symbol_name,
),
rustc_attr!(
TEST, rustc_dump_def_path,
),
rustc_attr!(
TEST, rustc_mir,
),
rustc_attr!(TEST, rustc_dump_inferred_outlives),
rustc_attr!(TEST, rustc_capture_analysis,),
rustc_attr!(TEST, rustc_insignificant_dtor),
rustc_attr!(TEST, rustc_no_implicit_bounds),
rustc_attr!(TEST, rustc_strict_coherence),
rustc_attr!(TEST, rustc_dump_variances),
rustc_attr!(TEST, rustc_dump_variances_of_opaques),
rustc_attr!(TEST, rustc_dump_hidden_type_of_opaques),
rustc_attr!(TEST, rustc_dump_layout),
rustc_attr!(TEST, rustc_abi),
rustc_attr!(TEST, rustc_regions),
rustc_attr!(TEST, rustc_delayed_bug_from_inside_query),
rustc_attr!(TEST, rustc_dump_user_args),
rustc_attr!(TEST, rustc_evaluate_where_clauses),
rustc_attr!(TEST, rustc_if_this_changed),
rustc_attr!(TEST, rustc_then_this_would_need),
rustc_attr!(TEST, rustc_clean),
rustc_attr!(TEST, rustc_partition_reused),
rustc_attr!(TEST, rustc_partition_codegened),
rustc_attr!(TEST, rustc_expected_cgu_reuse),
rustc_attr!(TEST, rustc_dump_symbol_name),
rustc_attr!(TEST, rustc_dump_def_path),
rustc_attr!(TEST, rustc_mir),
gated!(
custom_mir, "the `#[custom_mir]` attribute is just used for the Rust test suite",
),
rustc_attr!(
TEST, rustc_dump_item_bounds,
),
rustc_attr!(
TEST, rustc_dump_predicates,
),
rustc_attr!(
TEST, rustc_dump_def_parents,
),
rustc_attr!(
TEST, rustc_dump_object_lifetime_defaults,
),
rustc_attr!(
TEST, rustc_dump_vtable,
),
rustc_attr!(
TEST, rustc_dummy,
),
rustc_attr!(
TEST, pattern_complexity_limit,
),
rustc_attr!(TEST, rustc_dump_item_bounds),
rustc_attr!(TEST, rustc_dump_predicates),
rustc_attr!(TEST, rustc_dump_def_parents),
rustc_attr!(TEST, rustc_dump_object_lifetime_defaults),
rustc_attr!(TEST, rustc_dump_vtable),
rustc_attr!(TEST, rustc_dummy),
rustc_attr!(TEST, pattern_complexity_limit),
];
pub fn is_builtin_attr_name(name: Symbol) -> bool {
+1 -1
View File
@@ -129,7 +129,7 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
pub use accepted::ACCEPTED_LANG_FEATURES;
pub use builtin_attrs::{
AttrSuggestionStyle, AttributeGate, AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP,
AttrSuggestionStyle, AttributeGate, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP,
BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, find_gated_cfg, is_builtin_attr_name,
};
pub use removed::REMOVED_LANG_FEATURES;