@@ -621,6 +621,30 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
621621 self . cx . trace_macros_diag ( ) ;
622622 }
623623
624+ fn error_expansion_growth_limit ( & mut self ) {
625+ let expn_data = self . cx . current_expansion . id . expn_data ( ) ;
626+ let suggested_limit = match self . cx . ecfg . expansion_growth_limit {
627+ Limit ( 0 ) => Limit ( 2 ) ,
628+ limit => limit * 2 ,
629+ } ;
630+
631+ self . cx
632+ . struct_span_err (
633+ expn_data. call_site ,
634+ & format ! (
635+ "expansion grow limit reached while expanding `{}`" ,
636+ expn_data. kind. descr( )
637+ ) ,
638+ )
639+ . help ( & format ! (
640+ "consider increasing the expansion grow limit by adding a \
641+ `#![expansion_growth_limit = \" {}\" ]` attribute to your crate (`{}`)",
642+ suggested_limit, self . cx. ecfg. crate_name,
643+ ) )
644+ . emit ( ) ;
645+ self . cx . trace_macros_diag ( ) ;
646+ }
647+
624648 /// A macro's expansion does not fit in this fragment kind.
625649 /// For example, a non-type macro in a type position.
626650 fn error_wrong_fragment_kind ( & mut self , kind : AstFragmentKind , mac : & ast:: MacCall , span : Span ) {
@@ -629,6 +653,22 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
629653 self . cx . trace_macros_diag ( ) ;
630654 }
631655
656+ fn reduce_expansion_growth_limit ( & mut self , tokens_solved_size : usize ) -> Result < ( ) , ( ) > {
657+ let expansion_limit =
658+ self . cx . reduced_expansion_growth_limit . unwrap_or ( self . cx . ecfg . expansion_growth_limit ) ;
659+ if !expansion_limit. value_within_limit ( tokens_solved_size) {
660+ if self . cx . reduced_expansion_growth_limit . is_none ( ) {
661+ self . error_expansion_growth_limit ( ) ;
662+ }
663+
664+ // Reduce the recursion limit by half each time it triggers.
665+ self . cx . reduced_recursion_limit = Some ( expansion_limit / 2 ) ;
666+
667+ return Err ( ( ) ) ;
668+ }
669+ Ok ( ( ) )
670+ }
671+
632672 fn expand_invoc (
633673 & mut self ,
634674 invoc : Invocation ,
@@ -658,6 +698,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
658698 self . parse_ast_fragment ( tok_result, fragment_kind, & mac. path , span)
659699 }
660700 SyntaxExtensionKind :: LegacyBang ( expander) => {
701+ if self . reduce_expansion_growth_limit ( mac. args . inner_tokens ( ) . len ( ) ) . is_err ( ) {
702+ return ExpandResult :: Ready ( fragment_kind. dummy ( span) ) ;
703+ }
704+ let prev = self . cx . current_expansion . prior_type_ascription ;
705+ self . cx . current_expansion . prior_type_ascription = mac. prior_type_ascription ;
661706 let tok_result = expander. expand ( self . cx , span, mac. args . tokens . clone ( ) ) ;
662707 let result = if let Some ( result) = fragment_kind. make_from ( tok_result) {
663708 result
@@ -1979,6 +2024,7 @@ pub struct ExpansionConfig<'feat> {
19792024 pub crate_name : String ,
19802025 pub features : & ' feat Features ,
19812026 pub recursion_limit : Limit ,
2027+ pub expansion_growth_limit : Limit ,
19822028 pub trace_mac : bool ,
19832029 /// If false, strip `#[test]` nodes
19842030 pub should_test : bool ,
@@ -1994,6 +2040,7 @@ impl ExpansionConfig<'_> {
19942040 crate_name,
19952041 features,
19962042 recursion_limit : Limit :: new ( 1024 ) ,
2043+ expansion_growth_limit : Limit :: new ( 1500 ) ,
19972044 trace_mac : false ,
19982045 should_test : false ,
19992046 span_debug : false ,
0 commit comments