mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #103877 - oli-obk:const_eval_step_limit, r=fee1-dead
Replace const eval limit by a lint and add an exponential backoff warning The lint triggers at the first power of 2 that comes after 1 million function calls or traversed back-edges (takes less than a second on usual programs). After the first emission, an unsilenceable warning is repeated at every following power of 2 terminators, causing it to get reported less and less the longer the evaluation runs. cc `@rust-lang/wg-const-eval` fixes #93481 closes #67217
This commit is contained in:
commit
23f93a1266
@ -10,6 +10,12 @@ const_eval_interior_mutable_data_refer =
|
||||
This would make multiple uses of a constant to be able to see different values and allow circumventing
|
||||
the `Send` and `Sync` requirements for shared mutable data, which is unsound.
|
||||
|
||||
const_eval_long_running =
|
||||
constant evaluation is taking a long time
|
||||
.note = this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
|
||||
If your compilation actually takes a long time, you can safely allow the lint.
|
||||
.label = the const evaluator is currently interpreting this expression
|
||||
.help = the constant being evaluated
|
||||
const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
|
||||
|
||||
const_eval_mut_deref =
|
||||
|
@ -103,7 +103,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
|
||||
tcx,
|
||||
root_span,
|
||||
param_env,
|
||||
CompileTimeInterpreter::new(tcx.const_eval_limit(), can_access_statics, CheckAlignment::No),
|
||||
CompileTimeInterpreter::new(can_access_statics, CheckAlignment::No),
|
||||
)
|
||||
}
|
||||
|
||||
@ -306,7 +306,6 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
||||
// 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.
|
||||
CompileTimeInterpreter::new(
|
||||
tcx.const_eval_limit(),
|
||||
/*can_access_statics:*/ is_static,
|
||||
if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
|
||||
CheckAlignment::Error
|
||||
|
@ -16,11 +16,11 @@ use std::fmt;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::AssertMessage;
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_target::abi::{Align, Size};
|
||||
use rustc_target::spec::abi::Abi as CallAbi;
|
||||
|
||||
use crate::errors::{LongRunning, LongRunningWarn};
|
||||
use crate::interpret::{
|
||||
self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx,
|
||||
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
|
||||
@ -28,13 +28,24 @@ use crate::interpret::{
|
||||
|
||||
use super::error::*;
|
||||
|
||||
/// When hitting this many interpreted terminators we emit a deny by default lint
|
||||
/// that notfies the user that their constant takes a long time to evaluate. If that's
|
||||
/// what they intended, they can just allow the lint.
|
||||
const LINT_TERMINATOR_LIMIT: usize = 2_000_000;
|
||||
/// The limit used by `-Z tiny-const-eval-limit`. This smaller limit is useful for internal
|
||||
/// tests not needing to run 30s or more to show some behaviour.
|
||||
const TINY_LINT_TERMINATOR_LIMIT: usize = 20;
|
||||
/// After this many interpreted terminators, we start emitting progress indicators at every
|
||||
/// power of two of interpreted terminators.
|
||||
const PROGRESS_INDICATOR_START: usize = 4_000_000;
|
||||
|
||||
/// Extra machine state for CTFE, and the Machine instance
|
||||
pub struct CompileTimeInterpreter<'mir, 'tcx> {
|
||||
/// For now, the number of terminators that can be evaluated before we throw a resource
|
||||
/// exhaustion error.
|
||||
/// The number of terminators that have been evaluated.
|
||||
///
|
||||
/// Setting this to `0` disables the limit and allows the interpreter to run forever.
|
||||
pub(super) steps_remaining: usize,
|
||||
/// This is used to produce lints informing the user that the compiler is not stuck.
|
||||
/// Set to `usize::MAX` to never report anything.
|
||||
pub(super) num_evaluated_steps: usize,
|
||||
|
||||
/// The virtual call stack.
|
||||
pub(super) stack: Vec<Frame<'mir, 'tcx, AllocId, ()>>,
|
||||
@ -72,13 +83,9 @@ impl CheckAlignment {
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
|
||||
pub(crate) fn new(
|
||||
const_eval_limit: Limit,
|
||||
can_access_statics: bool,
|
||||
check_alignment: CheckAlignment,
|
||||
) -> Self {
|
||||
pub(crate) fn new(can_access_statics: bool, check_alignment: CheckAlignment) -> Self {
|
||||
CompileTimeInterpreter {
|
||||
steps_remaining: const_eval_limit.0,
|
||||
num_evaluated_steps: 0,
|
||||
stack: Vec::new(),
|
||||
can_access_statics,
|
||||
check_alignment,
|
||||
@ -569,13 +576,54 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||
|
||||
fn increment_const_eval_counter(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
|
||||
// The step limit has already been hit in a previous call to `increment_const_eval_counter`.
|
||||
if ecx.machine.steps_remaining == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
ecx.machine.steps_remaining -= 1;
|
||||
if ecx.machine.steps_remaining == 0 {
|
||||
throw_exhaust!(StepLimitReached)
|
||||
if let Some(new_steps) = ecx.machine.num_evaluated_steps.checked_add(1) {
|
||||
let (limit, start) = if ecx.tcx.sess.opts.unstable_opts.tiny_const_eval_limit {
|
||||
(TINY_LINT_TERMINATOR_LIMIT, TINY_LINT_TERMINATOR_LIMIT)
|
||||
} else {
|
||||
(LINT_TERMINATOR_LIMIT, PROGRESS_INDICATOR_START)
|
||||
};
|
||||
|
||||
ecx.machine.num_evaluated_steps = new_steps;
|
||||
// By default, we have a *deny* lint kicking in after some time
|
||||
// to ensure `loop {}` doesn't just go forever.
|
||||
// In case that lint got reduced, in particular for `--cap-lint` situations, we also
|
||||
// have a hard warning shown every now and then for really long executions.
|
||||
if new_steps == limit {
|
||||
// By default, we stop after a million steps, but the user can disable this lint
|
||||
// to be able to run until the heat death of the universe or power loss, whichever
|
||||
// comes first.
|
||||
let hir_id = ecx.best_lint_scope();
|
||||
let is_error = ecx
|
||||
.tcx
|
||||
.lint_level_at_node(
|
||||
rustc_session::lint::builtin::LONG_RUNNING_CONST_EVAL,
|
||||
hir_id,
|
||||
)
|
||||
.0
|
||||
.is_error();
|
||||
let span = ecx.cur_span();
|
||||
ecx.tcx.emit_spanned_lint(
|
||||
rustc_session::lint::builtin::LONG_RUNNING_CONST_EVAL,
|
||||
hir_id,
|
||||
span,
|
||||
LongRunning { item_span: ecx.tcx.span },
|
||||
);
|
||||
// If this was a hard error, don't bother continuing evaluation.
|
||||
if is_error {
|
||||
let guard = ecx
|
||||
.tcx
|
||||
.sess
|
||||
.delay_span_bug(span, "The deny lint should have already errored");
|
||||
throw_inval!(AlreadyReported(guard.into()));
|
||||
}
|
||||
} else if new_steps > start && new_steps.is_power_of_two() {
|
||||
// Only report after a certain number of terminators have been evaluated and the
|
||||
// current number of evaluated terminators is a power of 2. The latter gives us a cheap
|
||||
// way to implement exponential backoff.
|
||||
let span = ecx.cur_span();
|
||||
ecx.tcx.sess.emit_warning(LongRunningWarn { span, item_span: ecx.tcx.span });
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1,5 +1,5 @@
|
||||
use rustc_hir::ConstContext;
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic};
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
@ -194,3 +194,21 @@ pub(crate) struct InteriorMutabilityBorrow {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(const_eval_long_running)]
|
||||
#[note]
|
||||
pub struct LongRunning {
|
||||
#[help]
|
||||
pub item_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_long_running)]
|
||||
pub struct LongRunningWarn {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[help]
|
||||
pub item_span: Span,
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use std::mem;
|
||||
|
||||
use either::{Either, Left, Right};
|
||||
|
||||
use hir::CRATE_HIR_ID;
|
||||
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir;
|
||||
@ -405,6 +406,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
self.stack().last().map_or(self.tcx.span, |f| f.current_span())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
/// Find the first stack frame that is within the current crate, if any, otherwise return the crate's HirId
|
||||
pub fn best_lint_scope(&self) -> hir::HirId {
|
||||
self.stack()
|
||||
.iter()
|
||||
.find_map(|frame| frame.body.source.def_id().as_local())
|
||||
.map_or(CRATE_HIR_ID, |def_id| self.tcx.hir().local_def_id_to_hir_id(def_id))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] {
|
||||
M::stack(self)
|
||||
|
@ -1,6 +1,5 @@
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement};
|
||||
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_session::Limit;
|
||||
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
|
||||
|
||||
use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
|
||||
@ -45,11 +44,8 @@ fn might_permit_raw_init_strict<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
kind: ValidityRequirement,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
let machine = CompileTimeInterpreter::new(
|
||||
Limit::new(0),
|
||||
/*can_access_statics:*/ false,
|
||||
CheckAlignment::Error,
|
||||
);
|
||||
let machine =
|
||||
CompileTimeInterpreter::new(/*can_access_statics:*/ false, CheckAlignment::Error);
|
||||
|
||||
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
|
||||
|
||||
|
@ -351,8 +351,6 @@ declare_features! (
|
||||
(active, const_async_blocks, "1.53.0", Some(85368), None),
|
||||
/// Allows `const || {}` closures in const contexts.
|
||||
(incomplete, const_closures, "1.68.0", Some(106003), None),
|
||||
/// Allows limiting the evaluation steps of const expressions
|
||||
(active, const_eval_limit, "1.43.0", Some(67217), None),
|
||||
/// Allows the definition of `const extern fn` and `const unsafe extern fn`.
|
||||
(active, const_extern_fn, "1.40.0", Some(64926), None),
|
||||
/// Allows basic arithmetic on floating point types in a `const fn`.
|
||||
|
@ -355,10 +355,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
// Limits:
|
||||
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
|
||||
ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
|
||||
gated!(
|
||||
const_eval_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
|
||||
const_eval_limit, experimental!(const_eval_limit)
|
||||
),
|
||||
gated!(
|
||||
move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
|
||||
large_assignments, experimental!(move_size_limit)
|
||||
|
@ -59,8 +59,10 @@ declare_features! (
|
||||
/// Allows comparing raw pointers during const eval.
|
||||
(removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
|
||||
Some("cannot be allowed in const eval in any meaningful way")),
|
||||
/// Allows limiting the evaluation steps of const expressions
|
||||
(removed, const_eval_limit, "1.43.0", Some(67217), None, Some("removed the limit entirely")),
|
||||
/// Allows non-trivial generic constants which have to be manually propagated upwards.
|
||||
(removed, const_evaluatable_checked, "1.48.0", Some(76560), None, Some("renamed to `generic_const_exprs`")),
|
||||
(removed, const_evaluatable_checked, "1.48.0", Some(76560), None, Some("renamed to `generic_const_exprs`")),
|
||||
/// Allows the definition of `const` functions with some advanced features.
|
||||
(removed, const_fn, "1.54.0", Some(57563), None,
|
||||
Some("split into finer-grained feature gates")),
|
||||
|
@ -3357,6 +3357,7 @@ declare_lint_pass! {
|
||||
LARGE_ASSIGNMENTS,
|
||||
LATE_BOUND_LIFETIME_ARGUMENTS,
|
||||
LEGACY_DERIVE_HELPERS,
|
||||
LONG_RUNNING_CONST_EVAL,
|
||||
LOSSY_PROVENANCE_CASTS,
|
||||
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
|
||||
MACRO_USE_EXTERN_CRATE,
|
||||
@ -3426,6 +3427,43 @@ declare_lint_pass! {
|
||||
]
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `long_running_const_eval` lint is emitted when const
|
||||
/// eval is running for a long time to ensure rustc terminates
|
||||
/// even if you accidentally wrote an infinite loop.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// const FOO: () = loop {};
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Loops allow const evaluation to compute arbitrary code, but may also
|
||||
/// cause infinite loops or just very long running computations.
|
||||
/// Users can enable long running computations by allowing the lint
|
||||
/// on individual constants or for entire crates.
|
||||
///
|
||||
/// ### Unconditional warnings
|
||||
///
|
||||
/// Note that regardless of whether the lint is allowed or set to warn,
|
||||
/// the compiler will issue warnings if constant evaluation runs significantly
|
||||
/// longer than this lint's limit. These warnings are also shown to downstream
|
||||
/// users from crates.io or similar registries. If you are above the lint's limit,
|
||||
/// both you and downstream users might be exposed to these warnings.
|
||||
/// They might also appear on compiler updates, as the compiler makes minor changes
|
||||
/// about how complexity is measured: staying below the limit ensures that there
|
||||
/// is enough room, and given that the lint is disabled for people who use your
|
||||
/// dependency it means you will be the only one to get the warning and can put
|
||||
/// out an update in your own time.
|
||||
pub LONG_RUNNING_CONST_EVAL,
|
||||
Deny,
|
||||
"detects long const eval operations"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unused_doc_comments` lint detects doc comments that aren't used
|
||||
/// by `rustdoc`.
|
||||
|
@ -1,8 +1,7 @@
|
||||
//! Registering limits:
|
||||
//! * recursion_limit,
|
||||
//! * move_size_limit,
|
||||
//! * type_length_limit, and
|
||||
//! * const_eval_limit
|
||||
//! * move_size_limit, and
|
||||
//! * type_length_limit
|
||||
//!
|
||||
//! There are various parts of the compiler that must impose arbitrary limits
|
||||
//! on how deeply they recurse to prevent stack overflow. Users can override
|
||||
@ -34,12 +33,6 @@ pub fn provide(providers: &mut Providers) {
|
||||
sym::type_length_limit,
|
||||
1048576,
|
||||
),
|
||||
const_eval_limit: get_limit(
|
||||
tcx.hir().krate_attrs(),
|
||||
tcx.sess,
|
||||
sym::const_eval_limit,
|
||||
2_000_000,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -465,10 +465,6 @@ impl fmt::Display for UnsupportedOpInfo {
|
||||
pub enum ResourceExhaustionInfo {
|
||||
/// The stack grew too big.
|
||||
StackFrameLimitReached,
|
||||
/// The program ran for too long.
|
||||
///
|
||||
/// The exact limit is set by the `const_eval_limit` attribute.
|
||||
StepLimitReached,
|
||||
/// There is not enough memory (on the host) to perform an allocation.
|
||||
MemoryExhausted,
|
||||
/// The address space (of the target) is full.
|
||||
@ -482,9 +478,6 @@ impl fmt::Display for ResourceExhaustionInfo {
|
||||
StackFrameLimitReached => {
|
||||
write!(f, "reached the configured maximum number of stack frames")
|
||||
}
|
||||
StepLimitReached => {
|
||||
write!(f, "exceeded interpreter step limit (see `#[const_eval_limit]`)")
|
||||
}
|
||||
MemoryExhausted => {
|
||||
write!(f, "tried to allocate more memory than available to compiler")
|
||||
}
|
||||
|
@ -82,8 +82,6 @@ use std::iter;
|
||||
use std::mem;
|
||||
use std::ops::{Bound, Deref};
|
||||
|
||||
const TINY_CONST_EVAL_LIMIT: Limit = Limit(20);
|
||||
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
type AdtDef = ty::AdtDef<'tcx>;
|
||||
@ -1178,14 +1176,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
self.limits(()).move_size_limit
|
||||
}
|
||||
|
||||
pub fn const_eval_limit(self) -> Limit {
|
||||
if self.sess.opts.unstable_opts.tiny_const_eval_limit {
|
||||
TINY_CONST_EVAL_LIMIT
|
||||
} else {
|
||||
self.limits(()).const_eval_limit
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx {
|
||||
iter::once(LOCAL_CRATE)
|
||||
.chain(self.crates(()).iter().copied())
|
||||
|
@ -128,8 +128,6 @@ pub struct Limits {
|
||||
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,
|
||||
}
|
||||
|
||||
pub struct CompilerIO {
|
||||
|
@ -55,7 +55,7 @@ RUN ./build-clang.sh
|
||||
ENV CC=clang CXX=clang++
|
||||
|
||||
# rustc-perf version from 2023-03-15
|
||||
ENV PERF_COMMIT 9dfaa35193154b690922347ee1141a06ec87a199
|
||||
ENV PERF_COMMIT 8b2ac3042e1ff2c0074455a0a3618adef97156b1
|
||||
RUN curl -LS -o perf.zip https://github.com/rust-lang/rustc-perf/archive/$PERF_COMMIT.zip && \
|
||||
unzip perf.zip && \
|
||||
mv rustc-perf-$PERF_COMMIT rustc-perf && \
|
||||
|
@ -175,7 +175,7 @@ class WindowsPipeline(Pipeline):
|
||||
|
||||
def build_rustc_perf(self):
|
||||
# rustc-perf version from 2023-03-15
|
||||
perf_commit = "9dfaa35193154b690922347ee1141a06ec87a199"
|
||||
perf_commit = "8b2ac3042e1ff2c0074455a0a3618adef97156b1"
|
||||
rustc_perf_zip_path = self.opt_artifacts() / "perf.zip"
|
||||
|
||||
def download_rustc_perf():
|
||||
|
@ -1,7 +0,0 @@
|
||||
# `const_eval_limit`
|
||||
|
||||
The tracking issue for this feature is: [#67217]
|
||||
|
||||
[#67217]: https://github.com/rust-lang/rust/issues/67217
|
||||
|
||||
The `const_eval_limit` allows someone to limit the evaluation steps the CTFE undertakes to evaluate a `const fn`.
|
@ -195,10 +195,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
// Limits:
|
||||
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
|
||||
ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
|
||||
gated!(
|
||||
const_eval_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
|
||||
const_eval_limit, experimental!(const_eval_limit)
|
||||
),
|
||||
gated!(
|
||||
move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
|
||||
large_assignments, experimental!(move_size_limit)
|
||||
|
@ -4,8 +4,8 @@ fn main() {
|
||||
let _ = [(); {
|
||||
let mut n = 113383; // #20 in https://oeis.org/A006884
|
||||
while n != 0 {
|
||||
//~^ ERROR evaluation of constant value failed
|
||||
n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
|
||||
//~^ ERROR is taking a long time
|
||||
n = if n % 2 == 0 { n / 2 } else { 3 * n + 1 };
|
||||
}
|
||||
n
|
||||
}];
|
||||
|
@ -1,12 +1,27 @@
|
||||
error[E0080]: evaluation of constant value failed
|
||||
error: constant evaluation is taking a long time
|
||||
--> $DIR/infinite_loop.rs:6:9
|
||||
|
|
||||
LL | / while n != 0 {
|
||||
LL | |
|
||||
LL | | n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
|
||||
LL | | n = if n % 2 == 0 { n / 2 } else { 3 * n + 1 };
|
||||
LL | | }
|
||||
| |_________^ exceeded interpreter step limit (see `#[const_eval_limit]`)
|
||||
| |_________^
|
||||
|
|
||||
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
|
||||
If your compilation actually takes a long time, you can safely allow the lint.
|
||||
help: the constant being evaluated
|
||||
--> $DIR/infinite_loop.rs:4:18
|
||||
|
|
||||
LL | let _ = [(); {
|
||||
| __________________^
|
||||
LL | | let mut n = 113383; // #20 in https://oeis.org/A006884
|
||||
LL | | while n != 0 {
|
||||
LL | |
|
||||
... |
|
||||
LL | | n
|
||||
LL | | }];
|
||||
| |_____^
|
||||
= note: `#[deny(long_running_const_eval)]` on by default
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
@ -2,7 +2,8 @@ fn main() {
|
||||
let _ = [(); {
|
||||
let mut x = &0;
|
||||
let mut n = 0;
|
||||
while n < 5 { //~ ERROR evaluation of constant value failed [E0080]
|
||||
while n < 5 {
|
||||
//~^ ERROR: constant evaluation is taking a long time
|
||||
n = (n + 1) % 5;
|
||||
x = &0; // Materialize a new AllocId
|
||||
}
|
||||
|
@ -1,12 +1,28 @@
|
||||
error[E0080]: evaluation of constant value failed
|
||||
error: constant evaluation is taking a long time
|
||||
--> $DIR/issue-52475.rs:5:9
|
||||
|
|
||||
LL | / while n < 5 {
|
||||
LL | |
|
||||
LL | | n = (n + 1) % 5;
|
||||
LL | | x = &0; // Materialize a new AllocId
|
||||
LL | | }
|
||||
| |_________^ exceeded interpreter step limit (see `#[const_eval_limit]`)
|
||||
| |_________^
|
||||
|
|
||||
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
|
||||
If your compilation actually takes a long time, you can safely allow the lint.
|
||||
help: the constant being evaluated
|
||||
--> $DIR/issue-52475.rs:2:18
|
||||
|
|
||||
LL | let _ = [(); {
|
||||
| __________________^
|
||||
LL | | let mut x = &0;
|
||||
LL | | let mut n = 0;
|
||||
LL | | while n < 5 {
|
||||
... |
|
||||
LL | | 0
|
||||
LL | | }];
|
||||
| |_____^
|
||||
= note: `#[deny(long_running_const_eval)]` on by default
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
@ -1,3 +1,3 @@
|
||||
static _X: () = loop {}; //~ ERROR could not evaluate static initializer
|
||||
static _X: () = loop {}; //~ ERROR taking a long time
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,9 +1,17 @@
|
||||
error[E0080]: could not evaluate static initializer
|
||||
error: constant evaluation is taking a long time
|
||||
--> $DIR/issue-70723.rs:1:17
|
||||
|
|
||||
LL | static _X: () = loop {};
|
||||
| ^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
|
||||
If your compilation actually takes a long time, you can safely allow the lint.
|
||||
help: the constant being evaluated
|
||||
--> $DIR/issue-70723.rs:1:1
|
||||
|
|
||||
LL | static _X: () = loop {};
|
||||
| ^^^^^^^^^^^^^
|
||||
= note: `#[deny(long_running_const_eval)]` on by default
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
@ -25,7 +25,7 @@ const fn call_foo() -> u32 {
|
||||
foo();
|
||||
foo();
|
||||
foo();
|
||||
foo(); //~ ERROR evaluation of constant value failed [E0080]
|
||||
foo(); //~ ERROR is taking a long time
|
||||
0
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,17 @@
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/ctfe-fn-call.rs:28:5
|
||||
|
|
||||
LL | foo();
|
||||
| ^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
|
||||
|
|
||||
note: inside `call_foo`
|
||||
error: constant evaluation is taking a long time
|
||||
--> $DIR/ctfe-fn-call.rs:28:5
|
||||
|
|
||||
LL | foo();
|
||||
| ^^^^^
|
||||
note: inside `X`
|
||||
--> $DIR/ctfe-fn-call.rs:32:16
|
||||
|
|
||||
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
|
||||
If your compilation actually takes a long time, you can safely allow the lint.
|
||||
help: the constant being evaluated
|
||||
--> $DIR/ctfe-fn-call.rs:32:1
|
||||
|
|
||||
LL | const X: u32 = call_foo();
|
||||
| ^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^
|
||||
= note: `#[deny(long_running_const_eval)]` on by default
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
@ -3,9 +3,10 @@
|
||||
|
||||
const fn labelled_loop(n: u32) -> u32 {
|
||||
let mut i = 0;
|
||||
'mylabel: loop { //~ ERROR evaluation of constant value failed [E0080]
|
||||
'mylabel: loop {
|
||||
//~^ ERROR is taking a long time
|
||||
if i > n {
|
||||
break 'mylabel
|
||||
break 'mylabel;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
@ -1,30 +1,23 @@
|
||||
error[E0080]: evaluation of constant value failed
|
||||
error: constant evaluation is taking a long time
|
||||
--> $DIR/ctfe-labelled-loop.rs:6:5
|
||||
|
|
||||
LL | / 'mylabel: loop {
|
||||
LL | |
|
||||
LL | | if i > n {
|
||||
LL | | break 'mylabel
|
||||
LL | | }
|
||||
LL | | i += 1;
|
||||
LL | | }
|
||||
| |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`)
|
||||
|
|
||||
note: inside `labelled_loop`
|
||||
--> $DIR/ctfe-labelled-loop.rs:6:5
|
||||
|
|
||||
LL | / 'mylabel: loop {
|
||||
LL | | if i > n {
|
||||
LL | | break 'mylabel
|
||||
LL | | break 'mylabel;
|
||||
LL | | }
|
||||
LL | | i += 1;
|
||||
LL | | }
|
||||
| |_____^
|
||||
note: inside `X`
|
||||
--> $DIR/ctfe-labelled-loop.rs:15:16
|
||||
|
|
||||
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
|
||||
If your compilation actually takes a long time, you can safely allow the lint.
|
||||
help: the constant being evaluated
|
||||
--> $DIR/ctfe-labelled-loop.rs:16:1
|
||||
|
|
||||
LL | const X: u32 = labelled_loop(19);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^
|
||||
= note: `#[deny(long_running_const_eval)]` on by default
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
@ -1,11 +1,12 @@
|
||||
// check-fail
|
||||
// compile-flags: -Z tiny-const-eval-limit
|
||||
|
||||
#[rustfmt::skip]
|
||||
const fn recurse(n: u32) -> u32 {
|
||||
if n == 0 {
|
||||
n
|
||||
} else {
|
||||
recurse(n - 1) //~ ERROR evaluation of constant value failed [E0080]
|
||||
recurse(n - 1) //~ ERROR is taking a long time
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,25 +1,17 @@
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/ctfe-recursion.rs:8:9
|
||||
|
|
||||
LL | recurse(n - 1)
|
||||
| ^^^^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
|
||||
|
|
||||
note: inside `recurse`
|
||||
--> $DIR/ctfe-recursion.rs:8:9
|
||||
error: constant evaluation is taking a long time
|
||||
--> $DIR/ctfe-recursion.rs:9:9
|
||||
|
|
||||
LL | recurse(n - 1)
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: [... 18 additional calls inside `recurse` ...]
|
||||
--> $DIR/ctfe-recursion.rs:8:9
|
||||
|
|
||||
LL | recurse(n - 1)
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: inside `X`
|
||||
--> $DIR/ctfe-recursion.rs:12:16
|
||||
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
|
||||
If your compilation actually takes a long time, you can safely allow the lint.
|
||||
help: the constant being evaluated
|
||||
--> $DIR/ctfe-recursion.rs:13:1
|
||||
|
|
||||
LL | const X: u32 = recurse(19);
|
||||
| ^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^
|
||||
= note: `#[deny(long_running_const_eval)]` on by default
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
@ -0,0 +1,19 @@
|
||||
warning: constant evaluation is taking a long time
|
||||
--> $DIR/ctfe-simple-loop.rs:9:5
|
||||
|
|
||||
LL | / while index < n {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | index = index + 1;
|
||||
LL | | }
|
||||
| |_____^ the const evaluator is currently interpreting this expression
|
||||
|
|
||||
help: the constant being evaluated
|
||||
--> $DIR/ctfe-simple-loop.rs:19:1
|
||||
|
|
||||
LL | const Y: u32 = simple_loop(35);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
@ -1,14 +1,22 @@
|
||||
// check-fail
|
||||
// check-pass
|
||||
// revisions: warn allow
|
||||
#![cfg_attr(warn, warn(long_running_const_eval))]
|
||||
#![cfg_attr(allow, allow(long_running_const_eval))]
|
||||
|
||||
// compile-flags: -Z tiny-const-eval-limit
|
||||
const fn simple_loop(n: u32) -> u32 {
|
||||
let mut index = 0;
|
||||
while index < n { //~ ERROR evaluation of constant value failed [E0080]
|
||||
while index < n {
|
||||
//~^ WARN is taking a long time
|
||||
//[warn]~| WARN is taking a long time
|
||||
//[warn]~| WARN is taking a long time
|
||||
index = index + 1;
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
const X: u32 = simple_loop(19);
|
||||
const Y: u32 = simple_loop(35);
|
||||
|
||||
fn main() {
|
||||
println!("{X}");
|
||||
|
@ -1,24 +0,0 @@
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/ctfe-simple-loop.rs:5:5
|
||||
|
|
||||
LL | / while index < n {
|
||||
LL | | index = index + 1;
|
||||
LL | | }
|
||||
| |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`)
|
||||
|
|
||||
note: inside `simple_loop`
|
||||
--> $DIR/ctfe-simple-loop.rs:5:5
|
||||
|
|
||||
LL | / while index < n {
|
||||
LL | | index = index + 1;
|
||||
LL | | }
|
||||
| |_____^
|
||||
note: inside `X`
|
||||
--> $DIR/ctfe-simple-loop.rs:11:16
|
||||
|
|
||||
LL | const X: u32 = simple_loop(19);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
@ -0,0 +1,62 @@
|
||||
warning: constant evaluation is taking a long time
|
||||
--> $DIR/ctfe-simple-loop.rs:9:5
|
||||
|
|
||||
LL | / while index < n {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | index = index + 1;
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
|
||||
If your compilation actually takes a long time, you can safely allow the lint.
|
||||
help: the constant being evaluated
|
||||
--> $DIR/ctfe-simple-loop.rs:18:1
|
||||
|
|
||||
LL | const X: u32 = simple_loop(19);
|
||||
| ^^^^^^^^^^^^
|
||||
note: the lint level is defined here
|
||||
--> $DIR/ctfe-simple-loop.rs:3:24
|
||||
|
|
||||
LL | #![cfg_attr(warn, warn(long_running_const_eval))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: constant evaluation is taking a long time
|
||||
--> $DIR/ctfe-simple-loop.rs:9:5
|
||||
|
|
||||
LL | / while index < n {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | index = index + 1;
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
|
||||
If your compilation actually takes a long time, you can safely allow the lint.
|
||||
help: the constant being evaluated
|
||||
--> $DIR/ctfe-simple-loop.rs:19:1
|
||||
|
|
||||
LL | const Y: u32 = simple_loop(35);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
warning: constant evaluation is taking a long time
|
||||
--> $DIR/ctfe-simple-loop.rs:9:5
|
||||
|
|
||||
LL | / while index < n {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | index = index + 1;
|
||||
LL | | }
|
||||
| |_____^ the const evaluator is currently interpreting this expression
|
||||
|
|
||||
help: the constant being evaluated
|
||||
--> $DIR/ctfe-simple-loop.rs:19:1
|
||||
|
|
||||
LL | const Y: u32 = simple_loop(35);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
warning: 3 warnings emitted
|
||||
|
@ -1,20 +0,0 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(const_eval_limit)]
|
||||
|
||||
// This needs to be higher than the number of loop iterations since each pass through the loop may
|
||||
// hit more than one terminator.
|
||||
#![const_eval_limit="4000"]
|
||||
|
||||
const X: usize = {
|
||||
let mut x = 0;
|
||||
while x != 1000 {
|
||||
x += 1;
|
||||
}
|
||||
|
||||
x
|
||||
};
|
||||
|
||||
fn main() {
|
||||
assert_eq!(X, 1000);
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
#![feature(const_eval_limit)]
|
||||
#![const_eval_limit="18_446_744_073_709_551_615"]
|
||||
//~^ ERROR `limit` must be a non-negative integer
|
||||
|
||||
const CONSTANT: usize = limit();
|
||||
|
||||
fn main() {
|
||||
assert_eq!(CONSTANT, 1764);
|
||||
}
|
||||
|
||||
const fn limit() -> usize {
|
||||
let x = 42;
|
||||
|
||||
x * 42
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
error: `limit` must be a non-negative integer
|
||||
--> $DIR/const_eval_limit_overflow.rs:2:1
|
||||
|
|
||||
LL | #![const_eval_limit="18_446_744_073_709_551_615"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^----------------------------^
|
||||
| |
|
||||
| not a valid integer
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,16 +0,0 @@
|
||||
#![feature(const_eval_limit)]
|
||||
#![const_eval_limit = "500"]
|
||||
|
||||
const X: usize = {
|
||||
let mut x = 0;
|
||||
while x != 1000 {
|
||||
//~^ ERROR evaluation of constant value failed
|
||||
x += 1;
|
||||
}
|
||||
|
||||
x
|
||||
};
|
||||
|
||||
fn main() {
|
||||
assert_eq!(X, 1000);
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/const_eval_limit_reached.rs:6:5
|
||||
|
|
||||
LL | / while x != 1000 {
|
||||
LL | |
|
||||
LL | | x += 1;
|
||||
LL | | }
|
||||
| |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`)
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
@ -1,14 +0,0 @@
|
||||
#![const_eval_limit="42"]
|
||||
//~^ ERROR the `#[const_eval_limit]` attribute is an experimental feature [E0658]
|
||||
|
||||
const CONSTANT: usize = limit();
|
||||
|
||||
fn main() {
|
||||
assert_eq!(CONSTANT, 1764);
|
||||
}
|
||||
|
||||
const fn limit() -> usize {
|
||||
let x = 42;
|
||||
|
||||
x * 42
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
error[E0658]: the `#[const_eval_limit]` attribute is an experimental feature
|
||||
--> $DIR/feature-gate-const_eval_limit.rs:1:1
|
||||
|
|
||||
LL | #![const_eval_limit="42"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #67217 <https://github.com/rust-lang/rust/issues/67217> for more information
|
||||
= help: add `#![feature(const_eval_limit)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
Loading…
Reference in New Issue
Block a user