Skip to content

Commit 4429d50

Browse files
committed
Deny derive attribute on invalid targets
1 parent ac384ac commit 4429d50

11 files changed

+45
-126
lines changed

compiler/rustc_expand/src/expand.rs

+21-35
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ macro_rules! ast_fragments {
4747
) => {
4848
/// A fragment of AST that can be produced by a single macro expansion.
4949
/// Can also serve as an input and intermediate result for macro expansion operations.
50+
#[derive(Debug)]
5051
pub enum AstFragment {
5152
OptExpr(Option<P<ast::Expr>>),
5253
$($Kind($AstTy),)*
@@ -88,7 +89,7 @@ macro_rules! ast_fragments {
8889
macro _repeating($flat_map_ast_elt) {}
8990
placeholder(AstFragmentKind::$Kind, *id, None).$make_ast()
9091
})),)?)*
91-
_ => panic!("unexpected AST fragment kind")
92+
_ => panic!("unexpected AST fragment kind: {:?}", self)
9293
}
9394
}
9495

@@ -483,12 +484,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
483484
InvocationRes::DeriveContainer(_exts) => {
484485
// FIXME: Consider using the derive resolutions (`_exts`) immediately,
485486
// instead of enqueuing the derives to be resolved again later.
486-
let (derives, item) = match invoc.kind {
487+
let (mut derives, item) = match invoc.kind {
487488
InvocationKind::DeriveContainer { derives, item } => (derives, item),
488489
_ => unreachable!(),
489490
};
490491
if !item.derive_allowed() {
491-
self.error_derive_forbidden_on_non_adt(&derives, &item);
492+
self.error_derive_forbidden_on_non_adt(&mut derives, &item);
492493
}
493494

494495
let mut item = self.fully_configure(item);
@@ -539,7 +540,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
539540
fragment_with_placeholders
540541
}
541542

542-
fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) {
543+
fn error_derive_forbidden_on_non_adt(&self, derives: &mut Vec<Path>, item: &Annotatable) {
543544
let attr = self.cx.sess.find_by_name(item.attrs(), sym::derive);
544545
let span = attr.map_or(item.span(), |attr| attr.span);
545546
let mut err = struct_span_err!(
@@ -560,6 +561,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
560561
);
561562
}
562563
err.emit();
564+
*derives = Vec::new();
563565
}
564566

565567
fn resolve_imports(&mut self) {
@@ -1097,22 +1099,6 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
10971099
(attr, traits, after_derive)
10981100
}
10991101

1100-
/// Alternative to `classify_item()` that ignores `#[derive]` so invocations fallthrough
1101-
/// to the unused-attributes lint (making it an error on statements and expressions
1102-
/// is a breaking change)
1103-
fn classify_nonitem(
1104-
&mut self,
1105-
nonitem: &mut impl HasAttrs,
1106-
) -> (Option<ast::Attribute>, /* after_derive */ bool) {
1107-
let (mut attr, mut after_derive) = (None, false);
1108-
1109-
nonitem.visit_attrs(|mut attrs| {
1110-
attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
1111-
});
1112-
1113-
(attr, after_derive)
1114-
}
1115-
11161102
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
11171103
self.cfg.configure(node)
11181104
}
@@ -1154,19 +1140,20 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
11541140
visit_clobber(expr.deref_mut(), |mut expr| {
11551141
self.cfg.configure_expr_kind(&mut expr.kind);
11561142

1157-
// ignore derives so they remain unused
1158-
let (attr, after_derive) = self.classify_nonitem(&mut expr);
1143+
let (attr, derives, after_derive) = self.classify_item(&mut expr);
11591144

1160-
if let Some(ref attr_value) = attr {
1161-
// Collect the invoc regardless of whether or not attributes are permitted here
1162-
// expansion will eat the attribute so it won't error later.
1163-
self.cfg.maybe_emit_expr_attr_err(attr_value);
1145+
if attr.is_some() || !derives.is_empty() {
1146+
if let Some(attr) = &attr {
1147+
// Collect the invoc regardless of whether or not attributes are permitted here
1148+
// expansion will eat the attribute so it won't error later.
1149+
self.cfg.maybe_emit_expr_attr_err(&attr);
1150+
}
11641151

11651152
// AstFragmentKind::Expr requires the macro to emit an expression.
11661153
return self
11671154
.collect_attr(
11681155
attr,
1169-
vec![],
1156+
derives,
11701157
Annotatable::Expr(P(expr)),
11711158
AstFragmentKind::Expr,
11721159
after_derive,
@@ -1304,16 +1291,17 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
13041291
expr.filter_map(|mut expr| {
13051292
self.cfg.configure_expr_kind(&mut expr.kind);
13061293

1307-
// Ignore derives so they remain unused.
1308-
let (attr, after_derive) = self.classify_nonitem(&mut expr);
1294+
let (attr, derives, after_derive) = self.classify_item(&mut expr);
13091295

1310-
if let Some(ref attr_value) = attr {
1311-
self.cfg.maybe_emit_expr_attr_err(attr_value);
1296+
if attr.is_some() || !derives.is_empty() {
1297+
if let Some(attr) = &attr {
1298+
self.cfg.maybe_emit_expr_attr_err(attr);
1299+
}
13121300

13131301
return self
13141302
.collect_attr(
13151303
attr,
1316-
vec![],
1304+
derives,
13171305
Annotatable::Expr(P(expr)),
13181306
AstFragmentKind::OptExpr,
13191307
after_derive,
@@ -1361,9 +1349,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
13611349
(None, vec![], false)
13621350
} else {
13631351
// ignore derives on non-item statements so it falls through
1364-
// to the unused-attributes lint
1365-
let (attr, after_derive) = self.classify_nonitem(&mut stmt);
1366-
(attr, vec![], after_derive)
1352+
self.classify_item(&mut stmt)
13671353
};
13681354

13691355
if attr.is_some() || !derives.is_empty() {

src/test/ui/issues/issue-36617.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#![derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions
22
//~| ERROR cannot determine resolution for the derive macro `Copy`
3-
//~| ERROR cannot determine resolution for the derive macro `Copy`
43

54
fn main() {}

src/test/ui/issues/issue-36617.stderr

+1-9
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,6 @@ LL | #![derive(Copy)]
1212
|
1313
= note: import resolution is stuck, try simplifying macro imports
1414

15-
error: cannot determine resolution for the derive macro `Copy`
16-
--> $DIR/issue-36617.rs:1:11
17-
|
18-
LL | #![derive(Copy)]
19-
| ^^^^
20-
|
21-
= note: import resolution is stuck, try simplifying macro imports
22-
23-
error: aborting due to 3 previous errors
15+
error: aborting due to 2 previous errors
2416

2517
For more information about this error, try `rustc --explain E0774`.

src/test/ui/issues/issue-49934-errors.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
fn foo<#[derive(Debug)] T>() {
22
//~^ ERROR `derive` may only be applied to structs, enums and unions
3-
//~| ERROR expected an inert attribute, found a derive macro
43
match 0 {
54
#[derive(Debug)]
65
//~^ ERROR `derive` may only be applied to structs, enums and unions
7-
//~| ERROR expected an inert attribute, found a derive macro
86
_ => (),
97
}
108
}

src/test/ui/issues/issue-49934-errors.stderr

+2-14
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,12 @@ error[E0774]: `derive` may only be applied to structs, enums and unions
44
LL | fn foo<#[derive(Debug)] T>() {
55
| ^^^^^^^^^^^^^^^^
66

7-
error: expected an inert attribute, found a derive macro
8-
--> $DIR/issue-49934-errors.rs:1:17
9-
|
10-
LL | fn foo<#[derive(Debug)] T>() {
11-
| ^^^^^
12-
137
error[E0774]: `derive` may only be applied to structs, enums and unions
14-
--> $DIR/issue-49934-errors.rs:5:9
8+
--> $DIR/issue-49934-errors.rs:4:9
159
|
1610
LL | #[derive(Debug)]
1711
| ^^^^^^^^^^^^^^^^
1812

19-
error: expected an inert attribute, found a derive macro
20-
--> $DIR/issue-49934-errors.rs:5:18
21-
|
22-
LL | #[derive(Debug)]
23-
| ^^^^^
24-
25-
error: aborting due to 4 previous errors
13+
error: aborting due to 2 previous errors
2614

2715
For more information about this error, try `rustc --explain E0774`.

src/test/ui/issues/issue-49934.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
// check-pass
2-
31
#![feature(stmt_expr_attributes)]
4-
#![warn(unused_attributes)] //~ NOTE the lint level is defined here
2+
#![warn(unused_attributes)]
53

64
fn main() {
75
// fold_stmt (Item)
@@ -11,25 +9,24 @@ fn main() {
119

1210
// fold_stmt (Mac)
1311
#[derive(Debug)]
14-
//~^ WARN `#[derive]` does nothing on macro invocations
15-
//~| NOTE this may become a hard error in a future release
12+
//~^ ERROR `derive` may only
1613
println!("Hello, world!");
1714

1815
// fold_stmt (Semi)
19-
#[derive(Debug)] //~ WARN unused attribute
16+
#[derive(Debug)] //~ ERROR `derive` may only
2017
"Hello, world!";
2118

2219
// fold_stmt (Local)
23-
#[derive(Debug)] //~ WARN unused attribute
20+
#[derive(Debug)] //~ ERROR `derive` may only
2421
let _ = "Hello, world!";
2522

2623
// visit_expr
2724
let _ = #[derive(Debug)] "Hello, world!";
28-
//~^ WARN unused attribute
25+
//~^ ERROR `derive` may only
2926

3027
let _ = [
3128
// filter_map_expr
32-
#[derive(Debug)] //~ WARN unused attribute
29+
#[derive(Debug)] //~ ERROR `derive` may only
3330
"Hello, world!"
3431
];
3532
}

src/test/ui/issues/issue-49934.stderr

+12-19
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,33 @@
1-
warning: `#[derive]` does nothing on macro invocations
2-
--> $DIR/issue-49934.rs:13:5
1+
error[E0774]: `derive` may only be applied to structs, enums and unions
2+
--> $DIR/issue-49934.rs:11:5
33
|
44
LL | #[derive(Debug)]
55
| ^^^^^^^^^^^^^^^^
6-
|
7-
= note: this may become a hard error in a future release
86

9-
warning: unused attribute
10-
--> $DIR/issue-49934.rs:19:5
7+
error[E0774]: `derive` may only be applied to structs, enums and unions
8+
--> $DIR/issue-49934.rs:16:5
119
|
1210
LL | #[derive(Debug)]
1311
| ^^^^^^^^^^^^^^^^
14-
|
15-
note: the lint level is defined here
16-
--> $DIR/issue-49934.rs:4:9
17-
|
18-
LL | #![warn(unused_attributes)]
19-
| ^^^^^^^^^^^^^^^^^
2012

21-
warning: unused attribute
22-
--> $DIR/issue-49934.rs:23:5
13+
error[E0774]: `derive` may only be applied to structs, enums and unions
14+
--> $DIR/issue-49934.rs:20:5
2315
|
2416
LL | #[derive(Debug)]
2517
| ^^^^^^^^^^^^^^^^
2618

27-
warning: unused attribute
28-
--> $DIR/issue-49934.rs:27:13
19+
error[E0774]: `derive` may only be applied to structs, enums and unions
20+
--> $DIR/issue-49934.rs:24:13
2921
|
3022
LL | let _ = #[derive(Debug)] "Hello, world!";
3123
| ^^^^^^^^^^^^^^^^
3224

33-
warning: unused attribute
34-
--> $DIR/issue-49934.rs:32:9
25+
error[E0774]: `derive` may only be applied to structs, enums and unions
26+
--> $DIR/issue-49934.rs:29:9
3527
|
3628
LL | #[derive(Debug)]
3729
| ^^^^^^^^^^^^^^^^
3830

39-
warning: 5 warnings emitted
31+
error: aborting due to 5 previous errors
4032

33+
For more information about this error, try `rustc --explain E0774`.

src/test/ui/malformed/issue-69341-malformed-derive-inert.rs

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ struct CLI {
44
#[derive(parse())]
55
//~^ ERROR traits in `#[derive(...)]` don't accept arguments
66
//~| ERROR cannot find derive macro `parse` in this scope
7-
//~| ERROR cannot find derive macro `parse` in this scope
87
path: (),
98
//~^ ERROR `derive` may only be applied to structs, enums and unions
109
}

src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr

+2-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | #[derive(parse())]
55
| ^^ help: remove the arguments
66

77
error[E0774]: `derive` may only be applied to structs, enums and unions
8-
--> $DIR/issue-69341-malformed-derive-inert.rs:8:5
8+
--> $DIR/issue-69341-malformed-derive-inert.rs:7:5
99
|
1010
LL | path: (),
1111
| ^^^^^^^^
@@ -16,12 +16,6 @@ error: cannot find derive macro `parse` in this scope
1616
LL | #[derive(parse())]
1717
| ^^^^^
1818

19-
error: cannot find derive macro `parse` in this scope
20-
--> $DIR/issue-69341-malformed-derive-inert.rs:4:14
21-
|
22-
LL | #[derive(parse())]
23-
| ^^^^^
24-
25-
error: aborting due to 4 previous errors
19+
error: aborting due to 3 previous errors
2620

2721
For more information about this error, try `rustc --explain E0774`.

src/test/ui/span/issue-43927-non-ADT-derive.rs

-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
//~| ERROR cannot determine resolution for the derive macro `Debug`
66
//~| ERROR cannot determine resolution for the derive macro `PartialEq`
77
//~| ERROR cannot determine resolution for the derive macro `Eq`
8-
//~| ERROR cannot determine resolution for the derive macro `Debug`
9-
//~| ERROR cannot determine resolution for the derive macro `PartialEq`
10-
//~| ERROR cannot determine resolution for the derive macro `Eq`
118
struct DerivedOn;
129

1310
fn main() {}

src/test/ui/span/issue-43927-non-ADT-derive.stderr

+1-25
Original file line numberDiff line numberDiff line change
@@ -28,30 +28,6 @@ LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
2828
|
2929
= note: import resolution is stuck, try simplifying macro imports
3030

31-
error: cannot determine resolution for the derive macro `Eq`
32-
--> $DIR/issue-43927-non-ADT-derive.rs:3:29
33-
|
34-
LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
35-
| ^^
36-
|
37-
= note: import resolution is stuck, try simplifying macro imports
38-
39-
error: cannot determine resolution for the derive macro `PartialEq`
40-
--> $DIR/issue-43927-non-ADT-derive.rs:3:18
41-
|
42-
LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
43-
| ^^^^^^^^^
44-
|
45-
= note: import resolution is stuck, try simplifying macro imports
46-
47-
error: cannot determine resolution for the derive macro `Debug`
48-
--> $DIR/issue-43927-non-ADT-derive.rs:3:11
49-
|
50-
LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
51-
| ^^^^^
52-
|
53-
= note: import resolution is stuck, try simplifying macro imports
54-
55-
error: aborting due to 7 previous errors
31+
error: aborting due to 4 previous errors
5632

5733
For more information about this error, try `rustc --explain E0774`.

0 commit comments

Comments
 (0)