1- use rustc_ast:: tokenstream:: TokenStream ;
2- use rustc_ast:: { Expr , ast} ;
1+ use rustc_ast:: attr:: mk_attr_from_item;
2+ use rustc_ast:: token:: { self , Delimiter , Token , TokenKind } ;
3+ use rustc_ast:: tokenstream:: {
4+ AttrTokenStream , AttrTokenTree , DelimSpacing , DelimSpan , LazyAttrTokenStream , Spacing ,
5+ TokenStream ,
6+ } ;
7+ use rustc_ast:: { AttrItem , AttrItemKind , EarlyParsedAttribute , Expr , Path , Safety , ast} ;
38use rustc_attr_parsing as attr;
49use rustc_attr_parsing:: { CfgSelectBranches , EvalConfigResult , parse_cfg_select} ;
510use rustc_expand:: base:: { DummyResult , ExpandResult , ExtCtxt , MacResult , MacroExpanderResult } ;
6- use rustc_span:: { Ident , Span , sym} ;
11+ use rustc_expand:: expand:: DeclaredIdents ;
12+ use rustc_hir:: attrs:: CfgEntry ;
13+ use rustc_span:: { DUMMY_SP , Ident , Span , sym} ;
714use smallvec:: SmallVec ;
815
916use crate :: errors:: CfgSelectNoMatches ;
@@ -17,6 +24,7 @@ struct CfgSelectResult<'cx, 'sess> {
1724 selected_tts : TokenStream ,
1825 selected_span : Span ,
1926 other_branches : CfgSelectBranches ,
27+ cfg_entry : CfgEntry ,
2028}
2129
2230fn tts_to_mac_result < ' cx , ' sess > (
@@ -37,19 +45,99 @@ macro_rules! forward_to_parser_any_macro {
3745 fn $method_name( self : Box <Self >) -> Option <$ret_ty> {
3846 let CfgSelectResult { ecx, site_span, selected_tts, selected_span, .. } = * self ;
3947
40- for ( tts, span) in self . other_branches. into_iter_tts( ) {
48+ for ( _ , tts, span) in self . other_branches. into_iter_tts( ) {
4149 let _ = tts_to_mac_result( ecx, site_span, tts, span) . $method_name( ) ;
4250 }
4351
4452 tts_to_mac_result( ecx, site_span, selected_tts, selected_span) . $method_name( )
4553 }
4654 } ;
55+ ( make_items) => {
56+ // The same logic as above, but we also register the items that were not selected in the
57+ // resolver for error reporting, as well as annotate the selected item with `#[cfg_trace]`.
58+ fn make_items( self : Box <Self >) -> Option <SmallVec <[ Box <ast:: Item >; 1 ] >> {
59+ let CfgSelectResult { ecx, site_span, selected_tts, selected_span, cfg_entry, .. } =
60+ * self ;
61+
62+ for ( cfg_entry, tts, span) in self . other_branches. into_iter_tts( ) {
63+ if let Some ( items) = tts_to_mac_result( ecx, site_span, tts, span) . make_items( ) {
64+ // Register item names that were not selected for error reporting. We do this
65+ // for `#[cfg]` too.
66+ for item in items {
67+ for name in item. declared_idents( ) {
68+ ecx. resolver. append_stripped_cfg_item(
69+ ecx. current_expansion. lint_node_id,
70+ name,
71+ cfg_entry. clone( ) ,
72+ span,
73+ ) ;
74+ }
75+ }
76+ }
77+ }
78+
79+ tts_to_mac_result( ecx, site_span, selected_tts, selected_span) . make_items( ) . map(
80+ |items| {
81+ items
82+ . into_iter( )
83+ . map( |mut item| {
84+ let g = & ecx. sess. psess. attr_id_generator;
85+ let args = AttrItemKind :: Parsed ( EarlyParsedAttribute :: CfgTrace (
86+ cfg_entry. clone( ) ,
87+ ) ) ;
88+ let trees = vec![
89+ AttrTokenTree :: Token (
90+ Token { kind: TokenKind :: Pound , span: DUMMY_SP } ,
91+ Spacing :: JointHidden ,
92+ ) ,
93+ AttrTokenTree :: Delimited (
94+ DelimSpan :: dummy( ) ,
95+ DelimSpacing :: new( Spacing :: JointHidden , Spacing :: Alone ) ,
96+ Delimiter :: Bracket ,
97+ AttrTokenStream :: new( vec![ AttrTokenTree :: Token (
98+ Token {
99+ kind: TokenKind :: Ident (
100+ sym:: cfg_trace,
101+ token:: IdentIsRaw :: No ,
102+ ) ,
103+ span: DUMMY_SP ,
104+ } ,
105+ Spacing :: Alone ,
106+ ) ] ) ,
107+ ) ,
108+ ] ;
109+ let tokens =
110+ Some ( LazyAttrTokenStream :: new_direct( AttrTokenStream :: new( trees) ) ) ;
111+ let attr_item = AttrItem {
112+ unsafety: Safety :: Default ,
113+ path: Path :: from_ident( Ident :: new(
114+ sym:: cfg_trace,
115+ cfg_entry. span( ) ,
116+ ) ) ,
117+ args,
118+ tokens: None ,
119+ } ;
120+ let attr = mk_attr_from_item(
121+ g,
122+ attr_item,
123+ tokens,
124+ ast:: AttrStyle :: Outer ,
125+ cfg_entry. span( ) ,
126+ ) ;
127+ item. attrs. push( attr) ;
128+ item
129+ } )
130+ . collect( )
131+ } ,
132+ )
133+ }
134+ } ;
47135}
48136
49137impl < ' cx , ' sess > MacResult for CfgSelectResult < ' cx , ' sess > {
50138 forward_to_parser_any_macro ! ( make_expr, Box <Expr >) ;
51139 forward_to_parser_any_macro ! ( make_stmts, SmallVec <[ ast:: Stmt ; 1 ] >) ;
52- forward_to_parser_any_macro ! ( make_items, SmallVec < [ Box <ast :: Item > ; 1 ] > ) ;
140+ forward_to_parser_any_macro ! ( make_items) ;
53141
54142 forward_to_parser_any_macro ! ( make_impl_items, SmallVec <[ Box <ast:: AssocItem >; 1 ] >) ;
55143 forward_to_parser_any_macro ! ( make_trait_impl_items, SmallVec <[ Box <ast:: AssocItem >; 1 ] >) ;
@@ -73,15 +161,18 @@ pub(super) fn expand_cfg_select<'cx>(
73161 ecx. current_expansion . lint_node_id ,
74162 ) {
75163 Ok ( mut branches) => {
76- if let Some ( ( selected_tts, selected_span) ) = branches. pop_first_match ( |cfg| {
77- matches ! ( attr:: eval_config_entry( & ecx. sess, cfg) , EvalConfigResult :: True )
78- } ) {
164+ if let Some ( ( cfg_entry, selected_tts, selected_span) ) =
165+ branches. pop_first_match ( |cfg| {
166+ matches ! ( attr:: eval_config_entry( & ecx. sess, cfg) , EvalConfigResult :: True )
167+ } )
168+ {
79169 let mac = CfgSelectResult {
80170 ecx,
81171 selected_tts,
82172 selected_span,
83173 other_branches : branches,
84174 site_span : sp,
175+ cfg_entry,
85176 } ;
86177 return ExpandResult :: Ready ( Box :: new ( mac) ) ;
87178 } else {
0 commit comments