From c94c74e2d936213cabcbb9675f81007ac7c3b78a Mon Sep 17 00:00:00 2001 From: Christoph Schmidler Date: Tue, 21 Jan 2020 16:46:07 +0100 Subject: [PATCH] Opt out of CTFE if the 'const_eval_limit' is set to 0 --- .../src/language-features/const-eval-limit.md | 4 ++-- src/librustc_mir/const_eval/eval_queries.rs | 4 ++-- src/librustc_mir/const_eval/machine.rs | 18 +++++++++++++----- .../const_limit/const_eval_limit_reached.rs | 2 ++ .../const_eval_limit_reached.stderr | 6 ++++++ .../feature-gate-const_eval_limit.stderr | 2 +- 6 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/consts/const_limit/const_eval_limit_reached.stderr 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 index d1442d866dc8..df68e83bcac7 100644 --- a/src/doc/unstable-book/src/language-features/const-eval-limit.md +++ b/src/doc/unstable-book/src/language-features/const-eval-limit.md @@ -2,6 +2,6 @@ The tracking issue for this feature is: [#67217] -[#57563]: https://github.com/rust-lang/rust/issues/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`. \ No newline at end of file +The `const_eval_limit` allows someone to limit the evaluation steps the CTFE undertakes to evaluate a `const fn`. diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 4d5464f774ff..1bf748e66e2a 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -89,7 +89,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>( InterpCx::new( tcx.at(span), param_env, - CompileTimeInterpreter::new(), + CompileTimeInterpreter::new(*tcx.sess.const_eval_limit.get()), MemoryExtra { can_access_statics }, ) } @@ -297,7 +297,7 @@ pub fn const_eval_raw_provider<'tcx>( let mut ecx = InterpCx::new( tcx.at(span), key.param_env, - CompileTimeInterpreter::new(), + CompileTimeInterpreter::new(*tcx.sess.const_eval_limit.get()), MemoryExtra { can_access_statics: is_static }, ); diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs index 25727b75faf1..ed8029834680 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/src/librustc_mir/const_eval/machine.rs @@ -3,6 +3,7 @@ use rustc::ty::layout::HasTyCtxt; use rustc::ty::{self, Ty}; use std::borrow::{Borrow, Cow}; use std::collections::hash_map::Entry; +use std::convert::TryFrom; use std::hash::Hash; use rustc_data_structures::fx::FxHashMap; @@ -85,9 +86,6 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { } } -/// Number of steps until the detector even starts doing anything. -/// Also, a warning is shown to the user when this number is reached. -const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000; /// The number of steps between loop detector snapshots. /// Should be a power of two for performance reasons. const DETECTOR_SNAPSHOT_PERIOD: isize = 256; @@ -100,6 +98,8 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> { /// detector period. pub(super) steps_since_detector_enabled: isize, + pub(super) is_detector_enabled: bool, + /// Extra state to detect loops. pub(super) loop_detector: snapshot::InfiniteLoopDetector<'mir, 'tcx>, } @@ -111,10 +111,14 @@ pub struct MemoryExtra { } impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { - pub(super) fn new() -> Self { + pub(super) fn new(const_eval_limit: usize) -> Self { + let steps_until_detector_enabled = + isize::try_from(const_eval_limit).unwrap_or(std::isize::MAX); + CompileTimeInterpreter { loop_detector: Default::default(), - steps_since_detector_enabled: -STEPS_UNTIL_DETECTOR_ENABLED, + steps_since_detector_enabled: -steps_until_detector_enabled, + is_detector_enabled: const_eval_limit != 0, } } } @@ -343,6 +347,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + if !ecx.machine.is_detector_enabled { + return Ok(()); + } + { let steps = &mut ecx.machine.steps_since_detector_enabled; diff --git a/src/test/ui/consts/const_limit/const_eval_limit_reached.rs b/src/test/ui/consts/const_limit/const_eval_limit_reached.rs index 86570c240e5f..1e146d447fa9 100644 --- a/src/test/ui/consts/const_limit/const_eval_limit_reached.rs +++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.rs @@ -1,8 +1,10 @@ +// only-x86_64 // check-pass #![feature(const_eval_limit)] #![const_eval_limit="2"] const CONSTANT: usize = limit(); +//~^ WARNING Constant evaluating a complex constant, this might take some time fn main() { assert_eq!(CONSTANT, 1764); diff --git a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr new file mode 100644 index 000000000000..8301dff6005c --- /dev/null +++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr @@ -0,0 +1,6 @@ +warning: Constant evaluating a complex constant, this might take some time + --> $DIR/const_eval_limit_reached.rs:6:1 + | +LL | const CONSTANT: usize = limit(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.stderr b/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.stderr index 790ba2483a1b..5bd29c7dfd22 100644 --- a/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.stderr +++ b/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.stderr @@ -4,7 +4,7 @@ error[E0658]: the `#[const_eval_limit]` attribute is an experimental feature LL | #![const_eval_limit="42"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: for more information, see https://github.com/rust-lang/rust/issues/67217 + = 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