From 82920f36c47fb649858a31caf840e29088dcd8ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 26 Feb 2020 23:43:49 +0100 Subject: [PATCH 1/2] Don't unwind when hitting the macro expansion recursion limit --- src/librustc_expand/base.rs | 2 ++ src/librustc_expand/expand.rs | 16 ++++++++++++---- src/librustc_interface/passes.rs | 13 +++++++++++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 74c304c96b9a4..0fc477bbd0b4c 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -922,6 +922,7 @@ pub struct ExpansionData { pub struct ExtCtxt<'a> { pub parse_sess: &'a ParseSess, pub ecfg: expand::ExpansionConfig<'a>, + pub reduced_recursion_limit: Option, pub root_path: PathBuf, pub resolver: &'a mut dyn Resolver, pub current_expansion: ExpansionData, @@ -940,6 +941,7 @@ impl<'a> ExtCtxt<'a> { ExtCtxt { parse_sess, ecfg, + reduced_recursion_limit: None, resolver, extern_mod_loaded, root_path: PathBuf::new(), diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index b6cc192cc33d6..4f568e5456c72 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -17,7 +17,7 @@ use rustc_ast::util::map_in_place::MapInPlace; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; -use rustc_errors::{Applicability, FatalError, PResult}; +use rustc_errors::{Applicability, PResult}; use rustc_feature::Features; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; @@ -645,7 +645,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { )) .emit(); self.cx.trace_macros_diag(); - FatalError.raise(); } /// A macro's expansion does not fit in this fragment kind. @@ -665,8 +664,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> { invoc: Invocation, ext: &SyntaxExtensionKind, ) -> ExpandResult { - if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { - self.error_recursion_limit_reached(); + let recursion_limit = + self.cx.reduced_recursion_limit.unwrap_or(self.cx.ecfg.recursion_limit); + if self.cx.current_expansion.depth > recursion_limit { + if self.cx.reduced_recursion_limit.is_none() { + self.error_recursion_limit_reached(); + } + + // Reduce the recursion limit by half each time it triggers. + self.cx.reduced_recursion_limit = Some(recursion_limit / 2); + + return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span())); } let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index ee323b204b7a0..22089f9de312d 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -311,6 +311,8 @@ fn configure_and_expand_inner<'a>( ecx.parse_sess.missing_fragment_specifiers.borrow().iter().cloned().collect(); missing_fragment_specifiers.sort(); + let recursion_limit_hit = ecx.reduced_recursion_limit.is_some(); + for span in missing_fragment_specifiers { let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER; let msg = "missing fragment specifier"; @@ -319,8 +321,15 @@ fn configure_and_expand_inner<'a>( if cfg!(windows) { env::set_var("PATH", &old_path); } - krate - }); + + if recursion_limit_hit { + // If we hit a recursion limit, exit early to avoid later passes getting overwhelmed + // with a large AST + Err(ErrorReported) + } else { + Ok(krate) + } + })?; sess.time("maybe_building_test_harness", || { rustc_builtin_macros::test_harness::inject( From d641ad044eb535741cd2160e7cbf96d91c2c54c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 29 Feb 2020 04:23:58 +0100 Subject: [PATCH 2/2] Update test --- src/test/ui/macros/trace_faulty_macros.rs | 2 +- src/test/ui/macros/trace_faulty_macros.stderr | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/test/ui/macros/trace_faulty_macros.rs b/src/test/ui/macros/trace_faulty_macros.rs index 627d58abf4ca2..a55f05414b206 100644 --- a/src/test/ui/macros/trace_faulty_macros.rs +++ b/src/test/ui/macros/trace_faulty_macros.rs @@ -13,7 +13,7 @@ macro_rules! pat_macro { pat_macro!(A{a:a, b:0, c:_, ..}); }; ($a:pat) => { - $a + $a //~ ERROR expected expression }; } diff --git a/src/test/ui/macros/trace_faulty_macros.stderr b/src/test/ui/macros/trace_faulty_macros.stderr index a18e22e07f8bc..109b493b43717 100644 --- a/src/test/ui/macros/trace_faulty_macros.stderr +++ b/src/test/ui/macros/trace_faulty_macros.stderr @@ -49,5 +49,16 @@ LL | my_recursive_macro!(); = note: expanding `my_recursive_macro! { }` = note: to `my_recursive_macro ! () ;` -error: aborting due to 2 previous errors +error: expected expression, found `A { a: a, b: 0, c: _, .. }` + --> $DIR/trace_faulty_macros.rs:16:9 + | +LL | $a + | ^^ expected expression +... +LL | let a = pat_macro!(); + | ------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors