mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Remove const eval limit and implement an exponential backoff lint instead
This commit is contained in:
parent
578bcbc2b4
commit
05eae08233
@ -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
|
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.
|
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_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
|
||||||
|
|
||||||
const_eval_mut_deref =
|
const_eval_mut_deref =
|
||||||
|
@ -103,7 +103,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
|
|||||||
tcx,
|
tcx,
|
||||||
root_span,
|
root_span,
|
||||||
param_env,
|
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
|
// Statics (and promoteds inside statics) may access other statics, because unlike consts
|
||||||
// they do not have to behave "as if" they were evaluated at runtime.
|
// they do not have to behave "as if" they were evaluated at runtime.
|
||||||
CompileTimeInterpreter::new(
|
CompileTimeInterpreter::new(
|
||||||
tcx.const_eval_limit(),
|
|
||||||
/*can_access_statics:*/ is_static,
|
/*can_access_statics:*/ is_static,
|
||||||
if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
|
if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
|
||||||
CheckAlignment::Error
|
CheckAlignment::Error
|
||||||
|
@ -16,11 +16,11 @@ use std::fmt;
|
|||||||
use rustc_ast::Mutability;
|
use rustc_ast::Mutability;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::mir::AssertMessage;
|
use rustc_middle::mir::AssertMessage;
|
||||||
use rustc_session::Limit;
|
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use rustc_target::abi::{Align, Size};
|
use rustc_target::abi::{Align, Size};
|
||||||
use rustc_target::spec::abi::Abi as CallAbi;
|
use rustc_target::spec::abi::Abi as CallAbi;
|
||||||
|
|
||||||
|
use crate::errors::{LongRunning, LongRunningWarn};
|
||||||
use crate::interpret::{
|
use crate::interpret::{
|
||||||
self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx,
|
self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx,
|
||||||
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
|
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
|
||||||
@ -28,13 +28,24 @@ use crate::interpret::{
|
|||||||
|
|
||||||
use super::error::*;
|
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
|
/// Extra machine state for CTFE, and the Machine instance
|
||||||
pub struct CompileTimeInterpreter<'mir, 'tcx> {
|
pub struct CompileTimeInterpreter<'mir, 'tcx> {
|
||||||
/// For now, the number of terminators that can be evaluated before we throw a resource
|
/// The number of terminators that have been evaluated.
|
||||||
/// exhaustion error.
|
|
||||||
///
|
///
|
||||||
/// Setting this to `0` disables the limit and allows the interpreter to run forever.
|
/// This is used to produce lints informing the user that the compiler is not stuck.
|
||||||
pub(super) steps_remaining: usize,
|
/// Set to `usize::MAX` to never report anything.
|
||||||
|
pub(super) num_evaluated_steps: usize,
|
||||||
|
|
||||||
/// The virtual call stack.
|
/// The virtual call stack.
|
||||||
pub(super) stack: Vec<Frame<'mir, 'tcx, AllocId, ()>>,
|
pub(super) stack: Vec<Frame<'mir, 'tcx, AllocId, ()>>,
|
||||||
@ -72,13 +83,9 @@ impl CheckAlignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
|
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(can_access_statics: bool, check_alignment: CheckAlignment) -> Self {
|
||||||
const_eval_limit: Limit,
|
|
||||||
can_access_statics: bool,
|
|
||||||
check_alignment: CheckAlignment,
|
|
||||||
) -> Self {
|
|
||||||
CompileTimeInterpreter {
|
CompileTimeInterpreter {
|
||||||
steps_remaining: const_eval_limit.0,
|
num_evaluated_steps: 0,
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
can_access_statics,
|
can_access_statics,
|
||||||
check_alignment,
|
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> {
|
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`.
|
// 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 let Some(new_steps) = ecx.machine.num_evaluated_steps.checked_add(1) {
|
||||||
if ecx.machine.steps_remaining == 0 {
|
let (limit, start) = if ecx.tcx.sess.opts.unstable_opts.tiny_const_eval_limit {
|
||||||
throw_exhaust!(StepLimitReached)
|
(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(())
|
Ok(())
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use rustc_hir::ConstContext;
|
use rustc_hir::ConstContext;
|
||||||
use rustc_macros::Diagnostic;
|
use rustc_macros::{Diagnostic, LintDiagnostic};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
@ -194,3 +194,21 @@ pub(crate) struct InteriorMutabilityBorrow {
|
|||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: 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 either::{Either, Left, Right};
|
||||||
|
|
||||||
|
use hir::CRATE_HIR_ID;
|
||||||
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
|
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::mir;
|
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())
|
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)]
|
#[inline(always)]
|
||||||
pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] {
|
pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] {
|
||||||
M::stack(self)
|
M::stack(self)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement};
|
use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement};
|
||||||
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
|
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
|
||||||
use rustc_session::Limit;
|
|
||||||
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
|
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
|
||||||
|
|
||||||
use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
|
use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
|
||||||
@ -45,11 +44,8 @@ fn might_permit_raw_init_strict<'tcx>(
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
kind: ValidityRequirement,
|
kind: ValidityRequirement,
|
||||||
) -> Result<bool, LayoutError<'tcx>> {
|
) -> Result<bool, LayoutError<'tcx>> {
|
||||||
let machine = CompileTimeInterpreter::new(
|
let machine =
|
||||||
Limit::new(0),
|
CompileTimeInterpreter::new(/*can_access_statics:*/ false, CheckAlignment::Error);
|
||||||
/*can_access_statics:*/ false,
|
|
||||||
CheckAlignment::Error,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
|
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),
|
(active, const_async_blocks, "1.53.0", Some(85368), None),
|
||||||
/// Allows `const || {}` closures in const contexts.
|
/// Allows `const || {}` closures in const contexts.
|
||||||
(incomplete, const_closures, "1.68.0", Some(106003), None),
|
(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`.
|
/// Allows the definition of `const extern fn` and `const unsafe extern fn`.
|
||||||
(active, const_extern_fn, "1.40.0", Some(64926), None),
|
(active, const_extern_fn, "1.40.0", Some(64926), None),
|
||||||
/// Allows basic arithmetic on floating point types in a `const fn`.
|
/// Allows basic arithmetic on floating point types in a `const fn`.
|
||||||
|
@ -355,10 +355,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||||||
// Limits:
|
// Limits:
|
||||||
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
|
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
|
||||||
ungated!(type_length_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!(
|
gated!(
|
||||||
move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
|
move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
|
||||||
large_assignments, experimental!(move_size_limit)
|
large_assignments, experimental!(move_size_limit)
|
||||||
|
@ -59,8 +59,10 @@ declare_features! (
|
|||||||
/// Allows comparing raw pointers during const eval.
|
/// Allows comparing raw pointers during const eval.
|
||||||
(removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
|
(removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
|
||||||
Some("cannot be allowed in const eval in any meaningful way")),
|
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.
|
/// 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.
|
/// Allows the definition of `const` functions with some advanced features.
|
||||||
(removed, const_fn, "1.54.0", Some(57563), None,
|
(removed, const_fn, "1.54.0", Some(57563), None,
|
||||||
Some("split into finer-grained feature gates")),
|
Some("split into finer-grained feature gates")),
|
||||||
|
@ -3357,6 +3357,7 @@ declare_lint_pass! {
|
|||||||
LARGE_ASSIGNMENTS,
|
LARGE_ASSIGNMENTS,
|
||||||
LATE_BOUND_LIFETIME_ARGUMENTS,
|
LATE_BOUND_LIFETIME_ARGUMENTS,
|
||||||
LEGACY_DERIVE_HELPERS,
|
LEGACY_DERIVE_HELPERS,
|
||||||
|
LONG_RUNNING_CONST_EVAL,
|
||||||
LOSSY_PROVENANCE_CASTS,
|
LOSSY_PROVENANCE_CASTS,
|
||||||
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
|
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
|
||||||
MACRO_USE_EXTERN_CRATE,
|
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! {
|
declare_lint! {
|
||||||
/// The `unused_doc_comments` lint detects doc comments that aren't used
|
/// The `unused_doc_comments` lint detects doc comments that aren't used
|
||||||
/// by `rustdoc`.
|
/// by `rustdoc`.
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
//! Registering limits:
|
//! Registering limits:
|
||||||
//! * recursion_limit,
|
//! * recursion_limit,
|
||||||
//! * move_size_limit,
|
//! * move_size_limit, and
|
||||||
//! * type_length_limit, and
|
//! * type_length_limit
|
||||||
//! * const_eval_limit
|
|
||||||
//!
|
//!
|
||||||
//! There are various parts of the compiler that must impose arbitrary limits
|
//! There are various parts of the compiler that must impose arbitrary limits
|
||||||
//! on how deeply they recurse to prevent stack overflow. Users can override
|
//! 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,
|
sym::type_length_limit,
|
||||||
1048576,
|
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 {
|
pub enum ResourceExhaustionInfo {
|
||||||
/// The stack grew too big.
|
/// The stack grew too big.
|
||||||
StackFrameLimitReached,
|
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.
|
/// There is not enough memory (on the host) to perform an allocation.
|
||||||
MemoryExhausted,
|
MemoryExhausted,
|
||||||
/// The address space (of the target) is full.
|
/// The address space (of the target) is full.
|
||||||
@ -482,9 +478,6 @@ impl fmt::Display for ResourceExhaustionInfo {
|
|||||||
StackFrameLimitReached => {
|
StackFrameLimitReached => {
|
||||||
write!(f, "reached the configured maximum number of stack frames")
|
write!(f, "reached the configured maximum number of stack frames")
|
||||||
}
|
}
|
||||||
StepLimitReached => {
|
|
||||||
write!(f, "exceeded interpreter step limit (see `#[const_eval_limit]`)")
|
|
||||||
}
|
|
||||||
MemoryExhausted => {
|
MemoryExhausted => {
|
||||||
write!(f, "tried to allocate more memory than available to compiler")
|
write!(f, "tried to allocate more memory than available to compiler")
|
||||||
}
|
}
|
||||||
|
@ -82,8 +82,6 @@ use std::iter;
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Bound, Deref};
|
use std::ops::{Bound, Deref};
|
||||||
|
|
||||||
const TINY_CONST_EVAL_LIMIT: Limit = Limit(20);
|
|
||||||
|
|
||||||
#[allow(rustc::usage_of_ty_tykind)]
|
#[allow(rustc::usage_of_ty_tykind)]
|
||||||
impl<'tcx> Interner for TyCtxt<'tcx> {
|
impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||||
type AdtDef = ty::AdtDef<'tcx>;
|
type AdtDef = ty::AdtDef<'tcx>;
|
||||||
@ -1178,14 +1176,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
self.limits(()).move_size_limit
|
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 {
|
pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx {
|
||||||
iter::once(LOCAL_CRATE)
|
iter::once(LOCAL_CRATE)
|
||||||
.chain(self.crates(()).iter().copied())
|
.chain(self.crates(()).iter().copied())
|
||||||
|
@ -128,8 +128,6 @@ pub struct Limits {
|
|||||||
pub move_size_limit: Limit,
|
pub move_size_limit: Limit,
|
||||||
/// The maximum length of types during monomorphization.
|
/// The maximum length of types during monomorphization.
|
||||||
pub type_length_limit: Limit,
|
pub type_length_limit: Limit,
|
||||||
/// The maximum blocks a const expression can evaluate.
|
|
||||||
pub const_eval_limit: Limit,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CompilerIO {
|
pub struct CompilerIO {
|
||||||
|
@ -55,7 +55,7 @@ RUN ./build-clang.sh
|
|||||||
ENV CC=clang CXX=clang++
|
ENV CC=clang CXX=clang++
|
||||||
|
|
||||||
# rustc-perf version from 2023-03-15
|
# 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 && \
|
RUN curl -LS -o perf.zip https://github.com/rust-lang/rustc-perf/archive/$PERF_COMMIT.zip && \
|
||||||
unzip perf.zip && \
|
unzip perf.zip && \
|
||||||
mv rustc-perf-$PERF_COMMIT rustc-perf && \
|
mv rustc-perf-$PERF_COMMIT rustc-perf && \
|
||||||
|
@ -175,7 +175,7 @@ class WindowsPipeline(Pipeline):
|
|||||||
|
|
||||||
def build_rustc_perf(self):
|
def build_rustc_perf(self):
|
||||||
# rustc-perf version from 2023-03-15
|
# rustc-perf version from 2023-03-15
|
||||||
perf_commit = "9dfaa35193154b690922347ee1141a06ec87a199"
|
perf_commit = "8b2ac3042e1ff2c0074455a0a3618adef97156b1"
|
||||||
rustc_perf_zip_path = self.opt_artifacts() / "perf.zip"
|
rustc_perf_zip_path = self.opt_artifacts() / "perf.zip"
|
||||||
|
|
||||||
def download_rustc_perf():
|
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:
|
// Limits:
|
||||||
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
|
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
|
||||||
ungated!(type_length_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!(
|
gated!(
|
||||||
move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
|
move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
|
||||||
large_assignments, experimental!(move_size_limit)
|
large_assignments, experimental!(move_size_limit)
|
||||||
|
@ -4,8 +4,8 @@ fn main() {
|
|||||||
let _ = [(); {
|
let _ = [(); {
|
||||||
let mut n = 113383; // #20 in https://oeis.org/A006884
|
let mut n = 113383; // #20 in https://oeis.org/A006884
|
||||||
while n != 0 {
|
while n != 0 {
|
||||||
//~^ ERROR evaluation of constant value failed
|
//~^ ERROR is taking a long time
|
||||||
n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
|
n = if n % 2 == 0 { n / 2 } else { 3 * n + 1 };
|
||||||
}
|
}
|
||||||
n
|
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
|
--> $DIR/infinite_loop.rs:6:9
|
||||||
|
|
|
|
||||||
LL | / while n != 0 {
|
LL | / while n != 0 {
|
||||||
LL | |
|
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 | | }
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0080`.
|
|
||||||
|
@ -2,7 +2,8 @@ fn main() {
|
|||||||
let _ = [(); {
|
let _ = [(); {
|
||||||
let mut x = &0;
|
let mut x = &0;
|
||||||
let mut n = 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;
|
n = (n + 1) % 5;
|
||||||
x = &0; // Materialize a new AllocId
|
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
|
--> $DIR/issue-52475.rs:5:9
|
||||||
|
|
|
|
||||||
LL | / while n < 5 {
|
LL | / while n < 5 {
|
||||||
|
LL | |
|
||||||
LL | | n = (n + 1) % 5;
|
LL | | n = (n + 1) % 5;
|
||||||
LL | | x = &0; // Materialize a new AllocId
|
LL | | x = &0; // Materialize a new AllocId
|
||||||
LL | | }
|
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
|
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() {}
|
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
|
--> $DIR/issue-70723.rs:1:17
|
||||||
|
|
|
|
||||||
LL | static _X: () = loop {};
|
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
|
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();
|
||||||
foo();
|
foo();
|
||||||
foo(); //~ ERROR evaluation of constant value failed [E0080]
|
foo(); //~ ERROR is taking a long time
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,17 @@
|
|||||||
error[E0080]: evaluation of constant value failed
|
error: constant evaluation is taking a long time
|
||||||
--> $DIR/ctfe-fn-call.rs:28:5
|
|
||||||
|
|
|
||||||
LL | foo();
|
|
||||||
| ^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
|
|
||||||
|
|
|
||||||
note: inside `call_foo`
|
|
||||||
--> $DIR/ctfe-fn-call.rs:28:5
|
--> $DIR/ctfe-fn-call.rs:28:5
|
||||||
|
|
|
|
||||||
LL | foo();
|
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();
|
LL | const X: u32 = call_foo();
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
= note: `#[deny(long_running_const_eval)]` on by default
|
||||||
|
|
||||||
error: aborting due to previous error
|
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 {
|
const fn labelled_loop(n: u32) -> u32 {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
'mylabel: loop { //~ ERROR evaluation of constant value failed [E0080]
|
'mylabel: loop {
|
||||||
|
//~^ ERROR is taking a long time
|
||||||
if i > n {
|
if i > n {
|
||||||
break 'mylabel
|
break 'mylabel;
|
||||||
}
|
}
|
||||||
i += 1;
|
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
|
--> $DIR/ctfe-labelled-loop.rs:6:5
|
||||||
|
|
|
|
||||||
LL | / 'mylabel: loop {
|
LL | / 'mylabel: loop {
|
||||||
|
LL | |
|
||||||
LL | | if i > n {
|
LL | | if i > n {
|
||||||
LL | | break 'mylabel
|
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 | | }
|
LL | | }
|
||||||
LL | | i += 1;
|
LL | | i += 1;
|
||||||
LL | | }
|
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);
|
LL | const X: u32 = labelled_loop(19);
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
= note: `#[deny(long_running_const_eval)]` on by default
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0080`.
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
// check-fail
|
// check-fail
|
||||||
// compile-flags: -Z tiny-const-eval-limit
|
// compile-flags: -Z tiny-const-eval-limit
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
const fn recurse(n: u32) -> u32 {
|
const fn recurse(n: u32) -> u32 {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
n
|
n
|
||||||
} else {
|
} 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
|
error: constant evaluation is taking a long time
|
||||||
--> $DIR/ctfe-recursion.rs:8:9
|
--> $DIR/ctfe-recursion.rs:9:9
|
||||||
|
|
|
||||||
LL | recurse(n - 1)
|
|
||||||
| ^^^^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
|
|
||||||
|
|
|
||||||
note: inside `recurse`
|
|
||||||
--> $DIR/ctfe-recursion.rs:8:9
|
|
||||||
|
|
|
|
||||||
LL | recurse(n - 1)
|
LL | recurse(n - 1)
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
note: [... 18 additional calls inside `recurse` ...]
|
|
||||||
--> $DIR/ctfe-recursion.rs:8:9
|
|
||||||
|
|
|
|
||||||
LL | recurse(n - 1)
|
= 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.
|
||||||
note: inside `X`
|
help: the constant being evaluated
|
||||||
--> $DIR/ctfe-recursion.rs:12:16
|
--> $DIR/ctfe-recursion.rs:13:1
|
||||||
|
|
|
|
||||||
LL | const X: u32 = recurse(19);
|
LL | const X: u32 = recurse(19);
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
= note: `#[deny(long_running_const_eval)]` on by default
|
||||||
|
|
||||||
error: aborting due to previous error
|
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
|
// compile-flags: -Z tiny-const-eval-limit
|
||||||
const fn simple_loop(n: u32) -> u32 {
|
const fn simple_loop(n: u32) -> u32 {
|
||||||
let mut index = 0;
|
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;
|
index = index + 1;
|
||||||
}
|
}
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
const X: u32 = simple_loop(19);
|
const X: u32 = simple_loop(19);
|
||||||
|
const Y: u32 = simple_loop(35);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("{X}");
|
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