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 9195ae163bc61..0a61dab8aac2c 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 57e55752027c7..96dc44ce185d8 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 bbe52dbced071..bf3525750d889 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`.