Skip to content

Commit 9ad67e9

Browse files
committed
Auto merge of #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 #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

+4
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

+26
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

+7-4
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

+1-23
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

+2-3
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
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() {}
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)