mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-17 22:46:50 +00:00
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>
This commit is contained in:
commit
cd6521e5de
@ -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)]
|
||||
|
@ -61,6 +61,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.
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -270,6 +270,7 @@ pub mod known {
|
||||
global_allocator,
|
||||
test,
|
||||
test_case,
|
||||
recursion_limit,
|
||||
// Safe intrinsics
|
||||
abort,
|
||||
add_with_overflow,
|
||||
|
Loading…
Reference in New Issue
Block a user