1
1
use crate :: cfg_eval:: cfg_eval;
2
2
3
- use rustc_ast:: { self as ast, attr, token, ItemKind , MetaItemKind , NestedMetaItem , StmtKind } ;
3
+ use rustc_ast as ast;
4
+ use rustc_ast:: { attr, token, GenericParamKind , ItemKind , MetaItemKind , NestedMetaItem , StmtKind } ;
4
5
use rustc_errors:: { struct_span_err, Applicability } ;
5
6
use rustc_expand:: base:: { Annotatable , ExpandResult , ExtCtxt , Indeterminate , MultiItemModifier } ;
6
7
use rustc_feature:: AttributeTemplate ;
7
8
use rustc_parse:: validate_attr;
8
9
use rustc_session:: Session ;
9
- use rustc_span:: symbol:: sym;
10
+ use rustc_span:: symbol:: { sym, Ident } ;
10
11
use rustc_span:: Span ;
11
12
12
13
crate struct Expander ;
@@ -26,6 +27,7 @@ impl MultiItemModifier for Expander {
26
27
return ExpandResult :: Ready ( vec ! [ item] ) ;
27
28
}
28
29
30
+ let ( sess, features) = ( ecx. sess , ecx. ecfg . features ) ;
29
31
let result =
30
32
ecx. resolver . resolve_derives ( ecx. current_expansion . id , ecx. force_mode , & || {
31
33
let template =
@@ -38,7 +40,8 @@ impl MultiItemModifier for Expander {
38
40
template,
39
41
) ;
40
42
41
- attr. meta_item_list ( )
43
+ let mut resolutions: Vec < _ > = attr
44
+ . meta_item_list ( )
42
45
. unwrap_or_default ( )
43
46
. into_iter ( )
44
47
. filter_map ( |nested_meta| match nested_meta {
@@ -54,17 +57,42 @@ impl MultiItemModifier for Expander {
54
57
report_path_args ( sess, & meta) ;
55
58
meta. path
56
59
} )
57
- . map ( |path| ( path, None ) )
58
- . collect ( )
60
+ . map ( |path| ( path, dummy_annotatable ( ) , None ) )
61
+ . collect ( ) ;
62
+
63
+ // Do not configure or clone items unless necessary.
64
+ match & mut resolutions[ ..] {
65
+ [ ] => { }
66
+ [ ( _, first_item, _) , others @ ..] => {
67
+ * first_item = cfg_eval ( sess, features, item. clone ( ) ) ;
68
+ for ( _, item, _) in others {
69
+ * item = first_item. clone ( ) ;
70
+ }
71
+ }
72
+ }
73
+
74
+ resolutions
59
75
} ) ;
60
76
61
77
match result {
62
- Ok ( ( ) ) => ExpandResult :: Ready ( cfg_eval ( ecx , item) ) ,
78
+ Ok ( ( ) ) => ExpandResult :: Ready ( vec ! [ item] ) ,
63
79
Err ( Indeterminate ) => ExpandResult :: Retry ( item) ,
64
80
}
65
81
}
66
82
}
67
83
84
+ // The cheapest `Annotatable` to construct.
85
+ fn dummy_annotatable ( ) -> Annotatable {
86
+ Annotatable :: GenericParam ( ast:: GenericParam {
87
+ id : ast:: DUMMY_NODE_ID ,
88
+ ident : Ident :: invalid ( ) ,
89
+ attrs : Default :: default ( ) ,
90
+ bounds : Default :: default ( ) ,
91
+ is_placeholder : false ,
92
+ kind : GenericParamKind :: Lifetime ,
93
+ } )
94
+ }
95
+
68
96
fn report_bad_target ( sess : & Session , item : & Annotatable , span : Span ) -> bool {
69
97
let item_kind = match item {
70
98
Annotatable :: Item ( item) => Some ( & item. kind ) ,
0 commit comments