diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 7d56cf0aa0701..917bd8295726b 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -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 =
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 046d2052968a3..e4d34b90018b8 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -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
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 58b5755af07f2..a8b6b98c96cbe 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -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>,
@@ -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(())
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index f8b7cc6d7e16b..ad2e68e752d37 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -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,
+}
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 91ccdef7215c2..cd43a53b1b3f4 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -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)
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index 23fcd22c52b8e..29063261adab6 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -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> {
- 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);
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index dde9890dfa5d6..4c53f9d8369fd 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -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`.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 06f4a0b5eef84..9be28c338f64b 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -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)
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 8bca24b2bf01e..ed5d76b861a49 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -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")),
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 1507087bdd4f3..eb246c3f93eb0 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -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`.
diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index bd859d4d61beb..d4f023958d6fd 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -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,
- ),
}
}
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 055d8e9a352bc..357bcca441990 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -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")
}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 77725f0b3b60b..b05e791211d10 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -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- + 'tcx {
iter::once(LOCAL_CRATE)
.chain(self.crates(()).iter().copied())
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 1eb54cee5a14c..2ebd83540ee15 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -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 {
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index 04fdb15f5acb2..c2fd2e3a91aef 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -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 && \
diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py
index 8d03d3759bf00..066d3a198f2fd 100644
--- a/src/ci/stage-build.py
+++ b/src/ci/stage-build.py
@@ -175,7 +175,7 @@ def rustc_stage_2(self) -> Path:
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():
diff --git a/src/doc/unstable-book/src/language-features/const-eval-limit.md b/src/doc/unstable-book/src/language-features/const-eval-limit.md
deleted file mode 100644
index df68e83bcac74..0000000000000
--- a/src/doc/unstable-book/src/language-features/const-eval-limit.md
+++ /dev/null
@@ -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`.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
index f7c1e683d0d20..142b12290194e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
@@ -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)
diff --git a/tests/ui/consts/const-eval/infinite_loop.rs b/tests/ui/consts/const-eval/infinite_loop.rs
index 4babc9a2850eb..2178149063791 100644
--- a/tests/ui/consts/const-eval/infinite_loop.rs
+++ b/tests/ui/consts/const-eval/infinite_loop.rs
@@ -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
}];
diff --git a/tests/ui/consts/const-eval/infinite_loop.stderr b/tests/ui/consts/const-eval/infinite_loop.stderr
index f30bfaf3f958c..f0434a847cea5 100644
--- a/tests/ui/consts/const-eval/infinite_loop.stderr
+++ b/tests/ui/consts/const-eval/infinite_loop.stderr
@@ -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`.
diff --git a/tests/ui/consts/const-eval/issue-52475.rs b/tests/ui/consts/const-eval/issue-52475.rs
index 307c1a6683410..ee26d280018b4 100644
--- a/tests/ui/consts/const-eval/issue-52475.rs
+++ b/tests/ui/consts/const-eval/issue-52475.rs
@@ -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
}
diff --git a/tests/ui/consts/const-eval/issue-52475.stderr b/tests/ui/consts/const-eval/issue-52475.stderr
index 3aa6bd277ddcb..ebf9d12a66ad8 100644
--- a/tests/ui/consts/const-eval/issue-52475.stderr
+++ b/tests/ui/consts/const-eval/issue-52475.stderr
@@ -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`.
diff --git a/tests/ui/consts/const-eval/issue-70723.rs b/tests/ui/consts/const-eval/issue-70723.rs
index 3c81afa67a69f..c8c809a25ed78 100644
--- a/tests/ui/consts/const-eval/issue-70723.rs
+++ b/tests/ui/consts/const-eval/issue-70723.rs
@@ -1,3 +1,3 @@
-static _X: () = loop {}; //~ ERROR could not evaluate static initializer
+static _X: () = loop {}; //~ ERROR taking a long time
fn main() {}
diff --git a/tests/ui/consts/const-eval/issue-70723.stderr b/tests/ui/consts/const-eval/issue-70723.stderr
index 09fb3e060dc4c..572a430726fbd 100644
--- a/tests/ui/consts/const-eval/issue-70723.stderr
+++ b/tests/ui/consts/const-eval/issue-70723.stderr
@@ -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`.
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.rs
index c59596238e140..a30518170ad42 100644
--- a/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.rs
+++ b/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.rs
@@ -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
}
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.stderr
index ed70975af341d..a3fd712ca4608 100644
--- a/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.stderr
+++ b/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.stderr
@@ -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`.
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.rs
index c10b8d8379119..f7cd04568be3c 100644
--- a/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.rs
+++ b/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.rs
@@ -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;
}
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.stderr
index d9404edd5b108..5808ee35a6b45 100644
--- a/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.stderr
+++ b/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.stderr
@@ -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`.
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.rs
index 80ff835f3e8dd..56a39fc45b0ae 100644
--- a/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.rs
+++ b/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.rs
@@ -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
}
}
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.stderr
index ed9a31119427a..524c8e5542666 100644
--- a/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.stderr
+++ b/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.stderr
@@ -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`.
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.allow.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.allow.stderr
new file mode 100644
index 0000000000000..30550f93ac10d
--- /dev/null
+++ b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.allow.stderr
@@ -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
+
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs
index ca0eec93c5dac..214f33dfb36c5 100644
--- a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs
+++ b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs
@@ -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}");
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.stderr
deleted file mode 100644
index 83ff275de7049..0000000000000
--- a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.stderr
+++ /dev/null
@@ -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`.
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.warn.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.warn.stderr
new file mode 100644
index 0000000000000..40fc4a876e9e5
--- /dev/null
+++ b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.warn.stderr
@@ -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
+
diff --git a/tests/ui/consts/const_limit/const_eval_limit_not_reached.rs b/tests/ui/consts/const_limit/const_eval_limit_not_reached.rs
deleted file mode 100644
index 629d1f02a30f3..0000000000000
--- a/tests/ui/consts/const_limit/const_eval_limit_not_reached.rs
+++ /dev/null
@@ -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);
-}
diff --git a/tests/ui/consts/const_limit/const_eval_limit_overflow.rs b/tests/ui/consts/const_limit/const_eval_limit_overflow.rs
deleted file mode 100644
index 1c49593cd53fa..0000000000000
--- a/tests/ui/consts/const_limit/const_eval_limit_overflow.rs
+++ /dev/null
@@ -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
-}
diff --git a/tests/ui/consts/const_limit/const_eval_limit_overflow.stderr b/tests/ui/consts/const_limit/const_eval_limit_overflow.stderr
deleted file mode 100644
index 7f5d5e6cd4c5a..0000000000000
--- a/tests/ui/consts/const_limit/const_eval_limit_overflow.stderr
+++ /dev/null
@@ -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
-
diff --git a/tests/ui/consts/const_limit/const_eval_limit_reached.rs b/tests/ui/consts/const_limit/const_eval_limit_reached.rs
deleted file mode 100644
index 3ce038c1d3f77..0000000000000
--- a/tests/ui/consts/const_limit/const_eval_limit_reached.rs
+++ /dev/null
@@ -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);
-}
diff --git a/tests/ui/consts/const_limit/const_eval_limit_reached.stderr b/tests/ui/consts/const_limit/const_eval_limit_reached.stderr
deleted file mode 100644
index a8e8ae9bb088a..0000000000000
--- a/tests/ui/consts/const_limit/const_eval_limit_reached.stderr
+++ /dev/null
@@ -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`.
diff --git a/tests/ui/consts/const_limit/feature-gate-const_eval_limit.rs b/tests/ui/consts/const_limit/feature-gate-const_eval_limit.rs
deleted file mode 100644
index 61119d7511d49..0000000000000
--- a/tests/ui/consts/const_limit/feature-gate-const_eval_limit.rs
+++ /dev/null
@@ -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
-}
diff --git a/tests/ui/consts/const_limit/feature-gate-const_eval_limit.stderr b/tests/ui/consts/const_limit/feature-gate-const_eval_limit.stderr
deleted file mode 100644
index 5bd29c7dfd22b..0000000000000
--- a/tests/ui/consts/const_limit/feature-gate-const_eval_limit.stderr
+++ /dev/null
@@ -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 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`.