Skip to content

Commit ede6512

Browse files
committed
Auto merge of #63867 - petrochenkov:dhelpers, r=matthewjasper
resolve: Block expansion of a derive container until all its derives are resolved So, it turns out there's one more reason to block expansion of a `#[derive]` container until all the derives inside it are resolved, beside `Copy` (#63248). The set of derive helper attributes registered by derives in the container also has to be known before the derives themselves are expanded, otherwise it may be too late (see #63468 (comment) and the `#[stable_hasher]`-related test failures in #63468). So, we stop our attempts to unblock the container earlier, as soon as the `Copy` status is known, and just block until all its derives are resolved. After all the derives are resolved we immediately go and process their helper attributes in the item, without delaying it until expansion of the individual derives. Unblocks #63468 r? @matthewjasper (as a reviewer of #63248) cc @c410-f3r
2 parents 555d7a2 + ddf193d commit ede6512

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)