1
Fork 0

derive: Do not configure or clone items unless necessary

This commit is contained in:
Vadim Petrochenkov 2021-07-17 17:28:43 +03:00
parent c993984e4d
commit 92804cd490
2 changed files with 47 additions and 22 deletions

View file

@ -2,6 +2,7 @@ use crate::util::check_builtin_macro_attribute;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::mut_visit::MutVisitor; use rustc_ast::mut_visit::MutVisitor;
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::CanSynthesizeMissingTokens; use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
use rustc_ast::visit::Visitor; use rustc_ast::visit::Visitor;
use rustc_ast::{mut_visit, visit}; use rustc_ast::{mut_visit, visit};
@ -9,10 +10,10 @@ use rustc_ast::{AstLike, Attribute};
use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_expand::config::StripUnconfigured; use rustc_expand::config::StripUnconfigured;
use rustc_expand::configure; use rustc_expand::configure;
use rustc_feature::Features;
use rustc_parse::parser::ForceCollect; use rustc_parse::parser::ForceCollect;
use rustc_session::utils::FlattenNonterminals; use rustc_session::utils::FlattenNonterminals;
use rustc_session::Session;
use rustc_ast::ptr::P;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::Span; use rustc_span::Span;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -24,21 +25,19 @@ crate fn expand(
annotatable: Annotatable, annotatable: Annotatable,
) -> Vec<Annotatable> { ) -> Vec<Annotatable> {
check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval); check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
vec![cfg_eval(ecx, annotatable)] vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)]
} }
crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Annotatable { crate fn cfg_eval(
CfgEval { sess: &Session,
cfg: &mut StripUnconfigured { features: Option<&Features>,
sess: ecx.sess, annotatable: Annotatable,
features: ecx.ecfg.features, ) -> Annotatable {
config_tokens: true, CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true } }
}, .configure_annotatable(annotatable)
} // Since the item itself has already been configured by the `InvocationCollector`,
.configure_annotatable(annotatable) // we know that fold result vector will contain exactly one element.
// Since the item itself has already been configured by the `InvocationCollector`, .unwrap()
// we know that fold result vector will contain exactly one element.
.unwrap()
} }
struct CfgEval<'a, 'b> { struct CfgEval<'a, 'b> {

View file

@ -1,12 +1,13 @@
use crate::cfg_eval::cfg_eval; use crate::cfg_eval::cfg_eval;
use rustc_ast::{self as ast, attr, token, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; use rustc_ast as ast;
use rustc_ast::{attr, token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
use rustc_errors::{struct_span_err, Applicability}; use rustc_errors::{struct_span_err, Applicability};
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
use rustc_feature::AttributeTemplate; use rustc_feature::AttributeTemplate;
use rustc_parse::validate_attr; use rustc_parse::validate_attr;
use rustc_session::Session; use rustc_session::Session;
use rustc_span::symbol::sym; use rustc_span::symbol::{sym, Ident};
use rustc_span::Span; use rustc_span::Span;
crate struct Expander; crate struct Expander;
@ -26,8 +27,7 @@ impl MultiItemModifier for Expander {
return ExpandResult::Ready(vec![item]); return ExpandResult::Ready(vec![item]);
} }
let configured_item = cfg_eval(ecx, item.clone()); let (sess, features) = (ecx.sess, ecx.ecfg.features);
let result = let result =
ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| { ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
let template = let template =
@ -40,7 +40,8 @@ impl MultiItemModifier for Expander {
template, template,
); );
attr.meta_item_list() let mut resolutions: Vec<_> = attr
.meta_item_list()
.unwrap_or_default() .unwrap_or_default()
.into_iter() .into_iter()
.filter_map(|nested_meta| match nested_meta { .filter_map(|nested_meta| match nested_meta {
@ -56,8 +57,21 @@ impl MultiItemModifier for Expander {
report_path_args(sess, &meta); report_path_args(sess, &meta);
meta.path meta.path
}) })
.map(|path| (path, configured_item.clone(), None)) .map(|path| (path, dummy_annotatable(), None))
.collect() .collect();
// Do not configure or clone items unless necessary.
match &mut resolutions[..] {
[] => {}
[(_, first_item, _), others @ ..] => {
*first_item = cfg_eval(sess, features, item.clone());
for (_, item, _) in others {
*item = first_item.clone();
}
}
}
resolutions
}); });
match result { match result {
@ -67,6 +81,18 @@ impl MultiItemModifier for Expander {
} }
} }
// The cheapest `Annotatable` to construct.
fn dummy_annotatable() -> Annotatable {
Annotatable::GenericParam(ast::GenericParam {
id: ast::DUMMY_NODE_ID,
ident: Ident::invalid(),
attrs: Default::default(),
bounds: Default::default(),
is_placeholder: false,
kind: GenericParamKind::Lifetime,
})
}
fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool { fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
let item_kind = match item { let item_kind = match item {
Annotatable::Item(item) => Some(&item.kind), Annotatable::Item(item) => Some(&item.kind),