Skip to content

Commit df9f9ca

Browse files
authored
Rollup merge of #140619 - jieyouxu:validate_attr_cleanups, r=Urgau
Small adjustments to `check_attribute_safety` to make the logic more obvious Follow-up to #140617.
2 parents 82b7923 + eb3a8e5 commit df9f9ca

File tree

5 files changed

+91
-15
lines changed

5 files changed

+91
-15
lines changed

compiler/rustc_expand/src/config.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ impl<'a> StripUnconfigured<'a> {
276276
pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec<Attribute> {
277277
validate_attr::check_attribute_safety(
278278
&self.sess.psess,
279-
AttributeSafety::Normal,
279+
Some(AttributeSafety::Normal),
280280
&cfg_attr,
281281
ast::CRATE_NODE_ID,
282282
);

compiler/rustc_parse/src/validate_attr.rs

+47-14
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,13 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
2222
return;
2323
}
2424

25-
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
26-
let attr_item = attr.get_normal_item();
25+
let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
2726

28-
// All non-builtin attributes are considered safe
29-
let safety = attr_info.map(|x| x.safety).unwrap_or(AttributeSafety::Normal);
30-
check_attribute_safety(psess, safety, attr, id);
27+
let builtin_attr_safety = builtin_attr_info.map(|x| x.safety);
28+
check_attribute_safety(psess, builtin_attr_safety, attr, id);
3129

3230
// Check input tokens for built-in and key-value attributes.
33-
match attr_info {
31+
match builtin_attr_info {
3432
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
3533
Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
3634
match parse_meta(psess, attr) {
@@ -44,6 +42,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
4442
}
4543
}
4644
_ => {
45+
let attr_item = attr.get_normal_item();
4746
if let AttrArgs::Eq { .. } = attr_item.args {
4847
// All key-value attributes are restricted to meta-item syntax.
4948
match parse_meta(psess, attr) {
@@ -157,14 +156,21 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
157156

158157
pub fn check_attribute_safety(
159158
psess: &ParseSess,
160-
safety: AttributeSafety,
159+
builtin_attr_safety: Option<AttributeSafety>,
161160
attr: &Attribute,
162161
id: NodeId,
163162
) {
164163
let attr_item = attr.get_normal_item();
164+
match (builtin_attr_safety, attr_item.unsafety) {
165+
// - Unsafe builtin attribute
166+
// - User wrote `#[unsafe(..)]`, which is permitted on any edition
167+
(Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => {
168+
// OK
169+
}
165170

166-
if let AttributeSafety::Unsafe { unsafe_since } = safety {
167-
if let ast::Safety::Default = attr_item.unsafety {
171+
// - Unsafe builtin attribute
172+
// - User did not write `#[unsafe(..)]`
173+
(Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => {
168174
let path_span = attr_item.path.span;
169175

170176
// If the `attr_item`'s span is not from a macro, then just suggest
@@ -199,11 +205,38 @@ pub fn check_attribute_safety(
199205
);
200206
}
201207
}
202-
} else if let Safety::Unsafe(unsafe_span) = attr_item.unsafety {
203-
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
204-
span: unsafe_span,
205-
name: attr_item.path.clone(),
206-
});
208+
209+
// - Normal builtin attribute, or any non-builtin attribute
210+
// - All non-builtin attributes are currently considered safe; writing `#[unsafe(..)]` is
211+
// not permitted on non-builtin attributes or normal builtin attributes
212+
(Some(AttributeSafety::Normal) | None, Safety::Unsafe(unsafe_span)) => {
213+
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
214+
span: unsafe_span,
215+
name: attr_item.path.clone(),
216+
});
217+
}
218+
219+
// - Normal builtin attribute
220+
// - No explicit `#[unsafe(..)]` written.
221+
(Some(AttributeSafety::Normal), Safety::Default) => {
222+
// OK
223+
}
224+
225+
// - Non-builtin attribute
226+
// - No explicit `#[unsafe(..)]` written.
227+
(None, Safety::Default) => {
228+
// OK
229+
}
230+
231+
(
232+
Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
233+
Safety::Safe(..),
234+
) => {
235+
psess.dcx().span_delayed_bug(
236+
attr_item.span(),
237+
"`check_attribute_safety` does not expect `Safety::Safe` on attributes",
238+
);
239+
}
207240
}
208241
}
209242

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
extern crate proc_macro;
2+
use proc_macro::TokenStream;
3+
4+
#[proc_macro_attribute]
5+
pub fn safe(_attr: TokenStream, item: TokenStream) -> TokenStream {
6+
item
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//! Anti-regression test for `#[safe]` proc-macro attribute.
2+
3+
//@ revisions: unknown_attr proc_macro_attr
4+
//@[proc_macro_attr] proc-macro: safe_attr.rs
5+
//@[proc_macro_attr] check-pass
6+
7+
#![warn(unsafe_attr_outside_unsafe)]
8+
9+
#[cfg(proc_macro_attr)]
10+
extern crate safe_attr;
11+
#[cfg(proc_macro_attr)]
12+
use safe_attr::safe;
13+
14+
#[safe]
15+
//[unknown_attr]~^ ERROR cannot find attribute `safe` in this scope
16+
fn foo() {}
17+
18+
#[safe(no_mangle)]
19+
//[unknown_attr]~^ ERROR cannot find attribute `safe` in this scope
20+
fn bar() {}
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: cannot find attribute `safe` in this scope
2+
--> $DIR/safe-proc-macro-attribute.rs:18:3
3+
|
4+
LL | #[safe(no_mangle)]
5+
| ^^^^
6+
7+
error: cannot find attribute `safe` in this scope
8+
--> $DIR/safe-proc-macro-attribute.rs:14:3
9+
|
10+
LL | #[safe]
11+
| ^^^^
12+
13+
error: aborting due to 2 previous errors
14+

0 commit comments

Comments
 (0)