@@ -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 ,
@@ -657,6 +697,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
657697 self . parse_ast_fragment ( tok_result, fragment_kind, & mac. path , span)
658698 }
659699 SyntaxExtensionKind :: LegacyBang ( expander) => {
700+ if self . reduce_expansion_growth_limit ( mac. args . inner_tokens ( ) . len ( ) ) . is_err ( ) {
701+ return ExpandResult :: Ready ( fragment_kind. dummy ( span) ) ;
702+ }
703+ let prev = self . cx . current_expansion . prior_type_ascription ;
704+ self . cx . current_expansion . prior_type_ascription = mac. prior_type_ascription ;
660705 let tok_result = expander. expand ( self . cx , span, mac. args . tokens . clone ( ) ) ;
661706 let result = if let Some ( result) = fragment_kind. make_from ( tok_result) {
662707 result
@@ -1966,6 +2011,7 @@ pub struct ExpansionConfig<'feat> {
19662011 pub crate_name : String ,
19672012 pub features : Option < & ' feat Features > ,
19682013 pub recursion_limit : Limit ,
2014+ pub expansion_growth_limit : Limit ,
19692015 pub trace_mac : bool ,
19702016 /// If false, strip `#[test]` nodes
19712017 pub should_test : bool ,
@@ -1981,6 +2027,7 @@ impl<'feat> ExpansionConfig<'feat> {
19812027 crate_name,
19822028 features : None ,
19832029 recursion_limit : Limit :: new ( 1024 ) ,
2030+ expansion_growth_limit : Limit :: new ( 1500 ) ,
19842031 trace_mac : false ,
19852032 should_test : false ,
19862033 span_debug : false ,
0 commit comments