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