Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 9ad67e9

Browse files
committed
Auto merge of rust-lang#44055 - zackmdavis:condensed_non-ADT_derive_error, r=jseyfried
only set non-ADT derive error once per attribute, not per trait I found the expansion code very hard to follow, leaving me unsure as to whether this might somehow be done better, but this patch does give us the behavior requested in rust-lang#43927 (up to exact choice of span; here, it's the entire attribute, not just the `derive` token). (Note to GitHub robots: _resolves #43927_.) r? @jseyfried
2 parents 01b1d15 + 083f053 commit 9ad67e9

File tree

7 files changed

+64
-30
lines changed

7 files changed

+64
-30
lines changed

src/libsyntax/ext/base.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,10 @@ impl<'a> ExtCtxt<'a> {
783783
pub fn span_err(&self, sp: Span, msg: &str) {
784784
self.parse_sess.span_diagnostic.span_err(sp, msg);
785785
}
786+
pub fn mut_span_err(&self, sp: Span, msg: &str)
787+
-> DiagnosticBuilder<'a> {
788+
self.parse_sess.span_diagnostic.mut_span_err(sp, msg)
789+
}
786790
pub fn span_warn(&self, sp: Span, msg: &str) {
787791
self.parse_sess.span_diagnostic.span_warn(sp, msg);
788792
}

src/libsyntax/ext/expand.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,32 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
282282
let expansion = self.expand_invoc(invoc, ext);
283283
self.collect_invocations(expansion, &[])
284284
} else if let InvocationKind::Attr { attr: None, traits, item } = invoc.kind {
285+
let derive_allowed = match item {
286+
Annotatable::Item(ref item) => match item.node {
287+
ast::ItemKind::Struct(..) |
288+
ast::ItemKind::Enum(..) |
289+
ast::ItemKind::Union(..) => true,
290+
_ => false,
291+
},
292+
_ => false,
293+
};
294+
if !derive_allowed {
295+
let attr = item.attrs().iter()
296+
.find(|attr| attr.check_name("derive"))
297+
.expect("`derive` attribute should exist");
298+
let span = attr.span;
299+
let mut err = self.cx.mut_span_err(span,
300+
"`derive` may only be applied to \
301+
structs, enums and unions");
302+
if let ast::AttrStyle::Inner = attr.style {
303+
let trait_list = traits.iter()
304+
.map(|t| format!("{}", t)).collect::<Vec<_>>();
305+
let suggestion = format!("#[derive({})]", trait_list.join(", "));
306+
err.span_suggestion(span, "try an outer attribute", suggestion);
307+
}
308+
err.emit();
309+
}
310+
285311
let item = item
286312
.map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs });
287313
let item_with_markers =

src/libsyntax_ext/deriving/generic/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,9 @@ impl<'a> TraitDef<'a> {
428428
}
429429
}
430430
_ => {
431-
cx.span_err(mitem.span,
432-
"`derive` may only be applied to structs, enums and unions");
431+
// Non-ADT derive is an error, but it should have been
432+
// set earlier; see
433+
// libsyntax/ext/expand.rs:MacroExpander::expand()
433434
return;
434435
}
435436
};
@@ -448,8 +449,10 @@ impl<'a> TraitDef<'a> {
448449
push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() })))
449450
}
450451
_ => {
451-
cx.span_err(mitem.span,
452-
"`derive` may only be applied to structs and enums");
452+
// Non-Item derive is an error, but it should have been
453+
// set earlier; see
454+
// libsyntax/ext/expand.rs:MacroExpander::expand()
455+
return;
453456
}
454457
}
455458
}

src/test/compile-fail/feature-gate/issue-43106-gating-of-derive-2.rs

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// `#![derive]` is interpreted (and raises errors) when it occurs at
12-
// contexts other than ADT definitions. This test checks cases where
13-
// the derive-macro does not exist.
11+
// This test checks cases where the derive-macro does not exist.
1412

15-
#![derive(x3300)]
16-
//~^ ERROR cannot find derive macro `x3300` in this scope
17-
18-
#[derive(x3300)]
19-
//~^ ERROR cannot find derive macro `x3300` in this scope
2013
mod derive {
21-
mod inner { #![derive(x3300)] }
22-
//~^ ERROR cannot find derive macro `x3300` in this scope
23-
24-
#[derive(x3300)]
25-
//~^ ERROR cannot find derive macro `x3300` in this scope
26-
fn derive() { }
27-
2814
#[derive(x3300)]
2915
//~^ ERROR cannot find derive macro `x3300` in this scope
3016
union U { f: i32 }
@@ -36,12 +22,4 @@ mod derive {
3622
#[derive(x3300)]
3723
//~^ ERROR cannot find derive macro `x3300` in this scope
3824
struct S;
39-
40-
#[derive(x3300)]
41-
//~^ ERROR cannot find derive macro `x3300` in this scope
42-
type T = S;
43-
44-
#[derive(x3300)]
45-
//~^ ERROR cannot find derive macro `x3300` in this scope
46-
impl S { }
4725
}

src/test/compile-fail/feature-gate/issue-43106-gating-of-derive.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// `#![derive]` is interpreted (and raises errors) when it occurs at
12-
// contexts other than ADT definitions. This test checks cases where
13-
// the derive-macro exists.
11+
// `#![derive]` raises errors when it occurs at contexts other than ADT
12+
// definitions.
1413

1514
#![derive(Debug)]
1615
//~^ ERROR `derive` may only be applied to structs, enums and unions
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(dead_code)]
12+
13+
#![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
14+
struct DerivedOn;
15+
16+
fn main() {}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: `derive` may only be applied to structs, enums and unions
2+
--> $DIR/issue-43927-non-ADT-derive.rs:13:1
3+
|
4+
13 | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug, PartialEq, Eq)]`
6+
7+
error: aborting due to previous error
8+

0 commit comments

Comments
 (0)