@@ -138,6 +138,59 @@ 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 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+ }
141194}
142195
143196impl < ' 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> {
354407 // items will be messed up, but that's ok because there can't be any if we're just looking
355408 // for bare idents.
356409
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 ) {
363416 return visit:: walk_anon_const ( self , constant) ;
364417 }
365418
@@ -368,23 +421,36 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
368421 }
369422
370423 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) ;
373433 }
374434
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| {
378447 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 ) ;
385450
386- self . with_parent ( grandparent_def , |this| {
451+ self . with_parent ( parent_def , |this| {
387452 let parent_def = match expr. kind {
453+ ExprKind :: MacCall ( ..) => return this. visit_macro_invoc ( expr. id ) ,
388454 ExprKind :: Closure ( ..) | ExprKind :: Gen ( ..) => {
389455 this. create_def ( expr. id , kw:: Empty , DefKind :: Closure , expr. span )
390456 }
0 commit comments