diff options
author | Aleksey Kladov <[email protected]> | 2020-07-11 17:35:35 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-07-11 17:39:49 +0100 |
commit | a8891ae3ca1f23ef310a91b2e30bac7e08be4aa1 (patch) | |
tree | 8717f26bc20300c1eaf37baba97bb0f80dd69208 /crates/ra_hir_def | |
parent | c884ceb31c2761a9eb7de8754c4be4cc47469dee (diff) |
More tight recursion limit when expanding macros in function bodies
cc #4944
cc #5317
This doesn't fully close #4944 -- looks like we hit SO in syntax
highlighting, when we use `Semantics::expand_macro`.
Seems like we need to place expansion limit on the macro itself (store
it as a part of MacroCallId?)!
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 54 |
1 files changed, 48 insertions, 6 deletions
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 031ffe13f..8c233a717 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -14,6 +14,7 @@ use ra_db::CrateId; | |||
14 | use ra_prof::profile; | 14 | use ra_prof::profile; |
15 | use ra_syntax::{ast, AstNode, AstPtr}; | 15 | use ra_syntax::{ast, AstNode, AstPtr}; |
16 | use rustc_hash::FxHashMap; | 16 | use rustc_hash::FxHashMap; |
17 | use test_utils::mark; | ||
17 | 18 | ||
18 | pub(crate) use lower::LowerCtx; | 19 | pub(crate) use lower::LowerCtx; |
19 | 20 | ||
@@ -42,7 +43,7 @@ pub(crate) struct Expander { | |||
42 | current_file_id: HirFileId, | 43 | current_file_id: HirFileId, |
43 | ast_id_map: Arc<AstIdMap>, | 44 | ast_id_map: Arc<AstIdMap>, |
44 | module: ModuleId, | 45 | module: ModuleId, |
45 | recursive_limit: usize, | 46 | recursion_limit: usize, |
46 | } | 47 | } |
47 | 48 | ||
48 | impl CfgExpander { | 49 | impl CfgExpander { |
@@ -81,7 +82,7 @@ impl Expander { | |||
81 | current_file_id, | 82 | current_file_id, |
82 | ast_id_map, | 83 | ast_id_map, |
83 | module, | 84 | module, |
84 | recursive_limit: 0, | 85 | recursion_limit: 0, |
85 | } | 86 | } |
86 | } | 87 | } |
87 | 88 | ||
@@ -91,7 +92,9 @@ impl Expander { | |||
91 | local_scope: Option<&ItemScope>, | 92 | local_scope: Option<&ItemScope>, |
92 | macro_call: ast::MacroCall, | 93 | macro_call: ast::MacroCall, |
93 | ) -> Option<(Mark, T)> { | 94 | ) -> Option<(Mark, T)> { |
94 | if self.recursive_limit > 1024 { | 95 | self.recursion_limit += 1; |
96 | if self.recursion_limit > 32 { | ||
97 | mark::hit!(your_stack_belongs_to_me); | ||
95 | return None; | 98 | return None; |
96 | } | 99 | } |
97 | 100 | ||
@@ -118,8 +121,6 @@ impl Expander { | |||
118 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); | 121 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); |
119 | self.current_file_id = file_id; | 122 | self.current_file_id = file_id; |
120 | self.ast_id_map = db.ast_id_map(file_id); | 123 | self.ast_id_map = db.ast_id_map(file_id); |
121 | self.recursive_limit += 1; | ||
122 | |||
123 | return Some((mark, expr)); | 124 | return Some((mark, expr)); |
124 | } | 125 | } |
125 | } | 126 | } |
@@ -134,7 +135,7 @@ impl Expander { | |||
134 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); | 135 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); |
135 | self.current_file_id = mark.file_id; | 136 | self.current_file_id = mark.file_id; |
136 | self.ast_id_map = mem::take(&mut mark.ast_id_map); | 137 | self.ast_id_map = mem::take(&mut mark.ast_id_map); |
137 | self.recursive_limit -= 1; | 138 | self.recursion_limit -= 1; |
138 | mark.bomb.defuse(); | 139 | mark.bomb.defuse(); |
139 | } | 140 | } |
140 | 141 | ||
@@ -311,3 +312,44 @@ impl BodySourceMap { | |||
311 | self.field_map[&(expr, field)].clone() | 312 | self.field_map[&(expr, field)].clone() |
312 | } | 313 | } |
313 | } | 314 | } |
315 | |||
316 | #[cfg(test)] | ||
317 | mod tests { | ||
318 | use ra_db::{fixture::WithFixture, SourceDatabase}; | ||
319 | use test_utils::mark; | ||
320 | |||
321 | use crate::ModuleDefId; | ||
322 | |||
323 | use super::*; | ||
324 | |||
325 | fn lower(ra_fixture: &str) -> Arc<Body> { | ||
326 | let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture); | ||
327 | |||
328 | let krate = db.crate_graph().iter().next().unwrap(); | ||
329 | let def_map = db.crate_def_map(krate); | ||
330 | let module = def_map.modules_for_file(file_id).next().unwrap(); | ||
331 | let module = &def_map[module]; | ||
332 | let fn_def = match module.scope.declarations().next().unwrap() { | ||
333 | ModuleDefId::FunctionId(it) => it, | ||
334 | _ => panic!(), | ||
335 | }; | ||
336 | |||
337 | db.body(fn_def.into()) | ||
338 | } | ||
339 | |||
340 | #[test] | ||
341 | fn your_stack_belongs_to_me() { | ||
342 | mark::check!(your_stack_belongs_to_me); | ||
343 | lower( | ||
344 | r" | ||
345 | macro_rules! n_nuple { | ||
346 | ($e:tt) => (); | ||
347 | ($($rest:tt)*) => {{ | ||
348 | (n_nuple!($($rest)*)None,) | ||
349 | }}; | ||
350 | } | ||
351 | fn main() { n_nuple!(1,2,3); } | ||
352 | ", | ||
353 | ); | ||
354 | } | ||
355 | } | ||