Skip to content

Commit bf65efa

Browse files
JonathanBrouwerBryntet
authored andcommitted
Remove AttributeSafety from BUILTIN_ATTRIBUTES
1 parent 12f35ad commit bf65efa

14 files changed

Lines changed: 141 additions & 247 deletions

File tree

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,
@@ -410,6 +411,7 @@ fn parse_cfg_attr_internal<'a>(
410411
attribute.style,
411412
AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span },
412413
Some(attribute.get_normal_item().unsafety),
414+
AttributeSafety::Normal,
413415
ParsedDescription::Attribute,
414416
pred_span,
415417
lint_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,
@@ -103,6 +105,7 @@ pub(crate) struct ExportNameParser;
103105
impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
104106
const PATH: &[rustc_span::Symbol] = &[sym::export_name];
105107
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
108+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
106109
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
107110
Allow(Target::Static),
108111
Allow(Target::Fn),
@@ -220,6 +223,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
220223
this.span = Some(cx.attr_span);
221224
}
222225
})];
226+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
223227
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
224228
Allow(Target::Fn),
225229
Allow(Target::Method(MethodKind::Inherent)),
@@ -340,6 +344,7 @@ pub(crate) struct NoMangleParser;
340344
impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
341345
const PATH: &[Symbol] = &[sym::no_mangle];
342346
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
347+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
343348
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
344349
Allow(Target::Fn),
345350
Allow(Target::Static),
@@ -542,6 +547,7 @@ pub(crate) struct ForceTargetFeatureParser;
542547
impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
543548
type Item = (Symbol, Span);
544549
const PATH: &[Symbol] = &[sym::force_target_feature];
550+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
545551
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
546552
features: items,
547553
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,
@@ -463,6 +465,7 @@ pub(crate) struct LinkSectionParser;
463465
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
464466
const PATH: &[Symbol] = &[sym::link_section];
465467
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
468+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
466469
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
467470
Allow(Target::Static),
468471
Allow(Target::Fn),
@@ -508,6 +511,7 @@ pub(crate) struct FfiConstParser;
508511
impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
509512
const PATH: &[Symbol] = &[sym::ffi_const];
510513
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
514+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
511515
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
512516
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
513517
}
@@ -516,6 +520,7 @@ pub(crate) struct FfiPureParser;
516520
impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
517521
const PATH: &[Symbol] = &[sym::ffi_pure];
518522
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
523+
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
519524
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
520525
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
521526
}

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

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

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

131134
const ALLOWED_TARGETS: AllowedTargets;
132135

@@ -165,6 +168,7 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
165168
},
166169
)];
167170
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
171+
const SAFETY: AttributeSafety = T::SAFETY;
168172

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

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

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

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

275294
const ALLOWED_TARGETS: AllowedTargets;
276295

@@ -312,6 +331,7 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S
312331
group.items.extend(T::extend(cx, args))
313332
})];
314333
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
334+
const SAFETY: AttributeSafety = T::SAFETY;
315335

316336
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
317337
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, MetaItemOrLitParser, 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
@@ -12,6 +12,7 @@ use rustc_session::Session;
1212
use rustc_session::lint::LintId;
1313
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
1414

15+
use crate::attributes::AttributeSafety;
1516
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
1617
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
1718
use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser};
@@ -135,6 +136,7 @@ impl<'sess> AttributeParser<'sess, Early> {
135136
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
136137
template: &AttributeTemplate,
137138
allow_expr_metavar: AllowExprMetavar,
139+
expected_safety: AttributeSafety,
138140
) -> Option<T> {
139141
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
140142
panic!("parse_single called on a doc attr")
@@ -157,6 +159,7 @@ impl<'sess> AttributeParser<'sess, Early> {
157159
attr.style,
158160
path,
159161
Some(normal_attr.item.unsafety),
162+
expected_safety,
160163
ParsedDescription::Attribute,
161164
target_span,
162165
target_node_id,
@@ -178,6 +181,7 @@ impl<'sess> AttributeParser<'sess, Early> {
178181
attr_style: AttrStyle,
179182
attr_path: AttrPath,
180183
attr_safety: Option<Safety>,
184+
expected_safety: AttributeSafety,
181185
parsed_description: ParsedDescription,
182186
target_span: Span,
183187
target_node_id: NodeId,
@@ -199,7 +203,13 @@ impl<'sess> AttributeParser<'sess, Early> {
199203
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
200204
};
201205
if let Some(safety) = attr_safety {
202-
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
206+
parser.check_attribute_safety(
207+
&attr_path,
208+
inner_span,
209+
safety,
210+
expected_safety,
211+
&mut emit_lint,
212+
)
203213
}
204214
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
205215
shared: SharedContext {
@@ -314,17 +324,18 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
314324
}
315325
};
316326

317-
self.check_attribute_safety(
318-
&attr_path,
319-
lower_span(n.item.span()),
320-
n.item.unsafety,
321-
&mut emit_lint,
322-
);
323-
324327
let parts =
325328
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
326329

327330
if let Some(accept) = S::parsers().accepters.get(parts.as_slice()) {
331+
self.check_attribute_safety(
332+
&attr_path,
333+
lower_span(n.item.span()),
334+
n.item.unsafety,
335+
accept.safety,
336+
&mut emit_lint,
337+
);
338+
328339
let Some(args) = ArgParser::from_attr_args(
329340
args,
330341
&parts,
@@ -397,6 +408,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
397408
span: attr_span,
398409
};
399410

411+
self.check_attribute_safety(
412+
&attr_path,
413+
lower_span(n.item.span()),
414+
n.item.unsafety,
415+
AttributeSafety::Normal,
416+
&mut emit_lint,
417+
);
418+
400419
if !matches!(self.stage.should_emit(), ShouldEmit::Nothing)
401420
&& target == Target::Crate
402421
{

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,12 +1,12 @@
11
use rustc_ast::Safety;
22
use rustc_errors::MultiSpan;
3-
use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
43
use rustc_hir::AttrPath;
54
use rustc_hir::lints::AttributeLintKind;
65
use rustc_session::lint::LintId;
76
use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE;
87
use rustc_span::Span;
98

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

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

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

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

4338
// If the `attr_item`'s span is not from a macro, then just suggest
@@ -96,7 +91,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
9691

9792
// - Normal builtin attribute
9893
// - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes
99-
(None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
94+
(AttributeSafety::Normal, Safety::Unsafe(unsafe_span)) => {
10095
self.stage.emit_err(
10196
self.sess,
10297
crate::session_diagnostics::InvalidAttrUnsafe {
@@ -108,14 +103,11 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
108103

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

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

0 commit comments

Comments
 (0)