4
4
use crate :: imports:: ImportResolver ;
5
5
use crate :: Namespace :: * ;
6
6
use 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 } ;
8
8
use crate :: { ModuleKind , ModuleOrUniformRoot , NameBinding , PathResult , Segment , ToNameBinding } ;
9
9
use rustc_ast:: { self as ast, Inline , ItemKind , ModKind , NodeId } ;
10
10
use rustc_ast_lowering:: ResolverAstLowering ;
@@ -14,8 +14,8 @@ use rustc_data_structures::fx::FxHashSet;
14
14
use rustc_data_structures:: ptr_key:: PtrKey ;
15
15
use rustc_data_structures:: sync:: Lrc ;
16
16
use 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 } ;
19
19
use rustc_expand:: compile_declarative_macro;
20
20
use rustc_expand:: expand:: { AstFragment , Invocation , InvocationKind , SupportsMacroExpansion } ;
21
21
use rustc_feature:: is_builtin_attr_name;
@@ -359,58 +359,69 @@ impl<'a> ResolverExpand for Resolver<'a> {
359
359
fn resolve_derives (
360
360
& mut self ,
361
361
expn_id : ExpnId ,
362
- derives : Vec < ast:: Path > ,
363
362
force : bool ,
363
+ derive_paths : & dyn Fn ( ) -> DeriveResolutions ,
364
364
) -> Result < ( ) , Indeterminate > {
365
365
// Block expansion of the container until we resolve all derives in it.
366
366
// This is required for two reasons:
367
367
// - Derive helper attributes are in scope for the item to which the `#[derive]`
368
368
// is applied, so they have to be produced by the container's expansion rather
369
369
// than by individual derives.
370
370
// - 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
+ } ) ;
372
378
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 ( path, opt_ext) in & mut entry. resolutions {
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 . iter ( ) . map ( |name| Ident :: new ( * name, span) ) ,
395
+ ) ;
396
+ }
397
+ entry. has_derive_copy |= ext. builtin_name == Some ( sym:: Copy ) ;
398
+ ext
399
+ }
400
+ Ok ( _) | Err ( Determinacy :: Determined ) => self . dummy_ext ( MacroKind :: Derive ) ,
401
+ Err ( Determinacy :: Undetermined ) => {
402
+ assert ! ( self . derive_data. is_empty( ) ) ;
403
+ self . derive_data = derive_data;
404
+ return Err ( Indeterminate ) ;
405
+ }
406
+ } ,
407
+ ) ;
408
+ }
398
409
}
399
- self . derive_resolutions . insert ( expn_id, exts) ;
400
- self . helper_attrs . insert ( expn_id, helper_attrs) ;
410
+ // If we get to here, then `derive_data` for the given `expn_id` will only be accessed by
411
+ // `take_derive_resolutions` later, so we can steal `helper_attrs` instead of cloning them.
412
+ self . helper_attrs . insert ( expn_id, mem:: take ( & mut entry. helper_attrs ) ) ;
401
413
// Mark this derive as having `Copy` either if it has `Copy` itself or if its parent derive
402
414
// has `Copy`, to support cases like `#[derive(Clone, Copy)] #[derive(Debug)]`.
403
- if has_derive_copy || self . has_derive_copy ( parent_scope. expansion ) {
415
+ if entry . has_derive_copy || self . has_derive_copy ( parent_scope. expansion ) {
404
416
self . containers_deriving_copy . insert ( expn_id) ;
405
417
}
418
+ assert ! ( self . derive_data. is_empty( ) ) ;
419
+ self . derive_data = derive_data;
406
420
Ok ( ( ) )
407
421
}
408
422
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)
423
+ fn take_derive_resolutions ( & mut self , expn_id : ExpnId ) -> Option < DeriveResolutions > {
424
+ self . derive_data . remove ( & expn_id) . map ( |data| data. resolutions )
414
425
}
415
426
416
427
// The function that implements the resolution logic of `#[cfg_accessible(path)]`.
0 commit comments