@@ -138,6 +138,59 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
138
138
) ;
139
139
assert ! ( old_parent. is_none( ) , "parent `LocalDefId` is reset for an invocation" ) ;
140
140
}
141
+
142
+ /// Determines whether the const argument `AnonConst` is a simple macro call, optionally
143
+ /// surrounded with braces.
144
+ ///
145
+ /// If this const argument *is* a trivial macro call then the id for the macro call is
146
+ /// returned along with the information required to build the anon const's def if
147
+ /// the macro call expands to a non-trivial expression.
148
+ fn is_const_arg_trivial_macro_expansion (
149
+ & self ,
150
+ anon_const : & ' a AnonConst ,
151
+ ) -> Option < ( PendingAnonConstInfo , NodeId ) > {
152
+ let ( block_was_stripped, expr) = anon_const. value . maybe_unwrap_block ( ) ;
153
+ match expr {
154
+ Expr { kind : ExprKind :: MacCall ( ..) , id, .. } => Some ( (
155
+ PendingAnonConstInfo {
156
+ id : anon_const. id ,
157
+ span : anon_const. value . span ,
158
+ block_was_stripped,
159
+ } ,
160
+ * id,
161
+ ) ) ,
162
+ _ => None ,
163
+ }
164
+ }
165
+
166
+ /// Determines whether the expression `const_arg_sub_expr` is a simple macro call, sometimes
167
+ /// surrounded with braces if a set of braces has not already been entered. This is required
168
+ /// as `{ N }` is legal rust wheras `{{ N }}` is not.
169
+ ///
170
+ /// If this expression is a trivial macro call then the id for the macro call is
171
+ /// returned along with the information required to build the anon const's def if
172
+ /// the macro call expands to a non-trivial expression.
173
+ fn is_const_arg_sub_expr_trivial_macro_expansion (
174
+ & self ,
175
+ const_arg_sub_expr : & ' a Expr ,
176
+ ) -> Option < ( PendingAnonConstInfo , NodeId ) > {
177
+ let pending_anon = self . pending_anon_const_info . expect (
178
+ "Checking expr is trivial macro call without having entered anon const: `{:?}`" ,
179
+ ) ;
180
+
181
+ let ( block_was_stripped, expr) = if pending_anon. block_was_stripped {
182
+ ( true , const_arg_sub_expr)
183
+ } else {
184
+ const_arg_sub_expr. maybe_unwrap_block ( )
185
+ } ;
186
+
187
+ match expr {
188
+ Expr { kind : ExprKind :: MacCall ( ..) , id, .. } => {
189
+ Some ( ( PendingAnonConstInfo { block_was_stripped, ..pending_anon } , * id) )
190
+ }
191
+ _ => None ,
192
+ }
193
+ }
141
194
}
142
195
143
196
impl < ' a , ' ra , ' tcx > visit:: Visitor < ' a > for DefCollector < ' a , ' ra , ' tcx > {
@@ -354,12 +407,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
354
407
// items will be messed up, but that's ok because there can't be any if we're just looking
355
408
// for bare idents.
356
409
357
- if matches ! ( constant . value . maybe_unwrap_block ( ) . kind , ExprKind :: MacCall ( .. ) ) {
358
- // See self.pending_anon_const_info for explanation
359
- self . pending_anon_const_info =
360
- Some ( PendingAnonConstInfo { id : constant . id , span : constant . value . span } ) ;
361
- return visit :: walk_anon_const ( self , constant ) ;
362
- } else if constant. value . is_potential_trivial_const_arg ( ) {
410
+ if let Some ( ( pending_anon , macro_invoc ) ) =
411
+ self . is_const_arg_trivial_macro_expansion ( constant )
412
+ {
413
+ self . pending_anon_const_info = Some ( pending_anon ) ;
414
+ return self . visit_macro_invoc ( macro_invoc ) ;
415
+ } else if constant. value . is_potential_trivial_const_arg ( true ) {
363
416
return visit:: walk_anon_const ( self , constant) ;
364
417
}
365
418
@@ -368,23 +421,36 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
368
421
}
369
422
370
423
fn visit_expr ( & mut self , expr : & ' a Expr ) {
371
- if matches ! ( expr. kind, ExprKind :: MacCall ( ..) ) {
372
- return self . visit_macro_invoc ( expr. id ) ;
424
+ // If we're visiting the expression of a const argument that was a macro call then
425
+ // check if it is *still* unknown whether it is a trivial const arg or not. If so
426
+ // recurse into the macro call and delay creating the anon const def until expansion.
427
+ if self . pending_anon_const_info . is_some ( )
428
+ && let Some ( ( pending_anon, macro_invoc) ) =
429
+ self . is_const_arg_sub_expr_trivial_macro_expansion ( expr)
430
+ {
431
+ self . pending_anon_const_info = Some ( pending_anon) ;
432
+ return self . visit_macro_invoc ( macro_invoc) ;
373
433
}
374
434
375
- let grandparent_def = if let Some ( pending_anon) = self . pending_anon_const_info . take ( ) {
376
- // See self.pending_anon_const_info for explanation
377
- if !expr. is_potential_trivial_const_arg ( ) {
435
+ // See self.pending_anon_const_info for explanation
436
+ let parent_def = self
437
+ . pending_anon_const_info
438
+ . take ( )
439
+ // If we already stripped away a set of braces then do not do it again when determining
440
+ // if the macro expanded to a trivial const arg. This arises in cases such as:
441
+ // `Foo<{ bar!() }>` where `bar!()` expands to `{ N }`. This should not be considered a
442
+ // trivial const argument even though `{ N }` by itself *is*.
443
+ . filter ( |pending_anon| {
444
+ !expr. is_potential_trivial_const_arg ( !pending_anon. block_was_stripped )
445
+ } )
446
+ . map ( |pending_anon| {
378
447
self . create_def ( pending_anon. id , kw:: Empty , DefKind :: AnonConst , pending_anon. span )
379
- } else {
380
- self . parent_def
381
- }
382
- } else {
383
- self . parent_def
384
- } ;
448
+ } )
449
+ . unwrap_or ( self . parent_def ) ;
385
450
386
- self . with_parent ( grandparent_def , |this| {
451
+ self . with_parent ( parent_def , |this| {
387
452
let parent_def = match expr. kind {
453
+ ExprKind :: MacCall ( ..) => return this. visit_macro_invoc ( expr. id ) ,
388
454
ExprKind :: Closure ( ..) | ExprKind :: Gen ( ..) => {
389
455
this. create_def ( expr. id , kw:: Empty , DefKind :: Closure , expr. span )
390
456
}
0 commit comments