Skip to content

Commit bd94a21

Browse files
committed
Add toggle for parse_meta_item unsafe parsing
This makes it possible for the `unsafe(...)` syntax to only be valid at the top level, and the `NestedMetaItem`s will automatically reject `unsafe(...)`.
1 parent 7e15ea0 commit bd94a21

File tree

10 files changed

+143
-38
lines changed

10 files changed

+143
-38
lines changed

compiler/rustc_builtin_macros/messages.ftl

-3
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,6 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a
110110
builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
111111
.suggestion = remove the value
112112
113-
builtin_macros_derive_unsafe_path = traits in `#[derive(...)]` don't accept `unsafe(...)`
114-
.suggestion = remove the `unsafe(...)`
115-
116113
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
117114
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
118115
.custom = use `std::env::var({$var_expr})` to read the variable at run time

compiler/rustc_builtin_macros/src/cfg.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a,
4242
return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
4343
}
4444

45-
let cfg = p.parse_meta_item()?;
45+
let cfg = p.parse_meta_item(true)?;
4646

4747
let _ = p.eat(&token::Comma);
4848

compiler/rustc_builtin_macros/src/derive.rs

+1-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::cfg_eval::cfg_eval;
22
use crate::errors;
33

44
use rustc_ast as ast;
5-
use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, Safety, StmtKind};
5+
use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
66
use rustc_expand::base::{
77
Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier,
88
};
@@ -62,7 +62,6 @@ impl MultiItemModifier for Expander {
6262
// Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the
6363
// paths.
6464
report_path_args(sess, meta);
65-
report_unsafe_args(sess, meta);
6665
meta.path.clone()
6766
})
6867
.map(|path| DeriveResolution {
@@ -162,13 +161,3 @@ fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
162161
}
163162
}
164163
}
165-
166-
fn report_unsafe_args(sess: &Session, meta: &ast::MetaItem) {
167-
match meta.unsafety {
168-
Safety::Unsafe(span) => {
169-
sess.dcx().emit_err(errors::DeriveUnsafePath { span });
170-
}
171-
Safety::Default => {}
172-
Safety::Safe(_) => unreachable!(),
173-
}
174-
}

compiler/rustc_builtin_macros/src/errors.rs

-7
Original file line numberDiff line numberDiff line change
@@ -295,13 +295,6 @@ pub(crate) struct DerivePathArgsValue {
295295
pub(crate) span: Span,
296296
}
297297

298-
#[derive(Diagnostic)]
299-
#[diag(builtin_macros_derive_unsafe_path)]
300-
pub(crate) struct DeriveUnsafePath {
301-
#[primary_span]
302-
pub(crate) span: Span,
303-
}
304-
305298
#[derive(Diagnostic)]
306299
#[diag(builtin_macros_no_default_variant)]
307300
#[help]

compiler/rustc_interface/src/interface.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg {
6868
}
6969

7070
match new_parser_from_source_str(&psess, filename, s.to_string()) {
71-
Ok(mut parser) => match parser.parse_meta_item() {
71+
Ok(mut parser) => match parser.parse_meta_item(false) {
7272
Ok(meta_item) if parser.token == token::Eof => {
7373
if meta_item.path.segments.len() != 1 {
7474
error!("argument key must be an identifier");
@@ -174,7 +174,7 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
174174
}
175175
};
176176

177-
let meta_item = match parser.parse_meta_item() {
177+
let meta_item = match parser.parse_meta_item(true) {
178178
Ok(meta_item) if parser.token == token::Eof => meta_item,
179179
Ok(..) => expected_error(),
180180
Err(err) => {

compiler/rustc_parse/src/parser/attr.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ impl<'a> Parser<'a> {
337337

338338
/// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
339339
pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
340-
let cfg_predicate = self.parse_meta_item()?;
340+
let cfg_predicate = self.parse_meta_item(false)?;
341341
self.expect(&token::Comma)?;
342342

343343
// Presumably, the majority of the time there will only be one attr.
@@ -373,7 +373,7 @@ impl<'a> Parser<'a> {
373373
/// MetaItem = SimplePath ( '=' UNSUFFIXED_LIT | '(' MetaSeq? ')' )? ;
374374
/// MetaSeq = MetaItemInner (',' MetaItemInner)* ','? ;
375375
/// ```
376-
pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
376+
pub fn parse_meta_item(&mut self, allow_leading_unsafe: bool) -> PResult<'a, ast::MetaItem> {
377377
// We can't use `maybe_whole` here because it would bump in the `None`
378378
// case, which we don't want.
379379
if let token::Interpolated(nt) = &self.token.kind
@@ -389,7 +389,7 @@ impl<'a> Parser<'a> {
389389
}
390390

391391
let lo = self.token.span;
392-
let is_unsafe = self.eat_keyword(kw::Unsafe);
392+
let is_unsafe = if allow_leading_unsafe { self.eat_keyword(kw::Unsafe) } else { false };
393393
let unsafety = if is_unsafe {
394394
let unsafe_span = self.prev_token.span;
395395
self.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span);
@@ -432,7 +432,7 @@ impl<'a> Parser<'a> {
432432
Err(err) => err.cancel(), // we provide a better error below
433433
}
434434

435-
match self.parse_meta_item() {
435+
match self.parse_meta_item(false) {
436436
Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)),
437437
Err(err) => err.cancel(), // we provide a better error below
438438
}

tests/ui/attributes/unsafe/derive-unsafe-attributes.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#![feature(unsafe_attributes)]
22

3-
#[derive(unsafe(Debug))] //~ ERROR: traits in `#[derive(...)]` don't accept `unsafe(...)`
3+
#[derive(unsafe(Debug))]
4+
//~^ ERROR: expected identifier, found keyword `unsafe`
5+
//~| ERROR: traits in `#[derive(...)]` don't accept arguments
6+
//~| ERROR: expected identifier, found keyword `unsafe`
7+
//~| ERROR: expected identifier, found keyword `unsafe`
8+
//~| ERROR: cannot find derive macro `r#unsafe` in this scope
9+
//~| ERROR: cannot find derive macro `r#unsafe` in this scope
410
struct Foo;
511

612
#[unsafe(derive(Debug))] //~ ERROR: is not an unsafe attribute
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,65 @@
1-
error: traits in `#[derive(...)]` don't accept `unsafe(...)`
1+
error: expected identifier, found keyword `unsafe`
22
--> $DIR/derive-unsafe-attributes.rs:3:10
33
|
44
LL | #[derive(unsafe(Debug))]
5-
| ^^^^^^
5+
| ^^^^^^ expected identifier, found keyword
6+
|
7+
help: escape `unsafe` to use it as an identifier
8+
|
9+
LL | #[derive(r#unsafe(Debug))]
10+
| ++
11+
12+
error: traits in `#[derive(...)]` don't accept arguments
13+
--> $DIR/derive-unsafe-attributes.rs:3:16
14+
|
15+
LL | #[derive(unsafe(Debug))]
16+
| ^^^^^^^ help: remove the arguments
617

718
error: `derive` is not an unsafe attribute
8-
--> $DIR/derive-unsafe-attributes.rs:6:3
19+
--> $DIR/derive-unsafe-attributes.rs:12:3
920
|
1021
LL | #[unsafe(derive(Debug))]
1122
| ^^^^^^
1223
|
1324
= note: extraneous unsafe is not allowed in attributes
1425

15-
error: aborting due to 2 previous errors
26+
error: expected identifier, found keyword `unsafe`
27+
--> $DIR/derive-unsafe-attributes.rs:3:10
28+
|
29+
LL | #[derive(unsafe(Debug))]
30+
| ^^^^^^ expected identifier, found keyword
31+
|
32+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
33+
help: escape `unsafe` to use it as an identifier
34+
|
35+
LL | #[derive(r#unsafe(Debug))]
36+
| ++
37+
38+
error: expected identifier, found keyword `unsafe`
39+
--> $DIR/derive-unsafe-attributes.rs:3:10
40+
|
41+
LL | #[derive(unsafe(Debug))]
42+
| ^^^^^^ expected identifier, found keyword
43+
|
44+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
45+
help: escape `unsafe` to use it as an identifier
46+
|
47+
LL | #[derive(r#unsafe(Debug))]
48+
| ++
49+
50+
error: cannot find derive macro `r#unsafe` in this scope
51+
--> $DIR/derive-unsafe-attributes.rs:3:10
52+
|
53+
LL | #[derive(unsafe(Debug))]
54+
| ^^^^^^
55+
56+
error: cannot find derive macro `r#unsafe` in this scope
57+
--> $DIR/derive-unsafe-attributes.rs:3:10
58+
|
59+
LL | #[derive(unsafe(Debug))]
60+
| ^^^^^^
61+
|
62+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
63+
64+
error: aborting due to 7 previous errors
1665

tests/ui/attributes/unsafe/proc-unsafe-attributes.rs

+10
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub fn b() {}
1313

1414
#[proc_macro_derive(unsafe(Foo))]
1515
//~^ ERROR attribute is only usable with crates of the `proc-macro` crate type
16+
//~| ERROR: expected identifier, found keyword `unsafe`
1617
pub fn c() {}
1718

1819
#[unsafe(proc_macro_attribute)]
@@ -24,4 +25,13 @@ pub fn d() {}
2425
//~^ ERROR: is not an unsafe attribute
2526
pub fn e() {}
2627

28+
#[unsafe(allow(unsafe(dead_code)))]
29+
//~^ ERROR: is not an unsafe attribute
30+
//~| ERROR: malformed lint attribute input
31+
//~| ERROR: malformed lint attribute input
32+
//~| ERROR: expected identifier, found keyword `unsafe`
33+
//~| ERROR: malformed lint attribute input
34+
//~| ERROR: malformed lint attribute input
35+
pub fn f() {}
36+
2737
fn main() {}

tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr

+65-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
error[E0452]: malformed lint attribute input
2+
--> $DIR/proc-unsafe-attributes.rs:28:16
3+
|
4+
LL | #[unsafe(allow(unsafe(dead_code)))]
5+
| ^^^^^^^^^^^^^^^^^ bad attribute argument
6+
7+
error[E0452]: malformed lint attribute input
8+
--> $DIR/proc-unsafe-attributes.rs:28:16
9+
|
10+
LL | #[unsafe(allow(unsafe(dead_code)))]
11+
| ^^^^^^^^^^^^^^^^^ bad attribute argument
12+
|
13+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
14+
115
error: `proc_macro` is not an unsafe attribute
216
--> $DIR/proc-unsafe-attributes.rs:3:3
317
|
@@ -14,22 +28,52 @@ LL | #[unsafe(proc_macro_derive(Foo))]
1428
|
1529
= note: extraneous unsafe is not allowed in attributes
1630

31+
error: expected identifier, found keyword `unsafe`
32+
--> $DIR/proc-unsafe-attributes.rs:14:21
33+
|
34+
LL | #[proc_macro_derive(unsafe(Foo))]
35+
| ^^^^^^ expected identifier, found keyword
36+
|
37+
help: escape `unsafe` to use it as an identifier
38+
|
39+
LL | #[proc_macro_derive(r#unsafe(Foo))]
40+
| ++
41+
1742
error: `proc_macro_attribute` is not an unsafe attribute
18-
--> $DIR/proc-unsafe-attributes.rs:18:3
43+
--> $DIR/proc-unsafe-attributes.rs:19:3
1944
|
2045
LL | #[unsafe(proc_macro_attribute)]
2146
| ^^^^^^
2247
|
2348
= note: extraneous unsafe is not allowed in attributes
2449

2550
error: `allow` is not an unsafe attribute
26-
--> $DIR/proc-unsafe-attributes.rs:23:3
51+
--> $DIR/proc-unsafe-attributes.rs:24:3
2752
|
2853
LL | #[unsafe(allow(dead_code))]
2954
| ^^^^^^
3055
|
3156
= note: extraneous unsafe is not allowed in attributes
3257

58+
error: `allow` is not an unsafe attribute
59+
--> $DIR/proc-unsafe-attributes.rs:28:3
60+
|
61+
LL | #[unsafe(allow(unsafe(dead_code)))]
62+
| ^^^^^^
63+
|
64+
= note: extraneous unsafe is not allowed in attributes
65+
66+
error: expected identifier, found keyword `unsafe`
67+
--> $DIR/proc-unsafe-attributes.rs:28:16
68+
|
69+
LL | #[unsafe(allow(unsafe(dead_code)))]
70+
| ^^^^^^ expected identifier, found keyword
71+
|
72+
help: escape `unsafe` to use it as an identifier
73+
|
74+
LL | #[unsafe(allow(r#unsafe(dead_code)))]
75+
| ++
76+
3377
error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type
3478
--> $DIR/proc-unsafe-attributes.rs:3:1
3579
|
@@ -49,10 +93,27 @@ LL | #[proc_macro_derive(unsafe(Foo))]
4993
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5094

5195
error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type
52-
--> $DIR/proc-unsafe-attributes.rs:18:1
96+
--> $DIR/proc-unsafe-attributes.rs:19:1
5397
|
5498
LL | #[unsafe(proc_macro_attribute)]
5599
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
56100

57-
error: aborting due to 8 previous errors
101+
error[E0452]: malformed lint attribute input
102+
--> $DIR/proc-unsafe-attributes.rs:28:16
103+
|
104+
LL | #[unsafe(allow(unsafe(dead_code)))]
105+
| ^^^^^^^^^^^^^^^^^ bad attribute argument
106+
|
107+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
108+
109+
error[E0452]: malformed lint attribute input
110+
--> $DIR/proc-unsafe-attributes.rs:28:16
111+
|
112+
LL | #[unsafe(allow(unsafe(dead_code)))]
113+
| ^^^^^^^^^^^^^^^^^ bad attribute argument
114+
|
115+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
116+
117+
error: aborting due to 15 previous errors
58118

119+
For more information about this error, try `rustc --explain E0452`.

0 commit comments

Comments
 (0)