@@ -4,7 +4,7 @@ use crate::attr::{self, HasAttrs};
44use crate :: source_map:: respan;
55use crate :: config:: StripUnconfigured ;
66use crate :: ext:: base:: * ;
7- use crate :: ext:: proc_macro:: collect_derives;
7+ use crate :: ext:: proc_macro:: { collect_derives, MarkAttrs } ;
88use crate :: ext:: hygiene:: { ExpnId , SyntaxContext , ExpnData , ExpnKind } ;
99use crate :: ext:: tt:: macro_rules:: annotate_err_with_kind;
1010use crate :: ext:: placeholders:: { placeholder, PlaceholderExpander } ;
@@ -307,10 +307,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
307307
308308 let eager_expansion_root =
309309 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 (
311311 & invoc, eager_expansion_root, force
312312 ) {
313- Ok ( ext ) => ext ,
313+ Ok ( res ) => res ,
314314 Err ( Indeterminate ) => {
315315 undetermined_invocations. push ( invoc) ;
316316 continue
@@ -322,54 +322,72 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
322322 self . cx . current_expansion = invoc. expansion_data . clone ( ) ;
323323
324324 // 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, & [ ] )
347329 }
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+ }
348353
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)
367390 }
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 ! ( )
373391 } ;
374392
375393 if expanded_fragments. len ( ) < depth {
0 commit comments