@@ -138,6 +138,51 @@ 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's expression is a simple macro call, optionally
143
+ /// surrounded in braces depending on whether a brace has already been unwrapped on this
144
+ /// const argument.
145
+ ///
146
+ /// If this expresion *is* a trivial macro call then the id for the macro call is
147
+ /// returned along with the information required to build the anon const's def if
148
+ /// the macro call expands to a non-trivial expression.
149
+ fn is_const_arg_trivial_macro_expansion (
150
+ & self ,
151
+ const_arg_expr : & ' a Expr ,
152
+ anon_const : Option < & ' a AnonConst > ,
153
+ ) -> Option < ( PendingAnonConstInfo , NodeId ) > {
154
+ let ( anon_const_id, anon_const_span) = if let Some ( anon_const) = anon_const {
155
+ ( anon_const. id , anon_const. value . span )
156
+ } else if let Some ( pending_anon) = & self . pending_anon_const_info {
157
+ ( pending_anon. id , pending_anon. span )
158
+ } else {
159
+ panic ! (
160
+ "`is_const_arg_trivial_macro_expansion` called without having recursed into anon const"
161
+ ) ;
162
+ } ;
163
+
164
+ let ( block_was_stripped, expr) = if self
165
+ . pending_anon_const_info
166
+ . is_some_and ( |pending_anon| pending_anon. block_was_stripped )
167
+ {
168
+ ( true , const_arg_expr)
169
+ } else {
170
+ const_arg_expr. maybe_unwrap_block ( )
171
+ } ;
172
+
173
+ if let Expr { kind : ExprKind :: MacCall ( ..) , id, .. } = expr {
174
+ Some ( (
175
+ PendingAnonConstInfo {
176
+ id : anon_const_id,
177
+ span : anon_const_span,
178
+ block_was_stripped,
179
+ } ,
180
+ * id,
181
+ ) )
182
+ } else {
183
+ None
184
+ }
185
+ }
141
186
}
142
187
143
188
impl < ' a , ' ra , ' tcx > visit:: Visitor < ' a > for DefCollector < ' a , ' ra , ' tcx > {
@@ -354,12 +399,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
354
399
// items will be messed up, but that's ok because there can't be any if we're just looking
355
400
// for bare idents.
356
401
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 ( ) {
402
+ if let Some ( ( pending_anon , macro_invoc ) ) =
403
+ self . is_const_arg_trivial_macro_expansion ( & * constant . value , Some ( & constant ) )
404
+ {
405
+ self . pending_anon_const_info = Some ( pending_anon ) ;
406
+ return self . visit_macro_invoc ( macro_invoc ) ;
407
+ } else if constant. value . is_potential_trivial_const_arg ( true ) {
363
408
return visit:: walk_anon_const ( self , constant) ;
364
409
}
365
410
@@ -368,23 +413,36 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
368
413
}
369
414
370
415
fn visit_expr ( & mut self , expr : & ' a Expr ) {
371
- if matches ! ( expr. kind, ExprKind :: MacCall ( ..) ) {
372
- return self . visit_macro_invoc ( expr. id ) ;
416
+ // If we're visiting the expression of a const argument that was a macro call then
417
+ // check if it is *still* unknown whether it is a trivial const arg or not. If so
418
+ // recurse into the macro call and delay creating the anon const def until expansion.
419
+ if self . pending_anon_const_info . is_some ( )
420
+ && let Some ( ( pending_anon, macro_invoc) ) =
421
+ self . is_const_arg_trivial_macro_expansion ( expr, None )
422
+ {
423
+ self . pending_anon_const_info = Some ( pending_anon) ;
424
+ return self . visit_macro_invoc ( macro_invoc) ;
373
425
}
374
426
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 ( ) {
427
+ // See self.pending_anon_const_info for explanation
428
+ let parent_def = self
429
+ . pending_anon_const_info
430
+ . take ( )
431
+ // If we already stripped away a set of braces then do not do it again when determining
432
+ // if the macro expanded to a trivial const arg. This arises in cases such as:
433
+ // `Foo<{ bar!() }>` where `bar!()` expands to `{ N }`. This should not be considered a
434
+ // trivial const argument even though `{ N }` by itself *is*.
435
+ . filter ( |pending_anon| {
436
+ !expr. is_potential_trivial_const_arg ( !pending_anon. block_was_stripped )
437
+ } )
438
+ . map ( |pending_anon| {
378
439
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
- } ;
440
+ } )
441
+ . unwrap_or ( self . parent_def ) ;
385
442
386
- self . with_parent ( grandparent_def , |this| {
443
+ self . with_parent ( parent_def , |this| {
387
444
let parent_def = match expr. kind {
445
+ ExprKind :: MacCall ( ..) => return this. visit_macro_invoc ( expr. id ) ,
388
446
ExprKind :: Closure ( ..) | ExprKind :: Gen ( ..) => {
389
447
this. create_def ( expr. id , kw:: Empty , DefKind :: Closure , expr. span )
390
448
}
0 commit comments