@@ -10,8 +10,8 @@ use crate::resolve_imports::ImportResolver;
10
10
use rustc:: hir:: def:: { self , DefKind , NonMacroAttrKind } ;
11
11
use rustc:: middle:: stability;
12
12
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 } ;
15
15
use syntax:: edition:: Edition ;
16
16
use syntax:: ext:: base:: { self , Indeterminate , SpecialDerives } ;
17
17
use syntax:: ext:: base:: { MacroKind , SyntaxExtension } ;
@@ -21,6 +21,7 @@ use syntax::ext::tt::macro_rules;
21
21
use syntax:: feature_gate:: { emit_feature_err, is_builtin_attr_name} ;
22
22
use syntax:: feature_gate:: GateIssue ;
23
23
use syntax:: symbol:: { Symbol , kw, sym} ;
24
+ use syntax:: visit:: Visitor ;
24
25
use syntax_pos:: { Span , DUMMY_SP } ;
25
26
26
27
use std:: { mem, ptr} ;
@@ -54,6 +55,21 @@ pub enum LegacyScope<'a> {
54
55
Invocation ( ExpnId ) ,
55
56
}
56
57
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
+
57
73
// Macro namespace is separated into two sub-namespaces, one for bang macros and
58
74
// one for attribute-like macros (attributes, derives).
59
75
// 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> {
164
180
( & mac. path , MacroKind :: Bang , & [ ] [ ..] , false ) ,
165
181
InvocationKind :: Derive { ref path, .. } =>
166
182
( 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 {
178
199
self . add_derives ( invoc_id, SpecialDerives :: COPY ) ;
179
- return Ok ( None ) ;
180
200
}
181
- Err ( Determinacy :: Undetermined ) => result = Err ( Indeterminate ) ,
182
- _ => { }
183
201
}
202
+ Ok ( _) | Err ( Determinacy :: Determined ) => { }
203
+ Err ( Determinacy :: Undetermined ) => return Err ( Indeterminate ) ,
184
204
}
185
205
}
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 ) ;
187
214
}
188
215
} ;
189
216
0 commit comments