Skip to content

Commit c7f99c4

Browse files
Remove AttributeSafety from BUILTIN_ATTRIBUTES
1 parent 9058b5f commit c7f99c4

File tree

14 files changed

+271
-273
lines changed

14 files changed

+271
-273
lines changed

compiler/rustc_attr_parsing/src/attributes/cfg.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use rustc_session::parse::{ParseSess, feature_err};
1919
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
2020
use thin_vec::ThinVec;
2121

22+
use crate::attributes::AttributeSafety;
2223
use crate::context::{AcceptContext, ShouldEmit, Stage};
2324
use crate::parser::{
2425
AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser,
@@ -408,6 +409,7 @@ fn parse_cfg_attr_internal<'a>(
408409
attribute.style,
409410
AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span },
410411
Some(attribute.get_normal_item().unsafety),
412+
AttributeSafety::Normal,
411413
ParsedDescription::Attribute,
412414
pred_span,
413415
CRATE_NODE_ID,

compiler/rustc_attr_parsing/src/attributes/cfg_select.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_session::Session;
1212
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
1313
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
1414

15+
use crate::attributes::AttributeSafety;
1516
use crate::parser::{AllowExprMetavar, MetaItemOrLitParser};
1617
use crate::{AttributeParser, ParsedDescription, ShouldEmit, errors, parse_cfg_entry};
1718

@@ -105,6 +106,7 @@ pub fn parse_cfg_select(
105106
AttrStyle::Inner,
106107
AttrPath { segments: vec![sym::cfg_select].into_boxed_slice(), span: cfg_span },
107108
None,
109+
AttributeSafety::Normal,
108110
ParsedDescription::Macro,
109111
cfg_span,
110112
lint_node_id,

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy};
22
use rustc_session::parse::feature_err;
3+
use rustc_span::edition::Edition::Edition2024;
34

45
use super::prelude::*;
6+
use crate::attributes::AttributeSafety;
57
use crate::session_diagnostics::{
68
NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector,
79
ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
@@ -121,6 +123,7 @@ pub(crate) struct ExportNameParser;
121123
impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
122124
const PATH: &[rustc_span::Symbol] = &[sym::export_name];
123125
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
126+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
124127
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
125128
Allow(Target::Static),
126129
Allow(Target::Fn),
@@ -238,6 +241,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
238241
this.span = Some(cx.attr_span);
239242
}
240243
})];
244+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
241245
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
242246
Allow(Target::Fn),
243247
Allow(Target::Method(MethodKind::Inherent)),
@@ -363,6 +367,7 @@ pub(crate) struct NoMangleParser;
363367
impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
364368
const PATH: &[Symbol] = &[sym::no_mangle];
365369
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
370+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
366371
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
367372
Allow(Target::Fn),
368373
Allow(Target::Static),
@@ -565,6 +570,7 @@ pub(crate) struct ForceTargetFeatureParser;
565570
impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
566571
type Item = (Symbol, Span);
567572
const PATH: &[Symbol] = &[sym::force_target_feature];
573+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
568574
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
569575
features: items,
570576
attr_span: span,

compiler/rustc_attr_parsing/src/attributes/link_attrs.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ use rustc_hir::attrs::*;
55
use rustc_session::Session;
66
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
77
use rustc_session::parse::feature_err;
8+
use rustc_span::edition::Edition::Edition2024;
89
use rustc_span::kw;
910
use rustc_target::spec::{Arch, BinaryFormat};
1011

1112
use super::prelude::*;
1213
use super::util::parse_single_integer;
14+
use crate::attributes::AttributeSafety;
1315
use crate::attributes::cfg::parse_cfg_entry;
1416
use crate::session_diagnostics::{
1517
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
@@ -468,6 +470,7 @@ pub(crate) struct LinkSectionParser;
468470
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
469471
const PATH: &[Symbol] = &[sym::link_section];
470472
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
473+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
471474
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
472475
Allow(Target::Static),
473476
Allow(Target::Fn),
@@ -513,6 +516,7 @@ pub(crate) struct FfiConstParser;
513516
impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
514517
const PATH: &[Symbol] = &[sym::ffi_const];
515518
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
519+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
516520
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
517521
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
518522
}
@@ -521,6 +525,7 @@ pub(crate) struct FfiPureParser;
521525
impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
522526
const PATH: &[Symbol] = &[sym::ffi_pure];
523527
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
528+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
524529
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
525530
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
526531
}

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use std::marker::PhantomData;
1818

1919
use rustc_feature::{AttributeTemplate, template};
2020
use rustc_hir::attrs::AttributeKind;
21+
use rustc_span::edition::Edition;
2122
use rustc_span::{Span, Symbol};
2223
use thin_vec::ThinVec;
2324

@@ -98,6 +99,7 @@ pub(crate) trait AttributeParser<S: Stage>: Default + 'static {
9899
/// If an attribute has this symbol, the `accept` function will be called on it.
99100
const ATTRIBUTES: AcceptMapping<Self, S>;
100101
const ALLOWED_TARGETS: AllowedTargets;
102+
const SAFETY: AttributeSafety = AttributeSafety::Normal;
101103

102104
/// The parser has gotten a chance to accept the attributes on an item,
103105
/// here it can produce an attribute.
@@ -128,6 +130,7 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
128130
/// Configures what to do when when the same attribute is
129131
/// applied more than once on the same syntax node.
130132
const ON_DUPLICATE: OnDuplicate<S>;
133+
const SAFETY: AttributeSafety = AttributeSafety::Normal;
131134

132135
const ALLOWED_TARGETS: AllowedTargets;
133136

@@ -166,6 +169,7 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
166169
},
167170
)];
168171
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
172+
const SAFETY: AttributeSafety = T::SAFETY;
169173

170174
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
171175
Some(self.1?.0)
@@ -218,6 +222,18 @@ impl<S: Stage> OnDuplicate<S> {
218222
}
219223
}
220224

225+
#[derive(Copy, Clone, PartialEq, Debug)]
226+
pub enum AttributeSafety {
227+
/// Normal attribute that does not need `#[unsafe(...)]`
228+
Normal,
229+
/// Unsafe attribute that requires safety obligations to be discharged.
230+
///
231+
/// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
232+
/// is less than the one stored in `unsafe_since`. This handles attributes that were safe in
233+
/// earlier editions, but become unsafe in later ones.
234+
Unsafe { unsafe_since: Option<Edition> },
235+
}
236+
221237
/// An even simpler version of [`SingleAttributeParser`]:
222238
/// now automatically check that there are no arguments provided to the attribute.
223239
///
@@ -227,6 +243,7 @@ pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static {
227243
const PATH: &[Symbol];
228244
const ON_DUPLICATE: OnDuplicate<S>;
229245
const ALLOWED_TARGETS: AllowedTargets;
246+
const SAFETY: AttributeSafety = AttributeSafety::Normal;
230247

231248
/// Create the [`AttributeKind`] given attribute's [`Span`].
232249
const CREATE: fn(Span) -> AttributeKind;
@@ -243,6 +260,7 @@ impl<T: NoArgsAttributeParser<S>, S: Stage> Default for WithoutArgs<T, S> {
243260
impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for WithoutArgs<T, S> {
244261
const PATH: &[Symbol] = T::PATH;
245262
const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE;
263+
const SAFETY: AttributeSafety = T::SAFETY;
246264
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
247265
const TEMPLATE: AttributeTemplate = template!(Word);
248266

@@ -272,6 +290,7 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
272290
/// For example, individual representations from `#[repr(...)]` attributes into an `AttributeKind::Repr(x)`,
273291
/// where `x` is a vec of these individual reprs.
274292
const CONVERT: ConvertFn<Self::Item>;
293+
const SAFETY: AttributeSafety = AttributeSafety::Normal;
275294

276295
const ALLOWED_TARGETS: AllowedTargets;
277296

@@ -313,6 +332,7 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S
313332
group.items.extend(T::extend(cx, args))
314333
})];
315334
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
335+
const SAFETY: AttributeSafety = T::SAFETY;
316336

317337
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
318338
if let Some(first_span) = self.first_span {

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ use crate::attributes::stability::*;
5959
use crate::attributes::test_attrs::*;
6060
use crate::attributes::traits::*;
6161
use crate::attributes::transparency::*;
62-
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
62+
use crate::attributes::{AttributeParser as _, AttributeSafety, Combine, Single, WithoutArgs};
6363
use crate::parser::{ArgParser, RefPathParser};
6464
use crate::session_diagnostics::{
6565
AttributeParseError, AttributeParseErrorReason, AttributeParseErrorSuggestions,
@@ -76,6 +76,7 @@ pub(super) struct GroupTypeInnerAccept<S: Stage> {
7676
pub(super) template: AttributeTemplate,
7777
pub(super) accept_fn: AcceptFn<S>,
7878
pub(super) allowed_targets: AllowedTargets,
79+
pub(super) safety: AttributeSafety,
7980
pub(super) finalizer: FinalizeFn<S>,
8081
}
8182

@@ -126,6 +127,7 @@ macro_rules! attribute_parsers {
126127
accept_fn(s, cx, args)
127128
})
128129
}),
130+
safety: <$names as crate::attributes::AttributeParser<$stage>>::SAFETY,
129131
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
130132
finalizer: Box::new(|cx| {
131133
let state = STATE_OBJECT.take();

compiler/rustc_attr_parsing/src/interface.rs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_session::Session;
1313
use rustc_session::lint::{BuiltinLintDiag, LintId};
1414
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
1515

16+
use crate::attributes::AttributeSafety;
1617
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
1718
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
1819
use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser};
@@ -172,6 +173,7 @@ impl<'sess> AttributeParser<'sess, Early> {
172173
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
173174
template: &AttributeTemplate,
174175
allow_expr_metavar: AllowExprMetavar,
176+
expected_safety: AttributeSafety,
175177
) -> Option<T> {
176178
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
177179
panic!("parse_single called on a doc attr")
@@ -194,6 +196,7 @@ impl<'sess> AttributeParser<'sess, Early> {
194196
attr.style,
195197
path,
196198
Some(normal_attr.item.unsafety),
199+
expected_safety,
197200
ParsedDescription::Attribute,
198201
target_span,
199202
target_node_id,
@@ -215,6 +218,7 @@ impl<'sess> AttributeParser<'sess, Early> {
215218
attr_style: AttrStyle,
216219
attr_path: AttrPath,
217220
attr_safety: Option<Safety>,
221+
expected_safety: AttributeSafety,
218222
parsed_description: ParsedDescription,
219223
target_span: Span,
220224
target_node_id: NodeId,
@@ -236,7 +240,13 @@ impl<'sess> AttributeParser<'sess, Early> {
236240
)
237241
};
238242
if let Some(safety) = attr_safety {
239-
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
243+
parser.check_attribute_safety(
244+
&attr_path,
245+
inner_span,
246+
safety,
247+
expected_safety,
248+
&mut emit_lint,
249+
)
240250
}
241251
let attr_id = sess.psess.attr_id_generator.mk_attr_id();
242252
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
@@ -353,17 +363,18 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
353363
}
354364
};
355365

356-
self.check_attribute_safety(
357-
&attr_path,
358-
lower_span(n.item.span()),
359-
n.item.unsafety,
360-
&mut emit_lint,
361-
);
362-
363366
let parts =
364367
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
365368

366369
if let Some(accept) = S::parsers().accepters.get(parts.as_slice()) {
370+
self.check_attribute_safety(
371+
&attr_path,
372+
lower_span(n.item.span()),
373+
n.item.unsafety,
374+
accept.safety,
375+
&mut emit_lint,
376+
);
377+
367378
let Some(args) = ArgParser::from_attr_args(
368379
args,
369380
&parts,
@@ -437,6 +448,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
437448
span: attr_span,
438449
};
439450

451+
self.check_attribute_safety(
452+
&attr_path,
453+
lower_span(n.item.span()),
454+
n.item.unsafety,
455+
AttributeSafety::Normal,
456+
&mut emit_lint,
457+
);
458+
440459
if !matches!(self.stage.should_emit(), ShouldEmit::Nothing)
441460
&& target == Target::Crate
442461
{

compiler/rustc_attr_parsing/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ mod session_diagnostics;
106106
mod target_checking;
107107
pub mod validate_attr;
108108

109+
pub use attributes::AttributeSafety;
109110
pub use attributes::cfg::{
110111
CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry,
111112
};

compiler/rustc_attr_parsing/src/safety.rs

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use rustc_ast::Safety;
2-
use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
32
use rustc_hir::AttrPath;
43
use rustc_hir::lints::AttributeLintKind;
54
use rustc_session::lint::LintId;
65
use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE;
76
use rustc_span::Span;
87

8+
use crate::attributes::AttributeSafety;
99
use crate::context::Stage;
1010
use crate::{AttributeParser, ShouldEmit};
1111

@@ -15,28 +15,23 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
1515
attr_path: &AttrPath,
1616
attr_span: Span,
1717
attr_safety: Safety,
18+
expected_safety: AttributeSafety,
1819
emit_lint: &mut impl FnMut(LintId, Span, AttributeLintKind),
1920
) {
2021
if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
2122
return;
2223
}
2324

24-
let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0]);
25-
26-
// FIXME: We should retrieve this information from the attribute parsers instead of from `BUILTIN_ATTRIBUTE_MAP`
27-
let builtin_attr_info = name.and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
28-
let builtin_attr_safety = builtin_attr_info.map(|x| x.safety);
29-
30-
match (builtin_attr_safety, attr_safety) {
25+
match (expected_safety, attr_safety) {
3126
// - Unsafe builtin attribute
3227
// - User wrote `#[unsafe(..)]`, which is permitted on any edition
33-
(Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => {
28+
(AttributeSafety::Unsafe { .. }, Safety::Unsafe(..)) => {
3429
// OK
3530
}
3631

3732
// - Unsafe builtin attribute
3833
// - User did not write `#[unsafe(..)]`
39-
(Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => {
34+
(AttributeSafety::Unsafe { unsafe_since }, Safety::Default) => {
4035
let path_span = attr_path.span;
4136

4237
// If the `attr_item`'s span is not from a macro, then just suggest
@@ -95,7 +90,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
9590

9691
// - Normal builtin attribute
9792
// - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes
98-
(None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
93+
(AttributeSafety::Normal, Safety::Unsafe(unsafe_span)) => {
9994
self.stage.emit_err(
10095
self.sess,
10196
crate::session_diagnostics::InvalidAttrUnsafe {
@@ -107,14 +102,11 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
107102

108103
// - Normal builtin attribute
109104
// - No explicit `#[unsafe(..)]` written.
110-
(None | Some(AttributeSafety::Normal), Safety::Default) => {
105+
(AttributeSafety::Normal, Safety::Default) => {
111106
// OK
112107
}
113108

114-
(
115-
Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
116-
Safety::Safe(..),
117-
) => {
109+
(_, Safety::Safe(..)) => {
118110
self.sess.dcx().span_delayed_bug(
119111
attr_span,
120112
"`check_attribute_safety` does not expect `Safety::Safe` on attributes",

0 commit comments

Comments
 (0)