44use crate :: imports:: ImportResolver ;
55use crate :: Namespace :: * ;
66use crate :: { AmbiguityError , AmbiguityErrorMisc , AmbiguityKind , BuiltinMacroState , Determinacy } ;
7- use crate :: { CrateLint , ParentScope , ResolutionError , Resolver , Scope , ScopeSet , Weak } ;
7+ use crate :: { CrateLint , DeriveData , ParentScope , ResolutionError , Resolver , Scope , ScopeSet , Weak } ;
88use crate :: { ModuleKind , ModuleOrUniformRoot , NameBinding , PathResult , Segment , ToNameBinding } ;
99use rustc_ast:: { self as ast, Inline , ItemKind , ModKind , NodeId } ;
1010use rustc_ast_lowering:: ResolverAstLowering ;
@@ -14,8 +14,8 @@ use rustc_data_structures::fx::FxHashSet;
1414use rustc_data_structures:: ptr_key:: PtrKey ;
1515use rustc_data_structures:: sync:: Lrc ;
1616use rustc_errors:: struct_span_err;
17- use rustc_expand:: base:: Annotatable ;
18- use rustc_expand:: base:: { Indeterminate , ResolverExpand , SyntaxExtension , SyntaxExtensionKind } ;
17+ use rustc_expand:: base:: { Annotatable , DeriveResolutions , Indeterminate , ResolverExpand } ;
18+ use rustc_expand:: base:: { SyntaxExtension , SyntaxExtensionKind } ;
1919use rustc_expand:: compile_declarative_macro;
2020use rustc_expand:: expand:: { AstFragment , Invocation , InvocationKind , SupportsMacroExpansion } ;
2121use rustc_feature:: is_builtin_attr_name;
@@ -359,58 +359,72 @@ impl<'a> ResolverExpand for Resolver<'a> {
359359 fn resolve_derives (
360360 & mut self ,
361361 expn_id : ExpnId ,
362- derives : Vec < ast:: Path > ,
363362 force : bool ,
363+ derive_paths : & dyn Fn ( ) -> DeriveResolutions ,
364364 ) -> Result < ( ) , Indeterminate > {
365365 // Block expansion of the container until we resolve all derives in it.
366366 // This is required for two reasons:
367367 // - Derive helper attributes are in scope for the item to which the `#[derive]`
368368 // is applied, so they have to be produced by the container's expansion rather
369369 // than by individual derives.
370370 // - Derives in the container need to know whether one of them is a built-in `Copy`.
371- // FIXME: Try to cache intermediate results to avoid resolving same derives multiple times.
371+ // Temporarily take the data to avoid borrow checker conflicts.
372+ let mut derive_data = mem:: take ( & mut self . derive_data ) ;
373+ let entry = derive_data. entry ( expn_id) . or_insert_with ( || DeriveData {
374+ resolutions : derive_paths ( ) ,
375+ helper_attrs : Vec :: new ( ) ,
376+ has_derive_copy : false ,
377+ } ) ;
372378 let parent_scope = self . invocation_parent_scopes [ & expn_id] ;
373- let mut exts = Vec :: new ( ) ;
374- let mut helper_attrs = Vec :: new ( ) ;
375- let mut has_derive_copy = false ;
376- for path in derives {
377- exts. push ( (
378- match self . resolve_macro_path (
379- & path,
380- Some ( MacroKind :: Derive ) ,
381- & parent_scope,
382- true ,
383- force,
384- ) {
385- Ok ( ( Some ( ext) , _) ) => {
386- let span =
387- path. segments . last ( ) . unwrap ( ) . ident . span . normalize_to_macros_2_0 ( ) ;
388- helper_attrs
389- . extend ( ext. helper_attrs . iter ( ) . map ( |name| Ident :: new ( * name, span) ) ) ;
390- has_derive_copy |= ext. builtin_name == Some ( sym:: Copy ) ;
391- ext
392- }
393- Ok ( _) | Err ( Determinacy :: Determined ) => self . dummy_ext ( MacroKind :: Derive ) ,
394- Err ( Determinacy :: Undetermined ) => return Err ( Indeterminate ) ,
395- } ,
396- path,
397- ) )
379+ for ( i, ( path, opt_ext) ) in entry. resolutions . iter_mut ( ) . enumerate ( ) {
380+ if opt_ext. is_none ( ) {
381+ * opt_ext = Some (
382+ match self . resolve_macro_path (
383+ & path,
384+ Some ( MacroKind :: Derive ) ,
385+ & parent_scope,
386+ true ,
387+ force,
388+ ) {
389+ Ok ( ( Some ( ext) , _) ) => {
390+ if !ext. helper_attrs . is_empty ( ) {
391+ let last_seg = path. segments . last ( ) . unwrap ( ) ;
392+ let span = last_seg. ident . span . normalize_to_macros_2_0 ( ) ;
393+ entry. helper_attrs . extend (
394+ ext. helper_attrs
395+ . iter ( )
396+ . map ( |name| ( i, Ident :: new ( * name, span) ) ) ,
397+ ) ;
398+ }
399+ entry. has_derive_copy |= ext. builtin_name == Some ( sym:: Copy ) ;
400+ ext
401+ }
402+ Ok ( _) | Err ( Determinacy :: Determined ) => self . dummy_ext ( MacroKind :: Derive ) ,
403+ Err ( Determinacy :: Undetermined ) => {
404+ assert ! ( self . derive_data. is_empty( ) ) ;
405+ self . derive_data = derive_data;
406+ return Err ( Indeterminate ) ;
407+ }
408+ } ,
409+ ) ;
410+ }
398411 }
399- self . derive_resolutions . insert ( expn_id, exts) ;
400- self . helper_attrs . insert ( expn_id, helper_attrs) ;
412+ // Sort helpers in a stable way independent from the derive resolution order.
413+ entry. helper_attrs . sort_by_key ( |( i, _) | * i) ;
414+ self . helper_attrs
415+ . insert ( expn_id, entry. helper_attrs . iter ( ) . map ( |( _, ident) | * ident) . collect ( ) ) ;
401416 // Mark this derive as having `Copy` either if it has `Copy` itself or if its parent derive
402417 // has `Copy`, to support cases like `#[derive(Clone, Copy)] #[derive(Debug)]`.
403- if has_derive_copy || self . has_derive_copy ( parent_scope. expansion ) {
418+ if entry . has_derive_copy || self . has_derive_copy ( parent_scope. expansion ) {
404419 self . containers_deriving_copy . insert ( expn_id) ;
405420 }
421+ assert ! ( self . derive_data. is_empty( ) ) ;
422+ self . derive_data = derive_data;
406423 Ok ( ( ) )
407424 }
408425
409- fn take_derive_resolutions (
410- & mut self ,
411- expn_id : ExpnId ,
412- ) -> Option < Vec < ( Lrc < SyntaxExtension > , ast:: Path ) > > {
413- self . derive_resolutions . remove ( & expn_id)
426+ fn take_derive_resolutions ( & mut self , expn_id : ExpnId ) -> Option < DeriveResolutions > {
427+ self . derive_data . remove ( & expn_id) . map ( |data| data. resolutions )
414428 }
415429
416430 // The function that implements the resolution logic of `#[cfg_accessible(path)]`.
0 commit comments