mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 10:13:54 +00:00
Replace terminator-based const eval limit
- Remove logic that limits const eval based on terminators, and use the stable metric instead (back edges + fn calls) - Add unstable flag `tiny-const-eval-limit` to add UI tests that do not have to go up to the regular 2M step limit
This commit is contained in:
parent
8d99b0fc8d
commit
eea42733ac
@ -561,8 +561,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||||||
throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time");
|
throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn before_terminator(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 `before_terminator`.
|
// The step limit has already been hit in a previous call to `increment_const_eval_counter`.
|
||||||
if ecx.machine.steps_remaining == 0 {
|
if ecx.machine.steps_remaining == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -46,9 +46,6 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
|
|||||||
|
|
||||||
/// The recursion limit (cached from `tcx.recursion_limit(())`)
|
/// The recursion limit (cached from `tcx.recursion_limit(())`)
|
||||||
pub recursion_limit: Limit,
|
pub recursion_limit: Limit,
|
||||||
|
|
||||||
pub const_eval_limit: u32,
|
|
||||||
pub const_eval_counter: u32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
|
// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
|
||||||
@ -411,8 +408,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
param_env,
|
param_env,
|
||||||
memory: Memory::new(),
|
memory: Memory::new(),
|
||||||
recursion_limit: tcx.recursion_limit(),
|
recursion_limit: tcx.recursion_limit(),
|
||||||
const_eval_limit: 20,
|
|
||||||
const_eval_counter: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,10 +243,10 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||||||
ecx.stack_mut()[frame].locals[local].access_mut()
|
ecx.stack_mut()[frame].locals[local].access_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called before a basic block terminator is executed.
|
/// Called when the interpreter encounters a `StatementKind::ConstEvalCounter` instruction.
|
||||||
/// You can use this to detect endlessly running programs.
|
/// You can use this to detect long or endlessly running programs.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
|
fn increment_const_eval_counter(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,17 +293,6 @@ where
|
|||||||
Prov: Provenance + 'static,
|
Prov: Provenance + 'static,
|
||||||
M: Machine<'mir, 'tcx, Provenance = Prov>,
|
M: Machine<'mir, 'tcx, Provenance = Prov>,
|
||||||
{
|
{
|
||||||
pub fn increment_const_eval_counter(&mut self) {
|
|
||||||
self.const_eval_counter = self.const_eval_counter + 1;
|
|
||||||
if self.const_eval_counter == self.const_eval_limit {
|
|
||||||
let mut warn = self.tcx.sess.struct_warn(format!(
|
|
||||||
"Const eval counter limit ({}) has been crossed",
|
|
||||||
self.const_eval_limit
|
|
||||||
));
|
|
||||||
warn.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Take a value, which represents a (thin or wide) reference, and make it a place.
|
/// Take a value, which represents a (thin or wide) reference, and make it a place.
|
||||||
/// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`.
|
/// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`.
|
||||||
///
|
///
|
||||||
|
@ -62,8 +62,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
M::before_terminator(self)?;
|
|
||||||
|
|
||||||
let terminator = basic_block.terminator();
|
let terminator = basic_block.terminator();
|
||||||
self.terminator(terminator)?;
|
self.terminator(terminator)?;
|
||||||
Ok(true)
|
Ok(true)
|
||||||
@ -130,7 +128,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
Coverage(..) => {}
|
Coverage(..) => {}
|
||||||
|
|
||||||
ConstEvalCounter => {
|
ConstEvalCounter => {
|
||||||
self.increment_const_eval_counter();
|
M::increment_const_eval_counter(self)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defined to do nothing. These are added by optimization passes, to avoid changing the
|
// Defined to do nothing. These are added by optimization passes, to avoid changing the
|
||||||
|
@ -802,6 +802,7 @@ fn test_unstable_options_tracking_hash() {
|
|||||||
tracked!(teach, true);
|
tracked!(teach, true);
|
||||||
tracked!(thinlto, Some(true));
|
tracked!(thinlto, Some(true));
|
||||||
tracked!(thir_unsafeck, true);
|
tracked!(thir_unsafeck, true);
|
||||||
|
tracked!(tiny_const_eval_limit, true);
|
||||||
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
|
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
|
||||||
tracked!(trait_solver, TraitSolver::Chalk);
|
tracked!(trait_solver, TraitSolver::Chalk);
|
||||||
tracked!(translate_remapped_path_to_local_path, false);
|
tracked!(translate_remapped_path_to_local_path, false);
|
||||||
|
@ -75,6 +75,8 @@ 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);
|
||||||
|
|
||||||
pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
|
pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
|
||||||
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
|
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
|
||||||
fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
|
fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
|
||||||
@ -1078,7 +1080,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn const_eval_limit(self) -> Limit {
|
pub fn const_eval_limit(self) -> Limit {
|
||||||
self.limits(()).const_eval_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 {
|
||||||
|
@ -1616,6 +1616,8 @@ options! {
|
|||||||
"measure time of each LLVM pass (default: no)"),
|
"measure time of each LLVM pass (default: no)"),
|
||||||
time_passes: bool = (false, parse_bool, [UNTRACKED],
|
time_passes: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"measure time of each rustc pass (default: no)"),
|
"measure time of each rustc pass (default: no)"),
|
||||||
|
tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED],
|
||||||
|
"sets a tiny, non-configurable limit for const eval; useful for compiler tests"),
|
||||||
#[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")]
|
#[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")]
|
||||||
tls_model: Option<TlsModel> = (None, parse_tls_model, [TRACKED],
|
tls_model: Option<TlsModel> = (None, parse_tls_model, [TRACKED],
|
||||||
"choose the TLS model to use (`rustc --print tls-models` for details)"),
|
"choose the TLS model to use (`rustc --print tls-models` for details)"),
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
# `tiny-const-eval-limit`
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The `-Ztiny-const-eval-limit` compiler flag sets a tiny, non-configurable limit for const eval.
|
||||||
|
This flag should only be used by const eval tests in the rustc test suite.
|
@ -1,4 +1,5 @@
|
|||||||
// check-pass
|
// check-fail
|
||||||
|
// compile-flags: -Z tiny-const-eval-limit
|
||||||
|
|
||||||
const fn foo() {}
|
const fn foo() {}
|
||||||
|
|
||||||
@ -8,21 +9,23 @@ const fn call_foo() -> u32 {
|
|||||||
foo();
|
foo();
|
||||||
foo();
|
foo();
|
||||||
foo();
|
foo();
|
||||||
|
|
||||||
foo();
|
foo();
|
||||||
foo();
|
foo();
|
||||||
foo();
|
foo();
|
||||||
foo();
|
foo();
|
||||||
foo();
|
foo();
|
||||||
|
|
||||||
foo();
|
foo();
|
||||||
foo();
|
foo();
|
||||||
foo();
|
foo();
|
||||||
foo();
|
foo();
|
||||||
foo();
|
foo();
|
||||||
|
|
||||||
foo();
|
foo();
|
||||||
foo();
|
foo();
|
||||||
foo();
|
foo();
|
||||||
foo();
|
foo(); //~ ERROR evaluation of constant value failed [E0080]
|
||||||
foo();
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,20 @@
|
|||||||
warning: Const eval counter limit (20) has been crossed
|
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`
|
||||||
|
--> $DIR/ctfe-fn-call.rs:28:5
|
||||||
|
|
|
||||||
|
LL | foo();
|
||||||
|
| ^^^^^
|
||||||
|
note: inside `X`
|
||||||
|
--> $DIR/ctfe-fn-call.rs:32:16
|
||||||
|
|
|
||||||
|
LL | const X: u32 = call_foo();
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
warning: 1 warning emitted
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0080`.
|
||||||
|
@ -1,24 +1,18 @@
|
|||||||
// check-pass
|
// check-fail
|
||||||
#![feature(const_for)]
|
// compile-flags: -Z tiny-const-eval-limit
|
||||||
|
|
||||||
const fn labelled_loop() -> u32 {
|
const fn labelled_loop(n: u32) -> u32 {
|
||||||
let mut n = 0;
|
let mut i = 0;
|
||||||
'outer: loop {
|
'mylabel: loop { //~ ERROR evaluation of constant value failed [E0080]
|
||||||
'inner: loop {
|
if i > n {
|
||||||
n = n + 1;
|
break 'mylabel
|
||||||
if n > 5 && n <= 10 {
|
|
||||||
n = n + 1;
|
|
||||||
continue 'inner
|
|
||||||
}
|
|
||||||
if n > 30 {
|
|
||||||
break 'outer
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
n
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
const X: u32 = labelled_loop();
|
const X: u32 = labelled_loop(19);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("{X}");
|
println!("{X}");
|
||||||
|
@ -1,4 +1,30 @@
|
|||||||
warning: Const eval counter limit (20) has been crossed
|
error[E0080]: evaluation of constant value failed
|
||||||
|
--> $DIR/ctfe-labelled-loop.rs:6:5
|
||||||
|
|
|
||||||
|
LL | / 'mylabel: loop {
|
||||||
|
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 | | }
|
||||||
|
LL | | i += 1;
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
note: inside `X`
|
||||||
|
--> $DIR/ctfe-labelled-loop.rs:15:16
|
||||||
|
|
|
||||||
|
LL | const X: u32 = labelled_loop(19);
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
warning: 1 warning emitted
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0080`.
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
// check-pass
|
// check-fail
|
||||||
|
// compile-flags: -Z tiny-const-eval-limit
|
||||||
|
|
||||||
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)
|
recurse(n - 1) //~ ERROR evaluation of constant value failed [E0080]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const X: u32 = recurse(30);
|
const X: u32 = recurse(19);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("{X}");
|
println!("{X}");
|
||||||
|
@ -1,4 +1,25 @@
|
|||||||
warning: Const eval counter limit (20) has been crossed
|
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
|
||||||
|
|
|
||||||
|
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
|
||||||
|
|
|
||||||
|
LL | const X: u32 = recurse(19);
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
warning: 1 warning emitted
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0080`.
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
// check-pass
|
// check-fail
|
||||||
|
// 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;
|
||||||
let mut res = 0;
|
while index < n { //~ ERROR evaluation of constant value failed [E0080]
|
||||||
while index < n {
|
|
||||||
res = res + index;
|
|
||||||
index = index + 1;
|
index = index + 1;
|
||||||
}
|
}
|
||||||
res
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
const X: u32 = simple_loop(30);
|
const X: u32 = simple_loop(19);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("{X}");
|
println!("{X}");
|
||||||
|
@ -1,4 +1,24 @@
|
|||||||
warning: Const eval counter limit (20) has been crossed
|
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);
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
warning: 1 warning emitted
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0080`.
|
||||||
|
Loading…
Reference in New Issue
Block a user