From 337af5ef7a31855fd7f6d6b77c9e52d6d747c350 Mon Sep 17 00:00:00 2001 From: Christoph Schmidler Date: Thu, 12 Dec 2019 17:23:14 +0100 Subject: [PATCH 1/5] Prepare const_limit feature gate and attribute --- .../src/language-features/const-limit.md | 7 +++++++ .../middle/{recursion_limit.rs => limits.rs} | 3 ++- src/librustc_feature/active.rs | 3 +++ src/librustc_feature/builtin_attrs.rs | 4 ++++ src/librustc_session/session.rs | 4 ++++ src/librustc_span/symbol.rs | 1 + .../consts/const_limit/feature-gate-const_limit.rs | 12 ++++++++++++ .../const_limit/feature-gate-const_limit.stderr | 12 ++++++++++++ 8 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/doc/unstable-book/src/language-features/const-limit.md rename src/librustc/middle/{recursion_limit.rs => limits.rs} (94%) create mode 100644 src/test/ui/consts/const_limit/feature-gate-const_limit.rs create mode 100644 src/test/ui/consts/const_limit/feature-gate-const_limit.stderr diff --git a/src/doc/unstable-book/src/language-features/const-limit.md b/src/doc/unstable-book/src/language-features/const-limit.md new file mode 100644 index 0000000000000..2fc5963dc6e0b --- /dev/null +++ b/src/doc/unstable-book/src/language-features/const-limit.md @@ -0,0 +1,7 @@ +# `const_limit` + +The tracking issue for this feature is: [#67217] + +[#57563]: https://github.com/rust-lang/rust/issues/67217 + +The `const_limit` allows someone to limit the evaluation steps the CTFE undertakes to evaluate a `const fn`. \ No newline at end of file diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/limits.rs similarity index 94% rename from src/librustc/middle/recursion_limit.rs rename to src/librustc/middle/limits.rs index ae31a2cc63da6..a831d99d4ed00 100644 --- a/src/librustc/middle/recursion_limit.rs +++ b/src/librustc/middle/limits.rs @@ -1,4 +1,4 @@ -// Recursion limit. +// Registering limits, recursion_limit, type_length_limit and const_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 @@ -16,6 +16,7 @@ use rustc_data_structures::sync::Once; pub fn update_limits(sess: &Session, krate: &ast::Crate) { update_limit(sess, krate, &sess.recursion_limit, sym::recursion_limit, 128); update_limit(sess, krate, &sess.type_length_limit, sym::type_length_limit, 1048576); + update_limit(sess, krate, &sess.const_limit, sym::const_limit, 128); } fn update_limit( diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 0082f4f1a6e89..2f9394cd566fb 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -532,6 +532,9 @@ declare_features! ( /// Allows using `&mut` in constant functions. (active, const_mut_refs, "1.41.0", Some(57349), None), + // Allows limiting the evaluation steps of const expressions + (active, const_limit, "1.41.0", Some(67217), None), + /// Allows the use of `loop` and `while` in constants. (active, const_loop, "1.41.0", Some(52000), None), diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs index e2e061c185c03..2b79f6bd942b0 100644 --- a/src/librustc_feature/builtin_attrs.rs +++ b/src/librustc_feature/builtin_attrs.rs @@ -239,6 +239,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Limits: ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")), ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N")), + gated!( + const_limit, CrateLevel, template!(NameValueStr: "N"), const_limit, + experimental!(const_limit) + ), // Entry point: ungated!(main, Normal, template!(Word)), diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index 2fb7977dce9ee..a8879f00c802a 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -88,6 +88,9 @@ pub struct Session { /// The maximum length of types during monomorphization. pub type_length_limit: Once, + /// The maximum blocks a const expression can evaluate. + pub const_limit: Once, + /// Map from imported macro spans (which consist of /// the localized span for the macro body) to the /// macro name and definition span in the source crate. @@ -1053,6 +1056,7 @@ fn build_session_( features: Once::new(), recursion_limit: Once::new(), type_length_limit: Once::new(), + const_limit: Once::new(), imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())), incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), cgu_reuse_tracker, diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index d6232f32f4c1b..e92e2fc1d43f2 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -208,6 +208,7 @@ symbols! { console, const_compare_raw_pointers, const_constructor, + const_limit, const_extern_fn, const_fn, const_fn_union, diff --git a/src/test/ui/consts/const_limit/feature-gate-const_limit.rs b/src/test/ui/consts/const_limit/feature-gate-const_limit.rs new file mode 100644 index 0000000000000..11d2b6af25d25 --- /dev/null +++ b/src/test/ui/consts/const_limit/feature-gate-const_limit.rs @@ -0,0 +1,12 @@ +#![const_limit="1"] +//~^ ERROR the `#[const_limit]` attribute is an experimental feature [E0658] + +const CONSTANT: usize = limit(); + +fn main() {} + +const fn limit() -> usize { + let x = 42; + + x * 42 +} diff --git a/src/test/ui/consts/const_limit/feature-gate-const_limit.stderr b/src/test/ui/consts/const_limit/feature-gate-const_limit.stderr new file mode 100644 index 0000000000000..db248994b4779 --- /dev/null +++ b/src/test/ui/consts/const_limit/feature-gate-const_limit.stderr @@ -0,0 +1,12 @@ +error[E0658]: the `#[const_limit]` attribute is an experimental feature + --> $DIR/feature-gate-const_limit.rs:1:1 + | +LL | #![const_limit="1"] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/67217 + = help: add `#![feature(const_limit)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. From ff38babc31a364e77d1d4d3702c91884b073af17 Mon Sep 17 00:00:00 2001 From: Christoph Schmidler Date: Fri, 13 Dec 2019 09:38:07 +0100 Subject: [PATCH 2/5] Disable CTFE if const_limit was set to 0, otherwise use the value set, which defaults to 1_000_000 --- src/librustc/middle/limits.rs | 14 +++++++------- .../consts/const_limit/const_limit_not_reached.rs | 15 +++++++++++++++ .../ui/consts/const_limit/const_limit_overflow.rs | 15 +++++++++++++++ .../const_limit/feature-gate-const_limit.rs | 4 +++- 4 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/consts/const_limit/const_limit_not_reached.rs create mode 100644 src/test/ui/consts/const_limit/const_limit_overflow.rs diff --git a/src/librustc/middle/limits.rs b/src/librustc/middle/limits.rs index a831d99d4ed00..6ed0a498c7dce 100644 --- a/src/librustc/middle/limits.rs +++ b/src/librustc/middle/limits.rs @@ -1,9 +1,9 @@ -// Registering limits, recursion_limit, type_length_limit and const_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 -// this via an attribute on the crate like `#![recursion_limit="22"]`. This pass -// just peeks and looks for that attribute. +//! Registering limits, recursion_limit, type_length_limit and const_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 +//! this via an attribute on the crate like `#![recursion_limit="22"]`. This pass +//! just peeks and looks for that attribute. use crate::session::Session; use core::num::IntErrorKind; @@ -16,7 +16,7 @@ use rustc_data_structures::sync::Once; pub fn update_limits(sess: &Session, krate: &ast::Crate) { update_limit(sess, krate, &sess.recursion_limit, sym::recursion_limit, 128); update_limit(sess, krate, &sess.type_length_limit, sym::type_length_limit, 1048576); - update_limit(sess, krate, &sess.const_limit, sym::const_limit, 128); + update_limit(sess, krate, &sess.const_limit, sym::const_limit, 1_000_000); } fn update_limit( diff --git a/src/test/ui/consts/const_limit/const_limit_not_reached.rs b/src/test/ui/consts/const_limit/const_limit_not_reached.rs new file mode 100644 index 0000000000000..24c0f92af348a --- /dev/null +++ b/src/test/ui/consts/const_limit/const_limit_not_reached.rs @@ -0,0 +1,15 @@ +// run-pass +#![feature(const_limit)] +#![const_limit="1000"] + +const CONSTANT: usize = limit(); + +fn main() { + assert_eq!(CONSTANT, 1764); +} + +const fn limit() -> usize { + let x = 42; + + x * 42 +} diff --git a/src/test/ui/consts/const_limit/const_limit_overflow.rs b/src/test/ui/consts/const_limit/const_limit_overflow.rs new file mode 100644 index 0000000000000..bea40e60261ce --- /dev/null +++ b/src/test/ui/consts/const_limit/const_limit_overflow.rs @@ -0,0 +1,15 @@ +// run-pass +#![feature(const_limit)] +#![const_limit="18_446_744_073_709_551_615"] + +const CONSTANT: usize = limit(); + +fn main() { + assert_eq!(CONSTANT, 1764); +} + +const fn limit() -> usize { + let x = 42; + + x * 42 +} diff --git a/src/test/ui/consts/const_limit/feature-gate-const_limit.rs b/src/test/ui/consts/const_limit/feature-gate-const_limit.rs index 11d2b6af25d25..761e80050a6c9 100644 --- a/src/test/ui/consts/const_limit/feature-gate-const_limit.rs +++ b/src/test/ui/consts/const_limit/feature-gate-const_limit.rs @@ -3,7 +3,9 @@ const CONSTANT: usize = limit(); -fn main() {} +fn main() { + assert_eq!(CONSTANT, 1764); +} const fn limit() -> usize { let x = 42; From 288e142737af75007ef973c037cd4ded87d7e510 Mon Sep 17 00:00:00 2001 From: Christoph Schmidler Date: Sat, 14 Dec 2019 18:51:56 +0100 Subject: [PATCH 3/5] Add a new test to reach const_limit setting, although with wrong WARNINGs yet rename feature to const_eval_limit --- .../src/language-features/const-eval-limit.md | 7 +++++++ .../src/language-features/const-limit.md | 7 ------- src/librustc/middle/limits.rs | 4 ++-- src/librustc/middle/mod.rs | 2 +- src/librustc_feature/active.rs | 2 +- src/librustc_feature/builtin_attrs.rs | 4 ++-- src/librustc_interface/passes.rs | 2 +- src/librustc_session/session.rs | 4 ++-- src/librustc_span/symbol.rs | 2 +- ...overflow.rs => const_eval_limit_not_reached.rs} | 6 +++--- ...const_limit.rs => const_eval_limit_overflow.rs} | 5 +++-- ..._not_reached.rs => const_eval_limit_reached.rs} | 6 +++--- .../const_limit/feature-gate-const_eval_limit.rs | 14 ++++++++++++++ .../feature-gate-const_eval_limit.stderr | 12 ++++++++++++ .../const_limit/feature-gate-const_limit.stderr | 12 ------------ 15 files changed, 52 insertions(+), 37 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/const-eval-limit.md delete mode 100644 src/doc/unstable-book/src/language-features/const-limit.md rename src/test/ui/consts/const_limit/{const_limit_overflow.rs => const_eval_limit_not_reached.rs} (63%) rename src/test/ui/consts/const_limit/{feature-gate-const_limit.rs => const_eval_limit_overflow.rs} (59%) rename src/test/ui/consts/const_limit/{const_limit_not_reached.rs => const_eval_limit_reached.rs} (66%) create mode 100644 src/test/ui/consts/const_limit/feature-gate-const_eval_limit.rs create mode 100644 src/test/ui/consts/const_limit/feature-gate-const_eval_limit.stderr delete mode 100644 src/test/ui/consts/const_limit/feature-gate-const_limit.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 new file mode 100644 index 0000000000000..d1442d866dc8e --- /dev/null +++ b/src/doc/unstable-book/src/language-features/const-eval-limit.md @@ -0,0 +1,7 @@ +# `const_eval_limit` + +The tracking issue for this feature is: [#67217] + +[#57563]: 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 diff --git a/src/doc/unstable-book/src/language-features/const-limit.md b/src/doc/unstable-book/src/language-features/const-limit.md deleted file mode 100644 index 2fc5963dc6e0b..0000000000000 --- a/src/doc/unstable-book/src/language-features/const-limit.md +++ /dev/null @@ -1,7 +0,0 @@ -# `const_limit` - -The tracking issue for this feature is: [#67217] - -[#57563]: https://github.com/rust-lang/rust/issues/67217 - -The `const_limit` allows someone to limit the evaluation steps the CTFE undertakes to evaluate a `const fn`. \ No newline at end of file diff --git a/src/librustc/middle/limits.rs b/src/librustc/middle/limits.rs index 6ed0a498c7dce..19eb8a3fab881 100644 --- a/src/librustc/middle/limits.rs +++ b/src/librustc/middle/limits.rs @@ -1,4 +1,4 @@ -//! Registering limits, recursion_limit, type_length_limit and const_limit +//! Registering limits, recursion_limit, type_length_limit and const_eval_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 @@ -16,7 +16,7 @@ use rustc_data_structures::sync::Once; pub fn update_limits(sess: &Session, krate: &ast::Crate) { update_limit(sess, krate, &sess.recursion_limit, sym::recursion_limit, 128); update_limit(sess, krate, &sess.type_length_limit, sym::type_length_limit, 1048576); - update_limit(sess, krate, &sess.const_limit, sym::const_limit, 1_000_000); + update_limit(sess, krate, &sess.const_eval_limit, sym::const_eval_limit, 1_000_000); } fn update_limit( diff --git a/src/librustc/middle/mod.rs b/src/librustc/middle/mod.rs index b20f2cf3a85c1..464488964afb7 100644 --- a/src/librustc/middle/mod.rs +++ b/src/librustc/middle/mod.rs @@ -28,8 +28,8 @@ pub mod lib_features { } } } +pub mod limits; pub mod privacy; -pub mod recursion_limit; pub mod region; pub mod resolve_lifetime; pub mod stability; diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 2f9394cd566fb..9bfb1a3a66498 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -533,7 +533,7 @@ declare_features! ( (active, const_mut_refs, "1.41.0", Some(57349), None), // Allows limiting the evaluation steps of const expressions - (active, const_limit, "1.41.0", Some(67217), None), + (active, const_eval_limit, "1.41.0", Some(67217), None), /// Allows the use of `loop` and `while` in constants. (active, const_loop, "1.41.0", Some(52000), None), diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs index 2b79f6bd942b0..c140adf64d511 100644 --- a/src/librustc_feature/builtin_attrs.rs +++ b/src/librustc_feature/builtin_attrs.rs @@ -240,8 +240,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")), ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N")), gated!( - const_limit, CrateLevel, template!(NameValueStr: "N"), const_limit, - experimental!(const_limit) + const_eval_limit, CrateLevel, template!(NameValueStr: "N"), const_eval_limit, + experimental!(const_eval_limit) ), // Entry point: diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 1e9b76c3e14d2..29e9ea1833f8e 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -189,7 +189,7 @@ pub fn register_plugins<'a>( } sess.time("recursion_limit", || { - middle::recursion_limit::update_limits(sess, &krate); + middle::limits::update_limits(sess, &krate); }); let mut lint_store = rustc_lint::new_lint_store( diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index a8879f00c802a..173b120e1f6d7 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -89,7 +89,7 @@ pub struct Session { pub type_length_limit: Once, /// The maximum blocks a const expression can evaluate. - pub const_limit: Once, + pub const_eval_limit: Once, /// Map from imported macro spans (which consist of /// the localized span for the macro body) to the @@ -1056,7 +1056,7 @@ fn build_session_( features: Once::new(), recursion_limit: Once::new(), type_length_limit: Once::new(), - const_limit: Once::new(), + const_eval_limit: Once::new(), imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())), incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), cgu_reuse_tracker, diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index e92e2fc1d43f2..c39f9f360c027 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -208,7 +208,7 @@ symbols! { console, const_compare_raw_pointers, const_constructor, - const_limit, + const_eval_limit, const_extern_fn, const_fn, const_fn_union, diff --git a/src/test/ui/consts/const_limit/const_limit_overflow.rs b/src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs similarity index 63% rename from src/test/ui/consts/const_limit/const_limit_overflow.rs rename to src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs index bea40e60261ce..4ed908312fb6d 100644 --- a/src/test/ui/consts/const_limit/const_limit_overflow.rs +++ b/src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs @@ -1,6 +1,6 @@ -// run-pass -#![feature(const_limit)] -#![const_limit="18_446_744_073_709_551_615"] +// check-pass +#![feature(const_eval_limit)] +#![const_eval_limit="1000"] const CONSTANT: usize = limit(); diff --git a/src/test/ui/consts/const_limit/feature-gate-const_limit.rs b/src/test/ui/consts/const_limit/const_eval_limit_overflow.rs similarity index 59% rename from src/test/ui/consts/const_limit/feature-gate-const_limit.rs rename to src/test/ui/consts/const_limit/const_eval_limit_overflow.rs index 761e80050a6c9..38e70f997f031 100644 --- a/src/test/ui/consts/const_limit/feature-gate-const_limit.rs +++ b/src/test/ui/consts/const_limit/const_eval_limit_overflow.rs @@ -1,5 +1,6 @@ -#![const_limit="1"] -//~^ ERROR the `#[const_limit]` attribute is an experimental feature [E0658] +// check-pass +#![feature(const_eval_limit)] +#![const_eval_limit="18_446_744_073_709_551_615"] const CONSTANT: usize = limit(); diff --git a/src/test/ui/consts/const_limit/const_limit_not_reached.rs b/src/test/ui/consts/const_limit/const_eval_limit_reached.rs similarity index 66% rename from src/test/ui/consts/const_limit/const_limit_not_reached.rs rename to src/test/ui/consts/const_limit/const_eval_limit_reached.rs index 24c0f92af348a..86570c240e5f0 100644 --- a/src/test/ui/consts/const_limit/const_limit_not_reached.rs +++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.rs @@ -1,6 +1,6 @@ -// run-pass -#![feature(const_limit)] -#![const_limit="1000"] +// check-pass +#![feature(const_eval_limit)] +#![const_eval_limit="2"] const CONSTANT: usize = limit(); diff --git a/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.rs b/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.rs new file mode 100644 index 0000000000000..61119d7511d49 --- /dev/null +++ b/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.rs @@ -0,0 +1,14 @@ +#![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/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 new file mode 100644 index 0000000000000..790ba2483a1b6 --- /dev/null +++ b/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.stderr @@ -0,0 +1,12 @@ +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: for more information, see https://github.com/rust-lang/rust/issues/67217 + = 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`. diff --git a/src/test/ui/consts/const_limit/feature-gate-const_limit.stderr b/src/test/ui/consts/const_limit/feature-gate-const_limit.stderr deleted file mode 100644 index db248994b4779..0000000000000 --- a/src/test/ui/consts/const_limit/feature-gate-const_limit.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: the `#[const_limit]` attribute is an experimental feature - --> $DIR/feature-gate-const_limit.rs:1:1 - | -LL | #![const_limit="1"] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/67217 - = help: add `#![feature(const_limit)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. From c94c74e2d936213cabcbb9675f81007ac7c3b78a Mon Sep 17 00:00:00 2001 From: Christoph Schmidler Date: Tue, 21 Jan 2020 16:46:07 +0100 Subject: [PATCH 4/5] 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 d1442d866dc8e..df68e83bcac74 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 4d5464f774ff5..1bf748e66e2a0 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 25727b75faf14..ed8029834680c 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 86570c240e5f0..1e146d447fa99 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 0000000000000..8301dff6005c7 --- /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 790ba2483a1b6..5bd29c7dfd22b 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 From 527456e219d1d898eee53b2d0e29cdb296c7bab8 Mon Sep 17 00:00:00 2001 From: Christoph Schmidler Date: Wed, 19 Feb 2020 10:24:16 +0100 Subject: [PATCH 5/5] Bumped version number for const_eval_limit in active.rs and renamed 'recursion_limit' in limits.rs to simple 'limit' because it does handle other limits too. --- src/librustc/middle/limits.rs | 14 ++++++-------- src/librustc_feature/active.rs | 6 +++--- .../const_limit/const_eval_limit_overflow.rs | 2 +- .../const_limit/const_eval_limit_overflow.stderr | 10 ++++++++++ .../consts/const_limit/const_eval_limit_reached.rs | 6 +++++- .../const_limit/const_eval_limit_reached.stderr | 12 +++++++++++- src/test/ui/recursion_limit/empty.rs | 4 ++-- src/test/ui/recursion_limit/empty.stderr | 4 ++-- src/test/ui/recursion_limit/invalid_digit.rs | 2 +- src/test/ui/recursion_limit/invalid_digit.stderr | 2 +- src/test/ui/recursion_limit/overflow.rs | 4 ++-- src/test/ui/recursion_limit/overflow.stderr | 4 ++-- src/test/ui/recursion_limit/zero.rs | 2 +- 13 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 src/test/ui/consts/const_limit/const_eval_limit_overflow.stderr diff --git a/src/librustc/middle/limits.rs b/src/librustc/middle/limits.rs index 19eb8a3fab881..22e4f5ea22261 100644 --- a/src/librustc/middle/limits.rs +++ b/src/librustc/middle/limits.rs @@ -38,10 +38,8 @@ fn update_limit( return; } Err(e) => { - let mut err = sess.struct_span_err( - attr.span, - "`recursion_limit` must be a non-negative integer", - ); + let mut err = + sess.struct_span_err(attr.span, "`limit` must be a non-negative integer"); let value_span = attr .meta() @@ -50,11 +48,11 @@ fn update_limit( .unwrap_or(attr.span); let error_str = match e.kind() { - IntErrorKind::Overflow => "`recursion_limit` is too large", - IntErrorKind::Empty => "`recursion_limit` must be a non-negative integer", + IntErrorKind::Overflow => "`limit` is too large", + IntErrorKind::Empty => "`limit` must be a non-negative integer", IntErrorKind::InvalidDigit => "not a valid integer", - IntErrorKind::Underflow => bug!("`recursion_limit` should never underflow"), - IntErrorKind::Zero => bug!("zero is a valid `recursion_limit`"), + IntErrorKind::Underflow => bug!("`limit` should never underflow"), + IntErrorKind::Zero => bug!("zero is a valid `limit`"), kind => bug!("unimplemented IntErrorKind variant: {:?}", kind), }; diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 9bfb1a3a66498..6517a22701b0e 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -532,9 +532,6 @@ declare_features! ( /// Allows using `&mut` in constant functions. (active, const_mut_refs, "1.41.0", Some(57349), None), - // Allows limiting the evaluation steps of const expressions - (active, const_eval_limit, "1.41.0", Some(67217), None), - /// Allows the use of `loop` and `while` in constants. (active, const_loop, "1.41.0", Some(52000), None), @@ -555,6 +552,9 @@ declare_features! ( /// Allows the use of `no_sanitize` attribute. (active, no_sanitize, "1.42.0", Some(39699), None), + // Allows limiting the evaluation steps of const expressions + (active, const_eval_limit, "1.43.0", Some(67217), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/test/ui/consts/const_limit/const_eval_limit_overflow.rs b/src/test/ui/consts/const_limit/const_eval_limit_overflow.rs index 38e70f997f031..1c49593cd53fa 100644 --- a/src/test/ui/consts/const_limit/const_eval_limit_overflow.rs +++ b/src/test/ui/consts/const_limit/const_eval_limit_overflow.rs @@ -1,6 +1,6 @@ -// check-pass #![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(); diff --git a/src/test/ui/consts/const_limit/const_eval_limit_overflow.stderr b/src/test/ui/consts/const_limit/const_eval_limit_overflow.stderr new file mode 100644 index 0000000000000..7f5d5e6cd4c5a --- /dev/null +++ b/src/test/ui/consts/const_limit/const_eval_limit_overflow.stderr @@ -0,0 +1,10 @@ +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/src/test/ui/consts/const_limit/const_eval_limit_reached.rs b/src/test/ui/consts/const_limit/const_eval_limit_reached.rs index 1e146d447fa99..d962398d4136e 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,5 +1,9 @@ +// ignore-tidy-linelength // only-x86_64 // check-pass +// NOTE: We always compile this test with -Copt-level=0 because higher opt-levels +// optimize away the const function +// compile-flags:-Copt-level=0 #![feature(const_eval_limit)] #![const_eval_limit="2"] @@ -10,7 +14,7 @@ fn main() { assert_eq!(CONSTANT, 1764); } -const fn limit() -> usize { +const fn limit() -> usize { //~ WARNING Constant evaluating a complex constant, this might take some time let x = 42; x * 42 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 index 8301dff6005c7..e0871ff718561 100644 --- a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr +++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr @@ -1,5 +1,15 @@ warning: Constant evaluating a complex constant, this might take some time - --> $DIR/const_eval_limit_reached.rs:6:1 + --> $DIR/const_eval_limit_reached.rs:17:1 + | +LL | / const fn limit() -> usize { +LL | | let x = 42; +LL | | +LL | | x * 42 +LL | | } + | |_^ + +warning: Constant evaluating a complex constant, this might take some time + --> $DIR/const_eval_limit_reached.rs:10:1 | LL | const CONSTANT: usize = limit(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/recursion_limit/empty.rs b/src/test/ui/recursion_limit/empty.rs index 2a064f3e11599..31ff9c1e3a72e 100644 --- a/src/test/ui/recursion_limit/empty.rs +++ b/src/test/ui/recursion_limit/empty.rs @@ -1,6 +1,6 @@ // Test the parse error for an empty recursion_limit -#![recursion_limit = ""] //~ ERROR `recursion_limit` must be a non-negative integer - //~| `recursion_limit` must be a non-negative integer +#![recursion_limit = ""] //~ ERROR `limit` must be a non-negative integer + //~| `limit` must be a non-negative integer fn main() {} diff --git a/src/test/ui/recursion_limit/empty.stderr b/src/test/ui/recursion_limit/empty.stderr index 690c33a746307..bcd1d27e59b56 100644 --- a/src/test/ui/recursion_limit/empty.stderr +++ b/src/test/ui/recursion_limit/empty.stderr @@ -1,10 +1,10 @@ -error: `recursion_limit` must be a non-negative integer +error: `limit` must be a non-negative integer --> $DIR/empty.rs:3:1 | LL | #![recursion_limit = ""] | ^^^^^^^^^^^^^^^^^^^^^--^ | | - | `recursion_limit` must be a non-negative integer + | `limit` must be a non-negative integer error: aborting due to previous error diff --git a/src/test/ui/recursion_limit/invalid_digit.rs b/src/test/ui/recursion_limit/invalid_digit.rs index 903d804047696..759d69d0af20d 100644 --- a/src/test/ui/recursion_limit/invalid_digit.rs +++ b/src/test/ui/recursion_limit/invalid_digit.rs @@ -1,6 +1,6 @@ // Test the parse error for an invalid digit in recursion_limit -#![recursion_limit = "-100"] //~ ERROR `recursion_limit` must be a non-negative integer +#![recursion_limit = "-100"] //~ ERROR `limit` must be a non-negative integer //~| not a valid integer fn main() {} diff --git a/src/test/ui/recursion_limit/invalid_digit.stderr b/src/test/ui/recursion_limit/invalid_digit.stderr index 1dcfea547c0bd..e6fd6b72a0900 100644 --- a/src/test/ui/recursion_limit/invalid_digit.stderr +++ b/src/test/ui/recursion_limit/invalid_digit.stderr @@ -1,4 +1,4 @@ -error: `recursion_limit` must be a non-negative integer +error: `limit` must be a non-negative integer --> $DIR/invalid_digit.rs:3:1 | LL | #![recursion_limit = "-100"] diff --git a/src/test/ui/recursion_limit/overflow.rs b/src/test/ui/recursion_limit/overflow.rs index 6487b1350aa98..8eee2792b2383 100644 --- a/src/test/ui/recursion_limit/overflow.rs +++ b/src/test/ui/recursion_limit/overflow.rs @@ -1,7 +1,7 @@ // Test the parse error for an overflowing recursion_limit #![recursion_limit = "999999999999999999999999"] -//~^ ERROR `recursion_limit` must be a non-negative integer -//~| `recursion_limit` is too large +//~^ ERROR `limit` must be a non-negative integer +//~| `limit` is too large fn main() {} diff --git a/src/test/ui/recursion_limit/overflow.stderr b/src/test/ui/recursion_limit/overflow.stderr index c3fc11989dcec..f6ed76c1ebc0e 100644 --- a/src/test/ui/recursion_limit/overflow.stderr +++ b/src/test/ui/recursion_limit/overflow.stderr @@ -1,10 +1,10 @@ -error: `recursion_limit` must be a non-negative integer +error: `limit` must be a non-negative integer --> $DIR/overflow.rs:3:1 | LL | #![recursion_limit = "999999999999999999999999"] | ^^^^^^^^^^^^^^^^^^^^^--------------------------^ | | - | `recursion_limit` is too large + | `limit` is too large error: aborting due to previous error diff --git a/src/test/ui/recursion_limit/zero.rs b/src/test/ui/recursion_limit/zero.rs index f7199944e0063..eb95d7babc6b2 100644 --- a/src/test/ui/recursion_limit/zero.rs +++ b/src/test/ui/recursion_limit/zero.rs @@ -1,4 +1,4 @@ -// Test that a `recursion_limit` of 0 is valid +// Test that a `limit` of 0 is valid #![recursion_limit = "0"]