Skip to content

Commit ddf193d

Browse files
committed
resolve: Block expansion of a derive container until all its derives are resolved
Also mark derive helpers as known as a part of the derive container's expansion instead of expansion of the derives themselves which may happen too late.
1 parent 5ade61a commit ddf193d

12 files changed

+127
-113
lines changed

src/librustc_resolve/macros.rs

+44-17
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use crate::resolve_imports::ImportResolver;
1010
use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
1111
use rustc::middle::stability;
1212
use rustc::{ty, lint, span_bug};
13-
use syntax::ast::{self, NodeId, Ident};
14-
use syntax::attr::StabilityLevel;
13+
use syntax::ast::{self, NodeId, Ident, Mac, Attribute};
14+
use syntax::attr::{self, StabilityLevel};
1515
use syntax::edition::Edition;
1616
use syntax::ext::base::{self, Indeterminate, SpecialDerives};
1717
use syntax::ext::base::{MacroKind, SyntaxExtension};
@@ -21,6 +21,7 @@ use syntax::ext::tt::macro_rules;
2121
use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name};
2222
use syntax::feature_gate::GateIssue;
2323
use syntax::symbol::{Symbol, kw, sym};
24+
use syntax::visit::Visitor;
2425
use syntax_pos::{Span, DUMMY_SP};
2526

2627
use std::{mem, ptr};
@@ -54,6 +55,21 @@ pub enum LegacyScope<'a> {
5455
Invocation(ExpnId),
5556
}
5657

58+
struct MarkDeriveHelpers<'a>(&'a [ast::Name]);
59+
60+
impl<'a> Visitor<'a> for MarkDeriveHelpers<'a> {
61+
fn visit_attribute(&mut self, attr: &Attribute) {
62+
if let Some(ident) = attr.ident() {
63+
if self.0.contains(&ident.name) {
64+
attr::mark_used(attr);
65+
attr::mark_known(attr);
66+
}
67+
}
68+
}
69+
70+
fn visit_mac(&mut self, _mac: &Mac) {}
71+
}
72+
5773
// Macro namespace is separated into two sub-namespaces, one for bang macros and
5874
// one for attribute-like macros (attributes, derives).
5975
// We ignore resolutions from one sub-namespace when searching names in scope for another.
@@ -164,26 +180,37 @@ impl<'a> base::Resolver for Resolver<'a> {
164180
(&mac.path, MacroKind::Bang, &[][..], false),
165181
InvocationKind::Derive { ref path, .. } =>
166182
(path, MacroKind::Derive, &[][..], false),
167-
InvocationKind::DeriveContainer { ref derives, .. } => {
168-
// Block expansion of derives in the container until we know whether one of them
169-
// is a built-in `Copy`. Skip the resolution if there's only one derive - either
170-
// it's not a `Copy` and we don't need to do anything, or it's a `Copy` and it
171-
// will automatically knows about itself.
172-
let mut result = Ok(None);
173-
if derives.len() > 1 {
174-
for path in derives {
175-
match self.resolve_macro_path(path, Some(MacroKind::Derive),
176-
&parent_scope, true, force) {
177-
Ok((Some(ref ext), _)) if ext.is_derive_copy => {
183+
InvocationKind::DeriveContainer { ref derives, ref item } => {
184+
// Block expansion of the container until we resolve all derives in it.
185+
// This is required for two reasons:
186+
// - Derive helper attributes are in scope for the item to which the `#[derive]`
187+
// is applied, so they have to be produced by the container's expansion rather
188+
// than by individual derives.
189+
// - Derives in the container need to know whether one of them is a built-in `Copy`.
190+
// FIXME: Try to avoid repeated resolutions for derives here and in expansion.
191+
let mut derive_helpers = Vec::new();
192+
for path in derives {
193+
match self.resolve_macro_path(
194+
path, Some(MacroKind::Derive), &parent_scope, true, force
195+
) {
196+
Ok((Some(ref ext), _)) => {
197+
derive_helpers.extend(&ext.helper_attrs);
198+
if ext.is_derive_copy {
178199
self.add_derives(invoc_id, SpecialDerives::COPY);
179-
return Ok(None);
180200
}
181-
Err(Determinacy::Undetermined) => result = Err(Indeterminate),
182-
_ => {}
183201
}
202+
Ok(_) | Err(Determinacy::Determined) => {}
203+
Err(Determinacy::Undetermined) => return Err(Indeterminate),
184204
}
185205
}
186-
return result;
206+
207+
// Mark derive helpers inside this item as known and used.
208+
// FIXME: This is a hack, derive helpers should be integrated with regular name
209+
// resolution instead. For example, helpers introduced by a derive container
210+
// can be in scope for all code produced by that container's expansion.
211+
item.visit_with(&mut MarkDeriveHelpers(&derive_helpers));
212+
213+
return Ok(None);
187214
}
188215
};
189216

src/libsyntax/ext/base.rs

+12
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::ptr::P;
1111
use crate::symbol::{kw, sym, Ident, Symbol};
1212
use crate::{ThinVec, MACRO_ARGUMENTS};
1313
use crate::tokenstream::{self, TokenStream, TokenTree};
14+
use crate::visit::Visitor;
1415

1516
use errors::{DiagnosticBuilder, DiagnosticId};
1617
use smallvec::{smallvec, SmallVec};
@@ -72,6 +73,17 @@ impl Annotatable {
7273
}
7374
}
7475

76+
pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
77+
match self {
78+
Annotatable::Item(item) => visitor.visit_item(item),
79+
Annotatable::TraitItem(trait_item) => visitor.visit_trait_item(trait_item),
80+
Annotatable::ImplItem(impl_item) => visitor.visit_impl_item(impl_item),
81+
Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item),
82+
Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt),
83+
Annotatable::Expr(expr) => visitor.visit_expr(expr),
84+
}
85+
}
86+
7587
pub fn expect_item(self) -> P<ast::Item> {
7688
match self {
7789
Annotatable::Item(i) => i,

src/libsyntax/ext/proc_macro.rs

+1-21
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
use crate::ast::{self, ItemKind, Attribute, Mac};
2-
use crate::attr::{mark_used, mark_known};
1+
use crate::ast::{self, ItemKind, Attribute};
32
use crate::errors::{Applicability, FatalError};
43
use crate::ext::base::{self, *};
54
use crate::ext::proc_macro_server;
65
use crate::parse::{self, token};
76
use crate::parse::parser::PathStyle;
87
use crate::symbol::sym;
98
use crate::tokenstream::{self, TokenStream};
10-
use crate::visit::Visitor;
119

1210
use rustc_data_structures::sync::Lrc;
1311
use syntax_pos::{Span, DUMMY_SP};
@@ -111,9 +109,6 @@ impl MultiItemModifier for ProcMacroDerive {
111109
}
112110
}
113111

114-
// Mark attributes as known, and used.
115-
MarkAttrs(&self.attrs).visit_item(&item);
116-
117112
let token = token::Interpolated(Lrc::new(token::NtItem(item)));
118113
let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
119114

@@ -164,21 +159,6 @@ impl MultiItemModifier for ProcMacroDerive {
164159
}
165160
}
166161

167-
struct MarkAttrs<'a>(&'a [ast::Name]);
168-
169-
impl<'a> Visitor<'a> for MarkAttrs<'a> {
170-
fn visit_attribute(&mut self, attr: &Attribute) {
171-
if let Some(ident) = attr.ident() {
172-
if self.0.contains(&ident.name) {
173-
mark_used(attr);
174-
mark_known(attr);
175-
}
176-
}
177-
}
178-
179-
fn visit_mac(&mut self, _mac: &Mac) {}
180-
}
181-
182162
pub fn is_proc_macro_attr(attr: &Attribute) -> bool {
183163
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
184164
.iter().any(|kind| attr.check_name(*kind))
+12-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,3 @@
1-
error: cannot find derive macro `Send` in this scope
2-
--> $DIR/deriving-bounds.rs:1:10
3-
|
4-
LL | #[derive(Send)]
5-
| ^^^^
6-
|
7-
note: unsafe traits like `Send` should be implemented explicitly
8-
--> $DIR/deriving-bounds.rs:1:10
9-
|
10-
LL | #[derive(Send)]
11-
| ^^^^
12-
131
error: cannot find derive macro `Sync` in this scope
142
--> $DIR/deriving-bounds.rs:5:10
153
|
@@ -22,5 +10,17 @@ note: unsafe traits like `Sync` should be implemented explicitly
2210
LL | #[derive(Sync)]
2311
| ^^^^
2412

13+
error: cannot find derive macro `Send` in this scope
14+
--> $DIR/deriving-bounds.rs:1:10
15+
|
16+
LL | #[derive(Send)]
17+
| ^^^^
18+
|
19+
note: unsafe traits like `Send` should be implemented explicitly
20+
--> $DIR/deriving-bounds.rs:1:10
21+
|
22+
LL | #[derive(Send)]
23+
| ^^^^
24+
2525
error: aborting due to 2 previous errors
2626

src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: cannot find derive macro `x3300` in this scope
2-
--> $DIR/issue-43106-gating-of-derive-2.rs:4:14
2+
--> $DIR/issue-43106-gating-of-derive-2.rs:12:14
33
|
44
LL | #[derive(x3300)]
55
| ^^^^^
@@ -11,7 +11,7 @@ LL | #[derive(x3300)]
1111
| ^^^^^
1212

1313
error: cannot find derive macro `x3300` in this scope
14-
--> $DIR/issue-43106-gating-of-derive-2.rs:12:14
14+
--> $DIR/issue-43106-gating-of-derive-2.rs:4:14
1515
|
1616
LL | #[derive(x3300)]
1717
| ^^^^^

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

-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
// `#![derive]` raises errors when it occurs at contexts other than ADT
22
// definitions.
33

4-
#![derive(Debug)]
5-
//~^ ERROR `derive` may only be applied to structs, enums and unions
6-
74
#[derive(Debug)]
85
//~^ ERROR `derive` may only be applied to structs, enums and unions
96
mod derive {
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,32 @@
11
error: `derive` may only be applied to structs, enums and unions
22
--> $DIR/issue-43106-gating-of-derive.rs:4:1
33
|
4-
LL | #![derive(Debug)]
5-
| ^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug)]`
6-
7-
error: `derive` may only be applied to structs, enums and unions
8-
--> $DIR/issue-43106-gating-of-derive.rs:7:1
9-
|
104
LL | #[derive(Debug)]
115
| ^^^^^^^^^^^^^^^^
126

137
error: `derive` may only be applied to structs, enums and unions
14-
--> $DIR/issue-43106-gating-of-derive.rs:10:17
8+
--> $DIR/issue-43106-gating-of-derive.rs:7:17
159
|
1610
LL | mod inner { #![derive(Debug)] }
1711
| ^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug)]`
1812

1913
error: `derive` may only be applied to structs, enums and unions
20-
--> $DIR/issue-43106-gating-of-derive.rs:13:5
14+
--> $DIR/issue-43106-gating-of-derive.rs:10:5
2115
|
2216
LL | #[derive(Debug)]
2317
| ^^^^^^^^^^^^^^^^
2418

2519
error: `derive` may only be applied to structs, enums and unions
26-
--> $DIR/issue-43106-gating-of-derive.rs:26:5
20+
--> $DIR/issue-43106-gating-of-derive.rs:23:5
2721
|
2822
LL | #[derive(Debug)]
2923
| ^^^^^^^^^^^^^^^^
3024

3125
error: `derive` may only be applied to structs, enums and unions
32-
--> $DIR/issue-43106-gating-of-derive.rs:30:5
26+
--> $DIR/issue-43106-gating-of-derive.rs:27:5
3327
|
3428
LL | #[derive(Debug)]
3529
| ^^^^^^^^^^^^^^^^
3630

37-
error: aborting due to 6 previous errors
31+
error: aborting due to 5 previous errors
3832

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

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

34
fn main() {}

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,13 @@ error: `derive` may only be applied to structs, enums and unions
44
LL | #![derive(Copy)]
55
| ^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Copy)]`
66

7-
error: aborting due to previous error
7+
error: cannot determine resolution for the derive macro `Copy`
8+
--> $DIR/issue-36617.rs:1:11
9+
|
10+
LL | #![derive(Copy)]
11+
| ^^^^
12+
|
13+
= note: import resolution is stuck, try simplifying macro imports
14+
15+
error: aborting due to 2 previous errors
816

src/test/ui/proc-macro/derive-helper-shadowing.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ struct S {
1919
struct U;
2020

2121
mod inner {
22-
#[empty_helper] //~ ERROR cannot find attribute macro `empty_helper` in this scope
22+
// FIXME No ambiguity, attributes in non-macro positions are not resolved properly
23+
#[empty_helper]
2324
struct V;
2425
}
2526

src/test/ui/proc-macro/derive-helper-shadowing.stderr

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
error: cannot find attribute macro `empty_helper` in this scope
2-
--> $DIR/derive-helper-shadowing.rs:22:15
3-
|
4-
LL | #[empty_helper]
5-
| ^^^^^^^^^^^^
6-
71
error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
82
--> $DIR/derive-helper-shadowing.rs:8:3
93
|
@@ -22,6 +16,6 @@ LL | use test_macros::empty_attr as empty_helper;
2216
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2317
= help: use `crate::empty_helper` to refer to this attribute macro unambiguously
2418

25-
error: aborting due to 2 previous errors
19+
error: aborting due to previous error
2620

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

0 commit comments

Comments
 (0)