@@ -4,7 +4,7 @@ use crate::attr::{self, HasAttrs};
4
4
use crate :: source_map:: respan;
5
5
use crate :: config:: StripUnconfigured ;
6
6
use crate :: ext:: base:: * ;
7
- use crate :: ext:: proc_macro:: collect_derives;
7
+ use crate :: ext:: proc_macro:: { collect_derives, MarkAttrs } ;
8
8
use crate :: ext:: hygiene:: { ExpnId , SyntaxContext , ExpnData , ExpnKind } ;
9
9
use crate :: ext:: tt:: macro_rules:: annotate_err_with_kind;
10
10
use crate :: ext:: placeholders:: { placeholder, PlaceholderExpander } ;
@@ -307,10 +307,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
307
307
308
308
let eager_expansion_root =
309
309
if self . monotonic { invoc. expansion_data . id } else { orig_expansion_data. id } ;
310
- let ext = match self . cx . resolver . resolve_macro_invocation (
310
+ let res = match self . cx . resolver . resolve_macro_invocation (
311
311
& invoc, eager_expansion_root, force
312
312
) {
313
- Ok ( ext ) => ext ,
313
+ Ok ( res ) => res ,
314
314
Err ( Indeterminate ) => {
315
315
undetermined_invocations. push ( invoc) ;
316
316
continue
@@ -322,54 +322,72 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
322
322
self . cx . current_expansion = invoc. expansion_data . clone ( ) ;
323
323
324
324
// FIXME(jseyfried): Refactor out the following logic
325
- let ( expanded_fragment, new_invocations) = if let Some ( ext) = ext {
326
- let fragment = self . expand_invoc ( invoc, & ext. kind ) ;
327
- self . collect_invocations ( fragment, & [ ] )
328
- } else if let InvocationKind :: DeriveContainer { derives : traits, item } = invoc. kind {
329
- if !item. derive_allowed ( ) {
330
- let attr = attr:: find_by_name ( item. attrs ( ) , sym:: derive)
331
- . expect ( "`derive` attribute should exist" ) ;
332
- let span = attr. span ;
333
- let mut err = self . cx . mut_span_err ( span,
334
- "`derive` may only be applied to \
335
- structs, enums and unions") ;
336
- if let ast:: AttrStyle :: Inner = attr. style {
337
- let trait_list = traits. iter ( )
338
- . map ( |t| t. to_string ( ) ) . collect :: < Vec < _ > > ( ) ;
339
- let suggestion = format ! ( "#[derive({})]" , trait_list. join( ", " ) ) ;
340
- err. span_suggestion (
341
- span, "try an outer attribute" , suggestion,
342
- // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT
343
- Applicability :: MaybeIncorrect
344
- ) ;
345
- }
346
- err. emit ( ) ;
325
+ let ( expanded_fragment, new_invocations) = match res {
326
+ InvocationRes :: Single ( ext) => {
327
+ let fragment = self . expand_invoc ( invoc, & ext. kind ) ;
328
+ self . collect_invocations ( fragment, & [ ] )
347
329
}
330
+ InvocationRes :: DeriveContainer ( exts) => {
331
+ let ( derives, item) = match invoc. kind {
332
+ InvocationKind :: DeriveContainer { derives, item } => ( derives, item) ,
333
+ _ => unreachable ! ( ) ,
334
+ } ;
335
+ if !item. derive_allowed ( ) {
336
+ let attr = attr:: find_by_name ( item. attrs ( ) , sym:: derive)
337
+ . expect ( "`derive` attribute should exist" ) ;
338
+ let span = attr. span ;
339
+ let mut err = self . cx . mut_span_err ( span,
340
+ "`derive` may only be applied to structs, enums and unions" ) ;
341
+ if let ast:: AttrStyle :: Inner = attr. style {
342
+ let trait_list = derives. iter ( )
343
+ . map ( |t| t. to_string ( ) ) . collect :: < Vec < _ > > ( ) ;
344
+ let suggestion = format ! ( "#[derive({})]" , trait_list. join( ", " ) ) ;
345
+ err. span_suggestion (
346
+ span, "try an outer attribute" , suggestion,
347
+ // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT
348
+ Applicability :: MaybeIncorrect
349
+ ) ;
350
+ }
351
+ err. emit ( ) ;
352
+ }
348
353
349
- let mut item = self . fully_configure ( item) ;
350
- item. visit_attrs ( |attrs| attrs. retain ( |a| a. path != sym:: derive) ) ;
351
- let derive_placeholders =
352
- all_derive_placeholders. entry ( invoc. expansion_data . id ) . or_default ( ) ;
353
-
354
- derive_placeholders. reserve ( traits. len ( ) ) ;
355
- invocations. reserve ( traits. len ( ) ) ;
356
- for path in traits {
357
- let expn_id = ExpnId :: fresh ( None ) ;
358
- derive_placeholders. push ( NodeId :: placeholder_from_expn_id ( expn_id) ) ;
359
- invocations. push ( Invocation {
360
- kind : InvocationKind :: Derive { path, item : item. clone ( ) } ,
361
- fragment_kind : invoc. fragment_kind ,
362
- expansion_data : ExpansionData {
363
- id : expn_id,
364
- ..invoc. expansion_data . clone ( )
365
- } ,
366
- } ) ;
354
+ let mut item = self . fully_configure ( item) ;
355
+ item. visit_attrs ( |attrs| attrs. retain ( |a| a. path != sym:: derive) ) ;
356
+ let mut helper_attrs = Vec :: new ( ) ;
357
+ let mut has_copy = false ;
358
+ for ext in exts {
359
+ helper_attrs. extend ( & ext. helper_attrs ) ;
360
+ has_copy |= ext. is_derive_copy ;
361
+ }
362
+ // Mark derive helpers inside this item as known and used.
363
+ // FIXME: This is a hack, derive helpers should be integrated with regular name
364
+ // resolution instead. For example, helpers introduced by a derive container
365
+ // can be in scope for all code produced by that container's expansion.
366
+ item. visit_with ( & mut MarkAttrs ( & helper_attrs) ) ;
367
+ if has_copy {
368
+ self . cx . resolver . add_derives ( invoc. expansion_data . id , SpecialDerives :: COPY ) ;
369
+ }
370
+
371
+ let derive_placeholders =
372
+ all_derive_placeholders. entry ( invoc. expansion_data . id ) . or_default ( ) ;
373
+ derive_placeholders. reserve ( derives. len ( ) ) ;
374
+ invocations. reserve ( derives. len ( ) ) ;
375
+ for path in derives {
376
+ let expn_id = ExpnId :: fresh ( None ) ;
377
+ derive_placeholders. push ( NodeId :: placeholder_from_expn_id ( expn_id) ) ;
378
+ invocations. push ( Invocation {
379
+ kind : InvocationKind :: Derive { path, item : item. clone ( ) } ,
380
+ fragment_kind : invoc. fragment_kind ,
381
+ expansion_data : ExpansionData {
382
+ id : expn_id,
383
+ ..invoc. expansion_data . clone ( )
384
+ } ,
385
+ } ) ;
386
+ }
387
+ let fragment = invoc. fragment_kind
388
+ . expect_from_annotatables ( :: std:: iter:: once ( item) ) ;
389
+ self . collect_invocations ( fragment, derive_placeholders)
367
390
}
368
- let fragment = invoc. fragment_kind
369
- . expect_from_annotatables ( :: std:: iter:: once ( item) ) ;
370
- self . collect_invocations ( fragment, derive_placeholders)
371
- } else {
372
- unreachable ! ( )
373
391
} ;
374
392
375
393
if expanded_fragments. len ( ) < depth {
0 commit comments