1
Fork 0

Auto merge of #86674 - Aaron1011:new-querify-limits, r=michaelwoerister

Query-ify global limit attribute handling

Currently, we read various 'global limits' from inner attributes the crate root (`recursion_limit`, `move_size_limit`, `type_length_limit`, `const_eval_limit`). These limits are then stored in `Sessions`, allowing them to be access from a `TyCtxt` without registering a dependency on the crate root attributes.

This PR moves the calculation of these global limits behind queries, so that we properly track dependencies on crate root attributes. During the setup of macro expansion (before we've created a `TyCtxt`), we need to access the recursion limit, which is now done by directly calling into the code shared by the normal query implementations.
This commit is contained in:
bors 2021-07-05 16:30:53 +00:00
commit 969a6c2481
31 changed files with 173 additions and 91 deletions

View file

@ -211,10 +211,6 @@ pub fn register_plugins<'a>(
}); });
} }
sess.time("recursion_limit", || {
middle::limits::update_limits(sess, &krate);
});
let mut lint_store = rustc_lint::new_lint_store( let mut lint_store = rustc_lint::new_lint_store(
sess.opts.debugging_opts.no_interleave_lints, sess.opts.debugging_opts.no_interleave_lints,
sess.unstable_options(), sess.unstable_options(),
@ -311,9 +307,11 @@ pub fn configure_and_expand(
// Create the config for macro expansion // Create the config for macro expansion
let features = sess.features_untracked(); let features = sess.features_untracked();
let recursion_limit =
rustc_middle::middle::limits::get_recursion_limit(&krate.attrs, &sess);
let cfg = rustc_expand::expand::ExpansionConfig { let cfg = rustc_expand::expand::ExpansionConfig {
features: Some(&features), features: Some(&features),
recursion_limit: sess.recursion_limit(), recursion_limit,
trace_mac: sess.opts.debugging_opts.trace_macros, trace_mac: sess.opts.debugging_opts.trace_macros,
should_test: sess.opts.test, should_test: sess.opts.test,
span_debug: sess.opts.debugging_opts.span_debug, span_debug: sess.opts.debugging_opts.span_debug,
@ -872,6 +870,13 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
tcx.ensure().check_mod_unstable_api_usage(module); tcx.ensure().check_mod_unstable_api_usage(module);
tcx.ensure().check_mod_const_bodies(module); tcx.ensure().check_mod_const_bodies(module);
}); });
},
{
// We force these querie to run,
// since they might not otherwise get called.
// This marks the corresponding crate-level attributes
// as used, and ensures that their values are valid.
tcx.ensure().limits(());
} }
); );
}); });

View file

@ -245,6 +245,8 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
} }
} }
impl rustc_session::HashStableContext for StableHashingContext<'a> {}
pub fn hash_stable_trait_impls<'a>( pub fn hash_stable_trait_impls<'a>(
hcx: &mut StableHashingContext<'a>, hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher, hasher: &mut StableHasher,

View file

@ -10,38 +10,46 @@
//! just peeks and looks for that attribute. //! just peeks and looks for that attribute.
use crate::bug; use crate::bug;
use rustc_ast as ast; use crate::ty;
use rustc_data_structures::sync::OnceCell; use rustc_ast::Attribute;
use rustc_session::Session; use rustc_session::Session;
use rustc_session::{Limit, Limits};
use rustc_span::symbol::{sym, Symbol}; use rustc_span::symbol::{sym, Symbol};
use std::num::IntErrorKind; use std::num::IntErrorKind;
pub fn update_limits(sess: &Session, krate: &ast::Crate) { pub fn provide(providers: &mut ty::query::Providers) {
update_limit(sess, krate, &sess.recursion_limit, sym::recursion_limit, 128); providers.limits = |tcx, ()| Limits {
update_limit(sess, krate, &sess.move_size_limit, sym::move_size_limit, 0); recursion_limit: get_recursion_limit(tcx.hir().krate_attrs(), tcx.sess),
update_limit(sess, krate, &sess.type_length_limit, sym::type_length_limit, 1048576); move_size_limit: get_limit(tcx.hir().krate_attrs(), tcx.sess, sym::move_size_limit, 0),
update_limit(sess, krate, &sess.const_eval_limit, sym::const_eval_limit, 1_000_000); type_length_limit: get_limit(
tcx.hir().krate_attrs(),
tcx.sess,
sym::type_length_limit,
1048576,
),
const_eval_limit: get_limit(
tcx.hir().krate_attrs(),
tcx.sess,
sym::const_eval_limit,
1_000_000,
),
}
} }
fn update_limit( pub fn get_recursion_limit(krate_attrs: &[Attribute], sess: &Session) -> Limit {
sess: &Session, get_limit(krate_attrs, sess, sym::recursion_limit, 128)
krate: &ast::Crate, }
limit: &OnceCell<impl From<usize> + std::fmt::Debug>,
name: Symbol, fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: usize) -> Limit {
default: usize, for attr in krate_attrs {
) {
for attr in &krate.attrs {
if !sess.check_name(attr, name) { if !sess.check_name(attr, name) {
continue; continue;
} }
if let Some(s) = attr.value_str() { if let Some(s) = attr.value_str() {
match s.as_str().parse() { match s.as_str().parse() {
Ok(n) => { Ok(n) => return Limit::new(n),
limit.set(From::from(n)).unwrap();
return;
}
Err(e) => { Err(e) => {
let mut err = let mut err =
sess.struct_span_err(attr.span, "`limit` must be a non-negative integer"); sess.struct_span_err(attr.span, "`limit` must be a non-negative integer");
@ -68,5 +76,5 @@ fn update_limit(
} }
} }
} }
limit.set(From::from(default)).unwrap(); return Limit::new(default);
} }

View file

@ -32,3 +32,7 @@ pub mod privacy;
pub mod region; pub mod region;
pub mod resolve_lifetime; pub mod resolve_lifetime;
pub mod stability; pub mod stability;
pub fn provide(providers: &mut crate::ty::query::Providers) {
limits::provide(providers);
}

View file

@ -1725,4 +1725,8 @@ rustc_queries! {
query conservative_is_privately_uninhabited(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { query conservative_is_privately_uninhabited(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "conservatively checking if {:?} is privately uninhabited", key } desc { "conservatively checking if {:?} is privately uninhabited", key }
} }
query limits(key: ()) -> Limits {
desc { "looking up limits" }
}
} }

View file

@ -53,6 +53,7 @@ use rustc_middle::ty::OpaqueTypeKey;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
use rustc_session::lint::{Level, Lint}; use rustc_session::lint::{Level, Lint};
use rustc_session::Limit;
use rustc_session::Session; use rustc_session::Session;
use rustc_span::def_id::StableCrateId; use rustc_span::def_id::StableCrateId;
use rustc_span::source_map::MultiSpan; use rustc_span::source_map::MultiSpan;
@ -1569,6 +1570,22 @@ impl<'tcx> TyCtxt<'tcx> {
def_kind => (def_kind.article(), def_kind.descr(def_id)), def_kind => (def_kind.article(), def_kind.descr(def_id)),
} }
} }
pub fn type_length_limit(self) -> Limit {
self.limits(()).type_length_limit
}
pub fn recursion_limit(self) -> Limit {
self.limits(()).recursion_limit
}
pub fn move_size_limit(self) -> Limit {
self.limits(()).move_size_limit
}
pub fn const_eval_limit(self) -> Limit {
self.limits(()).const_eval_limit
}
} }
/// A trait implemented for all `X<'a>` types that can be safely and /// A trait implemented for all `X<'a>` types that can be safely and

View file

@ -221,7 +221,7 @@ fn layout_raw<'tcx>(
ty::tls::with_related_context(tcx, move |icx| { ty::tls::with_related_context(tcx, move |icx| {
let (param_env, ty) = query.into_parts(); let (param_env, ty) = query.into_parts();
if !tcx.sess.recursion_limit().value_within_limit(icx.layout_depth) { if !tcx.recursion_limit().value_within_limit(icx.layout_depth) {
tcx.sess.fatal(&format!("overflow representing the type `{}`", ty)); tcx.sess.fatal(&format!("overflow representing the type `{}`", ty));
} }

View file

@ -1987,6 +1987,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
util::provide(providers); util::provide(providers);
print::provide(providers); print::provide(providers);
super::util::bug::provide(providers); super::util::bug::provide(providers);
super::middle::provide(providers);
*providers = ty::query::Providers { *providers = ty::query::Providers {
trait_impls_of: trait_def::trait_impls_of_provider, trait_impls_of: trait_def::trait_impls_of_provider,
type_uninhabited_from: inhabitedness::type_uninhabited_from, type_uninhabited_from: inhabitedness::type_uninhabited_from,

View file

@ -1437,7 +1437,7 @@ impl<F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> {
} }
fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
let type_length_limit = self.tcx.sess.type_length_limit(); let type_length_limit = self.tcx.type_length_limit();
if type_length_limit.value_within_limit(self.printed_type_count) { if type_length_limit.value_within_limit(self.printed_type_count) {
self.printed_type_count += 1; self.printed_type_count += 1;
self.pretty_print_type(ty) self.pretty_print_type(ty)

View file

@ -49,6 +49,7 @@ use rustc_serialize::opaque;
use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
use rustc_session::utils::NativeLibKind; use rustc_session::utils::NativeLibKind;
use rustc_session::CrateDisambiguator; use rustc_session::CrateDisambiguator;
use rustc_session::Limits;
use rustc_target::spec::PanicStrategy; use rustc_target::spec::PanicStrategy;
use rustc_ast as ast; use rustc_ast as ast;

View file

@ -206,8 +206,9 @@ impl<'tcx> TyCtxt<'tcx> {
mut ty: Ty<'tcx>, mut ty: Ty<'tcx>,
normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>, normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let recursion_limit = self.recursion_limit();
for iteration in 0.. { for iteration in 0.. {
if !self.sess.recursion_limit().value_within_limit(iteration) { if !recursion_limit.value_within_limit(iteration) {
return self.ty_error_with_message( return self.ty_error_with_message(
DUMMY_SP, DUMMY_SP,
&format!("reached the recursion limit finding the struct tail for {}", ty), &format!("reached the recursion limit finding the struct tail for {}", ty),

View file

@ -98,7 +98,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
tcx, tcx,
root_span, root_span,
param_env, param_env,
CompileTimeInterpreter::new(tcx.sess.const_eval_limit()), CompileTimeInterpreter::new(tcx.const_eval_limit()),
MemoryExtra { can_access_statics }, MemoryExtra { can_access_statics },
) )
} }
@ -300,7 +300,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
tcx, tcx,
tcx.def_span(def.did), tcx.def_span(def.did),
key.param_env, key.param_env,
CompileTimeInterpreter::new(tcx.sess.const_eval_limit()), CompileTimeInterpreter::new(tcx.const_eval_limit()),
// Statics (and promoteds inside statics) may access other statics, because unlike consts // Statics (and promoteds inside statics) may access other statics, because unlike consts
// they do not have to behave "as if" they were evaluated at runtime. // they do not have to behave "as if" they were evaluated at runtime.
MemoryExtra { can_access_statics: is_static }, MemoryExtra { can_access_statics: is_static },

View file

@ -393,7 +393,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
frame: Frame<'mir, 'tcx>, frame: Frame<'mir, 'tcx>,
) -> InterpResult<'tcx, Frame<'mir, 'tcx>> { ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> {
// Enforce stack size limit. Add 1 because this is run before the new frame is pushed. // Enforce stack size limit. Add 1 because this is run before the new frame is pushed.
if !ecx.tcx.sess.recursion_limit().value_within_limit(ecx.stack().len() + 1) { if !ecx.recursion_limit.value_within_limit(ecx.stack().len() + 1) {
throw_exhaust!(StackFrameLimitReached) throw_exhaust!(StackFrameLimitReached)
} else { } else {
Ok(frame) Ok(frame)

View file

@ -13,6 +13,7 @@ use rustc_middle::ty::layout::{self, TyAndLayout};
use rustc_middle::ty::{ use rustc_middle::ty::{
self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
}; };
use rustc_session::Limit;
use rustc_span::{Pos, Span}; use rustc_span::{Pos, Span};
use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout}; use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
@ -39,6 +40,9 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
/// The virtual memory system. /// The virtual memory system.
pub memory: Memory<'mir, 'tcx, M>, pub memory: Memory<'mir, 'tcx, M>,
/// The recursion limit (cached from `tcx.recursion_limit(())`)
pub recursion_limit: Limit,
} }
// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread // The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
@ -388,6 +392,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
tcx: tcx.at(root_span), tcx: tcx.at(root_span),
param_env, param_env,
memory: Memory::new(tcx, memory_extra), memory: Memory::new(tcx, memory_extra),
recursion_limit: tcx.recursion_limit(),
} }
} }

View file

@ -200,6 +200,7 @@ use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFold
use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext}; use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
use rustc_session::config::EntryFnType; use rustc_session::config::EntryFnType;
use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
use rustc_session::Limit;
use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
use rustc_target::abi::Size; use rustc_target::abi::Size;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -294,6 +295,7 @@ pub fn collect_crate_mono_items(
let mut visited = MTLock::new(FxHashSet::default()); let mut visited = MTLock::new(FxHashSet::default());
let mut inlining_map = MTLock::new(InliningMap::new()); let mut inlining_map = MTLock::new(InliningMap::new());
let recursion_limit = tcx.recursion_limit();
{ {
let visited: MTRef<'_, _> = &mut visited; let visited: MTRef<'_, _> = &mut visited;
@ -307,6 +309,7 @@ pub fn collect_crate_mono_items(
dummy_spanned(root), dummy_spanned(root),
visited, visited,
&mut recursion_depths, &mut recursion_depths,
recursion_limit,
inlining_map, inlining_map,
); );
}); });
@ -350,6 +353,7 @@ fn collect_items_rec<'tcx>(
starting_point: Spanned<MonoItem<'tcx>>, starting_point: Spanned<MonoItem<'tcx>>,
visited: MTRef<'_, MTLock<FxHashSet<MonoItem<'tcx>>>>, visited: MTRef<'_, MTLock<FxHashSet<MonoItem<'tcx>>>>,
recursion_depths: &mut DefIdMap<usize>, recursion_depths: &mut DefIdMap<usize>,
recursion_limit: Limit,
inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>, inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>,
) { ) {
if !visited.lock_mut().insert(starting_point.node) { if !visited.lock_mut().insert(starting_point.node) {
@ -409,8 +413,13 @@ fn collect_items_rec<'tcx>(
debug_assert!(should_codegen_locally(tcx, &instance)); debug_assert!(should_codegen_locally(tcx, &instance));
// Keep track of the monomorphization recursion depth // Keep track of the monomorphization recursion depth
recursion_depth_reset = recursion_depth_reset = Some(check_recursion_limit(
Some(check_recursion_limit(tcx, instance, starting_point.span, recursion_depths)); tcx,
instance,
starting_point.span,
recursion_depths,
recursion_limit,
));
check_type_length_limit(tcx, instance); check_type_length_limit(tcx, instance);
rustc_data_structures::stack::ensure_sufficient_stack(|| { rustc_data_structures::stack::ensure_sufficient_stack(|| {
@ -455,7 +464,7 @@ fn collect_items_rec<'tcx>(
record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map); record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map);
for neighbour in neighbors { for neighbour in neighbors {
collect_items_rec(tcx, neighbour, visited, recursion_depths, inlining_map); collect_items_rec(tcx, neighbour, visited, recursion_depths, recursion_limit, inlining_map);
} }
if let Some((def_id, depth)) = recursion_depth_reset { if let Some((def_id, depth)) = recursion_depth_reset {
@ -523,6 +532,7 @@ fn check_recursion_limit<'tcx>(
instance: Instance<'tcx>, instance: Instance<'tcx>,
span: Span, span: Span,
recursion_depths: &mut DefIdMap<usize>, recursion_depths: &mut DefIdMap<usize>,
recursion_limit: Limit,
) -> (DefId, usize) { ) -> (DefId, usize) {
let def_id = instance.def_id(); let def_id = instance.def_id();
let recursion_depth = recursion_depths.get(&def_id).cloned().unwrap_or(0); let recursion_depth = recursion_depths.get(&def_id).cloned().unwrap_or(0);
@ -539,7 +549,7 @@ fn check_recursion_limit<'tcx>(
// Code that needs to instantiate the same function recursively // Code that needs to instantiate the same function recursively
// more than the recursion limit is assumed to be causing an // more than the recursion limit is assumed to be causing an
// infinite expansion. // infinite expansion.
if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) { if !recursion_limit.value_within_limit(adjusted_recursion_depth) {
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
let error = format!("reached the recursion limit while instantiating `{}`", shrunk); let error = format!("reached the recursion limit while instantiating `{}`", shrunk);
let mut err = tcx.sess.struct_span_fatal(span, &error); let mut err = tcx.sess.struct_span_fatal(span, &error);
@ -577,7 +587,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
// which means that rustc basically hangs. // which means that rustc basically hangs.
// //
// Bail out in these cases to avoid that bad user experience. // Bail out in these cases to avoid that bad user experience.
if !tcx.sess.type_length_limit().value_within_limit(type_length) { if !tcx.type_length_limit().value_within_limit(type_length) {
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
let msg = format!("reached the type-length limit while instantiating `{}`", shrunk); let msg = format!("reached the type-length limit while instantiating `{}`", shrunk);
let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg); let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg);
@ -814,7 +824,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
self.super_operand(operand, location); self.super_operand(operand, location);
let limit = self.tcx.sess.move_size_limit(); let limit = self.tcx.move_size_limit().0;
if limit == 0 { if limit == 0 {
return; return;
} }

View file

@ -5,6 +5,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::mir::TerminatorKind; use rustc_middle::mir::TerminatorKind;
use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, subst::SubstsRef, InstanceDef, TyCtxt}; use rustc_middle::ty::{self, subst::SubstsRef, InstanceDef, TyCtxt};
use rustc_session::Limit;
// FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking // FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking
// this query riddiculously often. // this query riddiculously often.
@ -30,7 +31,7 @@ crate fn mir_callgraph_reachable(
); );
#[instrument( #[instrument(
level = "debug", level = "debug",
skip(tcx, param_env, target, stack, seen, recursion_limiter, caller) skip(tcx, param_env, target, stack, seen, recursion_limiter, caller, recursion_limit)
)] )]
fn process( fn process(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
@ -40,6 +41,7 @@ crate fn mir_callgraph_reachable(
stack: &mut Vec<ty::Instance<'tcx>>, stack: &mut Vec<ty::Instance<'tcx>>,
seen: &mut FxHashSet<ty::Instance<'tcx>>, seen: &mut FxHashSet<ty::Instance<'tcx>>,
recursion_limiter: &mut FxHashMap<DefId, usize>, recursion_limiter: &mut FxHashMap<DefId, usize>,
recursion_limit: Limit,
) -> bool { ) -> bool {
trace!(%caller); trace!(%caller);
for &(callee, substs) in tcx.mir_inliner_callees(caller.def) { for &(callee, substs) in tcx.mir_inliner_callees(caller.def) {
@ -96,11 +98,20 @@ crate fn mir_callgraph_reachable(
if seen.insert(callee) { if seen.insert(callee) {
let recursion = recursion_limiter.entry(callee.def_id()).or_default(); let recursion = recursion_limiter.entry(callee.def_id()).or_default();
trace!(?callee, recursion = *recursion); trace!(?callee, recursion = *recursion);
if tcx.sess.recursion_limit().value_within_limit(*recursion) { if recursion_limit.value_within_limit(*recursion) {
*recursion += 1; *recursion += 1;
stack.push(callee); stack.push(callee);
let found_recursion = ensure_sufficient_stack(|| { let found_recursion = ensure_sufficient_stack(|| {
process(tcx, param_env, callee, target, stack, seen, recursion_limiter) process(
tcx,
param_env,
callee,
target,
stack,
seen,
recursion_limiter,
recursion_limit,
)
}); });
if found_recursion { if found_recursion {
return true; return true;
@ -122,6 +133,7 @@ crate fn mir_callgraph_reachable(
&mut Vec::new(), &mut Vec::new(),
&mut FxHashSet::default(), &mut FxHashSet::default(),
&mut FxHashMap::default(), &mut FxHashMap::default(),
tcx.recursion_limit(),
) )
} }

View file

@ -24,3 +24,8 @@ pub use session::*;
pub mod output; pub mod output;
pub use getopts; pub use getopts;
/// Requirements for a `StableHashingContext` to be used in this crate.
/// This is a hack to allow using the `HashStable_Generic` derive macro
/// instead of implementing everything in `rustc_middle`.
pub trait HashStableContext {}

View file

@ -22,6 +22,7 @@ use rustc_errors::json::JsonEmitter;
use rustc_errors::registry::Registry; use rustc_errors::registry::Registry;
use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported}; use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported};
use rustc_lint_defs::FutureBreakage; use rustc_lint_defs::FutureBreakage;
use rustc_macros::HashStable_Generic;
pub use rustc_span::crate_disambiguator::CrateDisambiguator; pub use rustc_span::crate_disambiguator::CrateDisambiguator;
use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span}; use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
use rustc_span::{edition::Edition, RealFileName}; use rustc_span::{edition::Edition, RealFileName};
@ -66,7 +67,7 @@ pub enum CtfeBacktrace {
/// New-type wrapper around `usize` for representing limits. Ensures that comparisons against /// New-type wrapper around `usize` for representing limits. Ensures that comparisons against
/// limits are consistent throughout the compiler. /// limits are consistent throughout the compiler.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, HashStable_Generic)]
pub struct Limit(pub usize); pub struct Limit(pub usize);
impl Limit { impl Limit {
@ -111,6 +112,20 @@ impl Mul<usize> for Limit {
} }
} }
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub struct Limits {
/// The maximum recursion limit for potentially infinitely recursive
/// operations such as auto-dereference and monomorphization.
pub recursion_limit: Limit,
/// The size at which the `large_assignments` lint starts
/// being emitted.
pub move_size_limit: Limit,
/// The maximum length of types during monomorphization.
pub type_length_limit: Limit,
/// The maximum blocks a const expression can evaluate.
pub const_eval_limit: Limit,
}
/// Represents the data associated with a compilation /// Represents the data associated with a compilation
/// session for a single crate. /// session for a single crate.
pub struct Session { pub struct Session {
@ -144,20 +159,6 @@ pub struct Session {
lint_store: OnceCell<Lrc<dyn SessionLintStore>>, lint_store: OnceCell<Lrc<dyn SessionLintStore>>,
/// The maximum recursion limit for potentially infinitely recursive
/// operations such as auto-dereference and monomorphization.
pub recursion_limit: OnceCell<Limit>,
/// The size at which the `large_assignments` lint starts
/// being emitted.
pub move_size_limit: OnceCell<usize>,
/// The maximum length of types during monomorphization.
pub type_length_limit: OnceCell<Limit>,
/// The maximum blocks a const expression can evaluate.
pub const_eval_limit: OnceCell<Limit>,
incr_comp_session: OneThread<RefCell<IncrCompSession>>, incr_comp_session: OneThread<RefCell<IncrCompSession>>,
/// Used for incremental compilation tests. Will only be populated if /// Used for incremental compilation tests. Will only be populated if
/// `-Zquery-dep-graph` is specified. /// `-Zquery-dep-graph` is specified.
@ -347,25 +348,6 @@ impl Session {
self.crate_types.set(crate_types).expect("`crate_types` was initialized twice") self.crate_types.set(crate_types).expect("`crate_types` was initialized twice")
} }
#[inline]
pub fn recursion_limit(&self) -> Limit {
self.recursion_limit.get().copied().unwrap()
}
#[inline]
pub fn move_size_limit(&self) -> usize {
self.move_size_limit.get().copied().unwrap()
}
#[inline]
pub fn type_length_limit(&self) -> Limit {
self.type_length_limit.get().copied().unwrap()
}
pub fn const_eval_limit(&self) -> Limit {
self.const_eval_limit.get().copied().unwrap()
}
pub fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'_> { pub fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'_> {
self.diagnostic().struct_span_warn(sp, msg) self.diagnostic().struct_span_warn(sp, msg)
} }
@ -1391,10 +1373,6 @@ pub fn build_session(
crate_disambiguator: OnceCell::new(), crate_disambiguator: OnceCell::new(),
features: OnceCell::new(), features: OnceCell::new(),
lint_store: OnceCell::new(), lint_store: OnceCell::new(),
recursion_limit: OnceCell::new(),
move_size_limit: OnceCell::new(),
type_length_limit: OnceCell::new(),
const_eval_limit: OnceCell::new(),
incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
cgu_reuse_tracker, cgu_reuse_tracker,
prof, prof,

View file

@ -53,7 +53,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
} }
// If we have reached the recursion limit, error gracefully. // If we have reached the recursion limit, error gracefully.
if !tcx.sess.recursion_limit().value_within_limit(self.state.steps.len()) { if !tcx.recursion_limit().value_within_limit(self.state.steps.len()) {
if !self.silence_errors { if !self.silence_errors {
report_autoderef_recursion_limit_error(tcx, self.span, self.state.cur_ty); report_autoderef_recursion_limit_error(tcx, self.span, self.state.cur_ty);
} }
@ -217,7 +217,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
// We've reached the recursion limit, error gracefully. // We've reached the recursion limit, error gracefully.
let suggested_limit = tcx.sess.recursion_limit() * 2; let suggested_limit = tcx.recursion_limit() * 2;
let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty); let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty);
let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg); let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);

View file

@ -2310,7 +2310,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
} }
fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) { fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) {
let current_limit = self.tcx.sess.recursion_limit(); let current_limit = self.tcx.recursion_limit();
let suggested_limit = current_limit * 2; let suggested_limit = current_limit * 2;
err.help(&format!( err.help(&format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",

View file

@ -344,7 +344,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
Reveal::UserFacing => ty, Reveal::UserFacing => ty,
Reveal::All => { Reveal::All => {
let recursion_limit = self.tcx().sess.recursion_limit(); let recursion_limit = self.tcx().recursion_limit();
if !recursion_limit.value_within_limit(self.depth) { if !recursion_limit.value_within_limit(self.depth) {
let obligation = Obligation::with_depth( let obligation = Obligation::with_depth(
self.cause.clone(), self.cause.clone(),
@ -726,7 +726,7 @@ fn project_type<'cx, 'tcx>(
) -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>> { ) -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>> {
debug!(?obligation, "project_type"); debug!(?obligation, "project_type");
if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) { if !selcx.tcx().recursion_limit().value_within_limit(obligation.recursion_depth) {
debug!("project: overflow!"); debug!("project: overflow!");
// This should really be an immediate error, but some existing code // This should really be an immediate error, but some existing code
// relies on being able to recover from this. // relies on being able to recover from this.

View file

@ -116,7 +116,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
Reveal::UserFacing => ty, Reveal::UserFacing => ty,
Reveal::All => { Reveal::All => {
let recursion_limit = self.tcx().sess.recursion_limit(); let recursion_limit = self.tcx().recursion_limit();
if !recursion_limit.value_within_limit(self.anon_depth) { if !recursion_limit.value_within_limit(self.anon_depth) {
let obligation = Obligation::with_depth( let obligation = Obligation::with_depth(
self.cause.clone(), self.cause.clone(),

View file

@ -993,7 +993,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &Obligation<'tcx, T>, obligation: &Obligation<'tcx, T>,
error_obligation: &Obligation<'tcx, V>, error_obligation: &Obligation<'tcx, V>,
) -> Result<(), OverflowError> { ) -> Result<(), OverflowError> {
if !self.infcx.tcx.sess.recursion_limit().value_within_limit(obligation.recursion_depth) { if !self.infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) {
match self.query_mode { match self.query_mode {
TraitQueryMode::Standard => { TraitQueryMode::Standard => {
self.infcx().report_overflow_error(error_obligation, true); self.infcx().report_overflow_error(error_obligation, true);

View file

@ -163,7 +163,7 @@ fn dtorck_constraint_for_ty<'tcx>(
) -> Result<(), NoSolution> { ) -> Result<(), NoSolution> {
debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty); debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty);
if !tcx.sess.recursion_limit().value_within_limit(depth) { if !tcx.recursion_limit().value_within_limit(depth) {
constraints.overflows.push(ty); constraints.overflows.push(ty);
return Ok(()); return Ok(());
} }

View file

@ -63,7 +63,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> {
seen_tys, seen_tys,
query_ty: ty, query_ty: ty,
unchecked_tys: vec![(ty, 0)], unchecked_tys: vec![(ty, 0)],
recursion_limit: tcx.sess.recursion_limit(), recursion_limit: tcx.recursion_limit(),
adt_components, adt_components,
} }
} }

View file

@ -2,5 +2,7 @@
#![recursion_limit = ""] //~ ERROR `limit` must be a non-negative integer #![recursion_limit = ""] //~ ERROR `limit` must be a non-negative integer
//~| `limit` must be a non-negative integer //~| `limit` must be a non-negative integer
//~| ERROR `limit` must be a non-negative integer
//~| `limit` must be a non-negative integer
fn main() {} fn main() {}

View file

@ -6,5 +6,13 @@ LL | #![recursion_limit = ""]
| | | |
| `limit` must be a non-negative integer | `limit` must be a non-negative integer
error: aborting due to previous error error: `limit` must be a non-negative integer
--> $DIR/empty.rs:3:1
|
LL | #![recursion_limit = ""]
| ^^^^^^^^^^^^^^^^^^^^^--^
| |
| `limit` must be a non-negative integer
error: aborting due to 2 previous errors

View file

@ -2,5 +2,6 @@
#![recursion_limit = "-100"] //~ ERROR `limit` must be a non-negative integer #![recursion_limit = "-100"] //~ ERROR `limit` must be a non-negative integer
//~| not a valid integer //~| not a valid integer
//~| ERROR `limit` must be a non-negative integer
//~| not a valid integer
fn main() {} fn main() {}

View file

@ -6,5 +6,13 @@ LL | #![recursion_limit = "-100"]
| | | |
| not a valid integer | not a valid integer
error: aborting due to previous error error: `limit` must be a non-negative integer
--> $DIR/invalid_digit.rs:3:1
|
LL | #![recursion_limit = "-100"]
| ^^^^^^^^^^^^^^^^^^^^^------^
| |
| not a valid integer
error: aborting due to 2 previous errors

View file

@ -3,5 +3,7 @@
#![recursion_limit = "999999999999999999999999"] #![recursion_limit = "999999999999999999999999"]
//~^ ERROR `limit` must be a non-negative integer //~^ ERROR `limit` must be a non-negative integer
//~| `limit` is too large //~| `limit` is too large
//~| ERROR `limit` must be a non-negative integer
//~| `limit` is too large
fn main() {} fn main() {}

View file

@ -6,5 +6,13 @@ LL | #![recursion_limit = "999999999999999999999999"]
| | | |
| `limit` is too large | `limit` is too large
error: aborting due to previous error error: `limit` must be a non-negative integer
--> $DIR/overflow.rs:3:1
|
LL | #![recursion_limit = "999999999999999999999999"]
| ^^^^^^^^^^^^^^^^^^^^^--------------------------^
| |
| `limit` is too large
error: aborting due to 2 previous errors