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?)!
This commit is contained in:
Aleksey Kladov 2020-07-11 18:35:35 +02:00
parent c884ceb31c
commit a8891ae3ca

View file

@ -14,6 +14,7 @@ use ra_db::CrateId;
use ra_prof::profile; use ra_prof::profile;
use ra_syntax::{ast, AstNode, AstPtr}; use ra_syntax::{ast, AstNode, AstPtr};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use test_utils::mark;
pub(crate) use lower::LowerCtx; pub(crate) use lower::LowerCtx;
@ -42,7 +43,7 @@ pub(crate) struct Expander {
current_file_id: HirFileId, current_file_id: HirFileId,
ast_id_map: Arc<AstIdMap>, ast_id_map: Arc<AstIdMap>,
module: ModuleId, module: ModuleId,
recursive_limit: usize, recursion_limit: usize,
} }
impl CfgExpander { impl CfgExpander {
@ -81,7 +82,7 @@ impl Expander {
current_file_id, current_file_id,
ast_id_map, ast_id_map,
module, module,
recursive_limit: 0, recursion_limit: 0,
} }
} }
@ -91,7 +92,9 @@ impl Expander {
local_scope: Option<&ItemScope>, local_scope: Option<&ItemScope>,
macro_call: ast::MacroCall, macro_call: ast::MacroCall,
) -> Option<(Mark, T)> { ) -> Option<(Mark, T)> {
if self.recursive_limit > 1024 { self.recursion_limit += 1;
if self.recursion_limit > 32 {
mark::hit!(your_stack_belongs_to_me);
return None; return None;
} }
@ -118,8 +121,6 @@ impl Expander {
self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
self.current_file_id = file_id; self.current_file_id = file_id;
self.ast_id_map = db.ast_id_map(file_id); self.ast_id_map = db.ast_id_map(file_id);
self.recursive_limit += 1;
return Some((mark, expr)); return Some((mark, expr));
} }
} }
@ -134,7 +135,7 @@ impl Expander {
self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
self.current_file_id = mark.file_id; self.current_file_id = mark.file_id;
self.ast_id_map = mem::take(&mut mark.ast_id_map); self.ast_id_map = mem::take(&mut mark.ast_id_map);
self.recursive_limit -= 1; self.recursion_limit -= 1;
mark.bomb.defuse(); mark.bomb.defuse();
} }
@ -311,3 +312,44 @@ impl BodySourceMap {
self.field_map[&(expr, field)].clone() self.field_map[&(expr, field)].clone()
} }
} }
#[cfg(test)]
mod tests {
use ra_db::{fixture::WithFixture, SourceDatabase};
use test_utils::mark;
use crate::ModuleDefId;
use super::*;
fn lower(ra_fixture: &str) -> Arc<Body> {
let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture);
let krate = db.crate_graph().iter().next().unwrap();
let def_map = db.crate_def_map(krate);
let module = def_map.modules_for_file(file_id).next().unwrap();
let module = &def_map[module];
let fn_def = match module.scope.declarations().next().unwrap() {
ModuleDefId::FunctionId(it) => it,
_ => panic!(),
};
db.body(fn_def.into())
}
#[test]
fn your_stack_belongs_to_me() {
mark::check!(your_stack_belongs_to_me);
lower(
r"
macro_rules! n_nuple {
($e:tt) => ();
($($rest:tt)*) => {{
(n_nuple!($($rest)*)None,)
}};
}
fn main() { n_nuple!(1,2,3); }
",
);
}
}