@@ -138,6 +138,61 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
138138 ) ;
139139 assert ! ( old_parent. is_none( ) , "parent `LocalDefId` is reset for an invocation" ) ;
140140 }
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 treated as equivalent to a bare parameter `N` whereas `{{ N }}` is treated as
169+ /// a real block expression and is lowered to an anonymous constant which is not allowed to use
170+ /// generic parameters.
171+ ///
172+ /// If this expression is a trivial macro call then the id for the macro call is
173+ /// returned along with the information required to build the anon const's def if
174+ /// the macro call expands to a non-trivial expression.
175+ fn is_const_arg_sub_expr_trivial_macro_expansion (
176+ & self ,
177+ const_arg_sub_expr : & ' a Expr ,
178+ ) -> Option < ( PendingAnonConstInfo , NodeId ) > {
179+ let pending_anon = self . pending_anon_const_info . unwrap_or_else ( ||
180+ panic ! ( "Checking expr is trivial macro call without having entered anon const: `{const_arg_sub_expr:?}`" ) ,
181+ ) ;
182+
183+ let ( block_was_stripped, expr) = if pending_anon. block_was_stripped {
184+ ( true , const_arg_sub_expr)
185+ } else {
186+ const_arg_sub_expr. maybe_unwrap_block ( )
187+ } ;
188+
189+ match expr {
190+ Expr { kind : ExprKind :: MacCall ( ..) , id, .. } => {
191+ Some ( ( PendingAnonConstInfo { block_was_stripped, ..pending_anon } , * id) )
192+ }
193+ _ => None ,
194+ }
195+ }
141196}
142197
143198impl < ' a , ' ra , ' tcx > visit:: Visitor < ' a > for DefCollector < ' a , ' ra , ' tcx > {
@@ -354,12 +409,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
354409 // items will be messed up, but that's ok because there can't be any if we're just looking
355410 // for bare idents.
356411
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 ( ) {
412+ if let Some ( ( pending_anon , macro_invoc ) ) =
413+ self . is_const_arg_trivial_macro_expansion ( constant )
414+ {
415+ self . pending_anon_const_info = Some ( pending_anon ) ;
416+ return self . visit_macro_invoc ( macro_invoc ) ;
417+ } else if constant. value . is_potential_trivial_const_arg ( true ) {
363418 return visit:: walk_anon_const ( self , constant) ;
364419 }
365420
@@ -368,23 +423,36 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
368423 }
369424
370425 fn visit_expr ( & mut self , expr : & ' a Expr ) {
371- if matches ! ( expr. kind, ExprKind :: MacCall ( ..) ) {
372- return self . visit_macro_invoc ( expr. id ) ;
426+ // If we're visiting the expression of a const argument that was a macro call then
427+ // check if it is *still* unknown whether it is a trivial const arg or not. If so
428+ // recurse into the macro call and delay creating the anon const def until expansion.
429+ if self . pending_anon_const_info . is_some ( )
430+ && let Some ( ( pending_anon, macro_invoc) ) =
431+ self . is_const_arg_sub_expr_trivial_macro_expansion ( expr)
432+ {
433+ self . pending_anon_const_info = Some ( pending_anon) ;
434+ return self . visit_macro_invoc ( macro_invoc) ;
373435 }
374436
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 ( ) {
437+ // See self.pending_anon_const_info for explanation
438+ let parent_def = self
439+ . pending_anon_const_info
440+ . take ( )
441+ // If we already stripped away a set of braces then do not do it again when determining
442+ // if the macro expanded to a trivial const arg. This arises in cases such as:
443+ // `Foo<{ bar!() }>` where `bar!()` expands to `{ N }`. This should not be considered a
444+ // trivial const argument even though `{ N }` by itself *is*.
445+ . filter ( |pending_anon| {
446+ !expr. is_potential_trivial_const_arg ( !pending_anon. block_was_stripped )
447+ } )
448+ . map ( |pending_anon| {
378449 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- } ;
450+ } )
451+ . unwrap_or ( self . parent_def ) ;
385452
386- self . with_parent ( grandparent_def , |this| {
453+ self . with_parent ( parent_def , |this| {
387454 let parent_def = match expr. kind {
455+ ExprKind :: MacCall ( ..) => return this. visit_macro_invoc ( expr. id ) ,
388456 ExprKind :: Closure ( ..) | ExprKind :: Gen ( ..) => {
389457 this. create_def ( expr. id , kw:: Empty , DefKind :: Closure , expr. span )
390458 }
0 commit comments