diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-01-28 10:58:21 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-01-28 10:58:21 +0000 |
| commit | cd6521e5de4ee903abf59945319c102c8e83ef7d (patch) | |
| tree | 220f0d3961ffcca5ffa1ecf70670fb8ded650f87 | |
| parent | 93036aa0e201474d43c38be3862f4a899defe267 (diff) | |
| parent | 6d18c5b69d9751bdee8feaa90b095247be350d61 (diff) | |
| download | rust-cd6521e5de4ee903abf59945319c102c8e83ef7d.tar.gz rust-cd6521e5de4ee903abf59945319c102c8e83ef7d.zip | |
Merge #11360
11360: feat: Support `#![recursion_limit]` attribute r=Veykril a=WaffleLapkin  Resolves #8640 `@matklad` thanks, for the instructions, they were very helpful :) Co-authored-by: Maybe Waffle <waffle.lapkin@gmail.com>
| -rw-r--r-- | crates/hir_def/src/body.rs | 19 | ||||
| -rw-r--r-- | crates/hir_def/src/body/tests.rs | 18 | ||||
| -rw-r--r-- | crates/hir_def/src/db.rs | 17 | ||||
| -rw-r--r-- | crates/hir_def/src/nameres.rs | 7 | ||||
| -rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 11 | ||||
| -rw-r--r-- | crates/hir_expand/src/name.rs | 1 |
6 files changed, 66 insertions, 7 deletions
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 505b07cc8ac..8488b4f0d03 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs @@ -54,12 +54,6 @@ pub struct Expander { recursion_limit: usize, } -#[cfg(test)] -static EXPANSION_RECURSION_LIMIT: Limit = Limit::new(32); - -#[cfg(not(test))] -static EXPANSION_RECURSION_LIMIT: Limit = Limit::new(128); - impl CfgExpander { pub(crate) fn new( db: &dyn DefDatabase, @@ -101,7 +95,7 @@ impl Expander { db: &dyn DefDatabase, macro_call: ast::MacroCall, ) -> Result<ExpandResult<Option<(Mark, T)>>, UnresolvedMacro> { - if EXPANSION_RECURSION_LIMIT.check(self.recursion_limit + 1).is_err() { + if self.recursion_limit(db).check(self.recursion_limit + 1).is_err() { cov_mark::hit!(your_stack_belongs_to_me); return Ok(ExpandResult::str_err( "reached recursion limit during macro expansion".into(), @@ -222,6 +216,17 @@ impl Expander { let file_local_id = self.ast_id_map.ast_id(item); AstId::new(self.current_file_id, file_local_id) } + + fn recursion_limit(&self, db: &dyn DefDatabase) -> Limit { + let limit = db.crate_limits(self.cfg_expander.krate).recursion_limit as _; + + #[cfg(not(test))] + return Limit::new(limit); + + // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug + #[cfg(test)] + return Limit::new(std::cmp::min(32, limit)); + } } #[derive(Debug)] diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs index 673a7538616..1d84da48fb9 100644 --- a/crates/hir_def/src/body/tests.rs +++ b/crates/hir_def/src/body/tests.rs @@ -62,6 +62,24 @@ fn main() { n_nuple!(1,2,3); } } #[test] +fn recursion_limit() { + cov_mark::check!(your_stack_belongs_to_me); + + lower( + r#" +#![recursion_limit = "2"] +macro_rules! n_nuple { + ($e:tt) => (); + ($first:tt $($rest:tt)*) => {{ + n_nuple!($($rest)*) + }}; +} +fn main() { n_nuple!(1,2,3); } +"#, + ); +} + +#[test] fn macro_resolve() { // Regression test for a path resolution bug introduced with inner item handling. lower( diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs index 7946558311a..f9dd935c4b0 100644 --- a/crates/hir_def/src/db.rs +++ b/crates/hir_def/src/db.rs @@ -157,9 +157,26 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { #[salsa::invoke(visibility::function_visibility_query)] fn function_visibility(&self, def: FunctionId) -> Visibility; + + #[salsa::transparent] + fn crate_limits(&self, crate_id: CrateId) -> CrateLimits; } fn crate_def_map_wait(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> { let _p = profile::span("crate_def_map:wait"); db.crate_def_map_query(krate) } + +pub struct CrateLimits { + /// The maximum depth for potentially infinitely-recursive compile-time operations like macro expansion or auto-dereference. + pub recursion_limit: u32, +} + +fn crate_limits(db: &dyn DefDatabase, crate_id: CrateId) -> CrateLimits { + let def_map = db.crate_def_map(crate_id); + + CrateLimits { + // 128 is the default in rustc. + recursion_limit: def_map.recursion_limit().unwrap_or(128), + } +} diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 64929c02b40..ca4255c5819 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs @@ -114,6 +114,7 @@ pub struct DefMap { registered_tools: Vec<SmolStr>, edition: Edition, + recursion_limit: Option<u32>, diagnostics: Vec<DefDiagnostic>, } @@ -272,6 +273,7 @@ impl DefMap { block: None, krate, edition, + recursion_limit: None, extern_prelude: FxHashMap::default(), exported_proc_macros: FxHashMap::default(), prelude: None, @@ -461,6 +463,7 @@ impl DefMap { registered_tools, block: _, edition: _, + recursion_limit: _, krate: _, prelude: _, root: _, @@ -482,6 +485,10 @@ impl DefMap { pub fn diagnostics(&self) -> &[DefDiagnostic] { self.diagnostics.as_slice() } + + pub fn recursion_limit(&self) -> Option<u32> { + self.recursion_limit + } } impl ModuleData { diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index dc75dc4d91a..7f7213f4c3e 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs @@ -271,6 +271,17 @@ impl DefCollector<'_> { None => continue, }; + if *attr_name == hir_expand::name![recursion_limit] { + if let Some(input) = &attr.input { + if let AttrInput::Literal(limit) = &**input { + if let Ok(limit) = limit.parse() { + self.def_map.recursion_limit = Some(limit); + } + } + } + continue; + } + let attr_is_register_like = *attr_name == hir_expand::name![register_attr] || *attr_name == hir_expand::name![register_tool]; if !attr_is_register_like { diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index 4dcda0fcdc8..c36bd09e2b3 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs @@ -270,6 +270,7 @@ pub mod known { global_allocator, test, test_case, + recursion_limit, // Safe intrinsics abort, add_with_overflow, |
