Skip to content

Commit

Permalink
Auto merge of #119821 - oli-obk:reveal_all_const_evals, r=lcnr
Browse files Browse the repository at this point in the history
Always use RevealAll for const eval queries

implements what is described in #116803 (comment)

Using `UserFacing` for const eval does not make sense anymore, unless we significantly change things like avoiding revealing opaque types.

New tests are copied from #101478
  • Loading branch information
bors committed Jan 20, 2024
2 parents 128148d + 867831a commit 5378c1c
Show file tree
Hide file tree
Showing 32 changed files with 363 additions and 108 deletions.
38 changes: 9 additions & 29 deletions compiler/rustc_const_eval/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,17 +225,10 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
// see comment in eval_to_allocation_raw_provider for what we're doing here
if key.param_env.reveal() == Reveal::All {
let mut key = key;
key.param_env = key.param_env.with_user_facing();
match tcx.eval_to_const_value_raw(key) {
// try again with reveal all as requested
Err(ErrorHandled::TooGeneric(_)) => {}
// deduplicate calls
other => return other,
}
}
// Const eval always happens in Reveal::All mode in order to be able to use the hidden types of
// opaque types. This is needed for trivial things like `size_of`, but also for using associated
// types that are not specified in the opaque type.
assert_eq!(key.param_env.reveal(), Reveal::All);

// We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
Expand Down Expand Up @@ -265,24 +258,11 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
// Because the constant is computed twice (once per value of `Reveal`), we are at risk of
// reporting the same error twice here. To resolve this, we check whether we can evaluate the
// constant in the more restrictive `Reveal::UserFacing`, which most likely already was
// computed. For a large percentage of constants that will already have succeeded. Only
// associated constants of generic functions will fail due to not enough monomorphization
// information being available.

// In case we fail in the `UserFacing` variant, we just do the real computation.
if key.param_env.reveal() == Reveal::All {
let mut key = key;
key.param_env = key.param_env.with_user_facing();
match tcx.eval_to_allocation_raw(key) {
// try again with reveal all as requested
Err(ErrorHandled::TooGeneric(_)) => {}
// deduplicate calls
other => return other,
}
}
// Const eval always happens in Reveal::All mode in order to be able to use the hidden types of
// opaque types. This is needed for trivial things like `size_of`, but also for using associated
// types that are not specified in the opaque type.

assert_eq!(key.param_env.reveal(), Reveal::All);
if cfg!(debug_assertions) {
// Make sure we format the instance even if we do not print it.
// This serves as a regression test against an ICE on printing.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/mir/interpret/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl<'tcx> TyCtxt<'tcx> {
) -> EvalToConstValueResult<'tcx> {
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
// improve caching of queries.
let inputs = self.erase_regions(param_env.and(cid));
let inputs = self.erase_regions(param_env.with_reveal_all_normalized(self).and(cid));
if let Some(span) = span {
// The query doesn't know where it is being invoked, so we need to fix the span.
self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span))
Expand All @@ -164,7 +164,7 @@ impl<'tcx> TyCtxt<'tcx> {
) -> EvalToValTreeResult<'tcx> {
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
// improve caching of queries.
let inputs = self.erase_regions(param_env.and(cid));
let inputs = self.erase_regions(param_env.with_reveal_all_normalized(self).and(cid));
debug!(?inputs);
if let Some(span) = span {
// The query doesn't know where it is being invoked, so we need to fix the span.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`.
|
LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
|
LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `IMPL_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:27
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ note: ...which requires simplifying constant for the type system `DEFAULT_REF_BA
|
LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1
|
LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:30
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`
|
LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1
|
LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:28
|
Expand Down
5 changes: 2 additions & 3 deletions tests/ui/consts/const-eval/const-eval-query-stack.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ LL | const X: i32 = 1 / 0;
query stack during panic:
#0 [eval_to_allocation_raw] const-evaluating + checking `X`
#1 [eval_to_const_value_raw] simplifying constant for the type system `X`
#2 [eval_to_const_value_raw] simplifying constant for the type system `X`
#3 [lint_mod] linting top-level module
#4 [analysis] running analysis passes on this crate
#2 [lint_mod] linting top-level module
#3 [analysis] running analysis passes on this crate
end of query stack
5 changes: 0 additions & 5 deletions tests/ui/consts/const-size_of-cycle.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ LL | bytes: [u8; std::mem::size_of::<Foo>()]
note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
--> $DIR/const-size_of-cycle.rs:4:17
|
LL | bytes: [u8; std::mem::size_of::<Foo>()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
--> $DIR/const-size_of-cycle.rs:4:17
|
LL | bytes: [u8; std::mem::size_of::<Foo>()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing layout of `Foo`...
Expand Down
14 changes: 10 additions & 4 deletions tests/ui/consts/issue-36163.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@ note: ...which requires const-evaluating + checking `A`...
LL | const A: isize = Foo::B as isize;
| ^^^^^^^^^^^^^^^
= note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle
note: cycle used when simplifying constant for the type system `Foo::B::{constant#0}`
--> $DIR/issue-36163.rs:4:9
note: cycle used when collecting item types in top-level module
--> $DIR/issue-36163.rs:1:1
|
LL | B = A,
| ^
LL | / const A: isize = Foo::B as isize;
LL | |
LL | | enum Foo {
LL | | B = A,
LL | | }
LL | |
LL | | fn main() {}
| |____________^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

error: aborting due to 1 previous error
Expand Down
5 changes: 0 additions & 5 deletions tests/ui/consts/issue-44415.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
--> $DIR/issue-44415.rs:6:17
|
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
--> $DIR/issue-44415.rs:6:17
|
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing layout of `Foo`...
Expand Down
9 changes: 2 additions & 7 deletions tests/ui/consts/recursive-zst-static.default.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
error[E0391]: cycle detected when const-evaluating + checking `FOO`
--> $DIR/recursive-zst-static.rs:10:1
|
LL | static FOO: () = FOO;
| ^^^^^^^^^^^^^^
|
note: ...which requires const-evaluating + checking `FOO`...
--> $DIR/recursive-zst-static.rs:10:18
|
LL | static FOO: () = FOO;
| ^^^
= note: ...which again requires const-evaluating + checking `FOO`, completing the cycle
|
= note: ...which immediately requires const-evaluating + checking `FOO` again
note: cycle used when linting top-level module
--> $DIR/recursive-zst-static.rs:10:1
|
Expand Down
9 changes: 2 additions & 7 deletions tests/ui/consts/recursive-zst-static.unleash.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
error[E0391]: cycle detected when const-evaluating + checking `FOO`
--> $DIR/recursive-zst-static.rs:10:1
|
LL | static FOO: () = FOO;
| ^^^^^^^^^^^^^^
|
note: ...which requires const-evaluating + checking `FOO`...
--> $DIR/recursive-zst-static.rs:10:18
|
LL | static FOO: () = FOO;
| ^^^
= note: ...which again requires const-evaluating + checking `FOO`, completing the cycle
|
= note: ...which immediately requires const-evaluating + checking `FOO` again
note: cycle used when linting top-level module
--> $DIR/recursive-zst-static.rs:10:1
|
Expand Down
9 changes: 2 additions & 7 deletions tests/ui/consts/write-to-static-mut-in-static.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,12 @@ LL | pub static mut B: () = unsafe { A = 1; };
| ^^^^^ modifying a static's initial value from another static's initializer

error[E0391]: cycle detected when const-evaluating + checking `C`
--> $DIR/write-to-static-mut-in-static.rs:5:1
|
LL | pub static mut C: u32 = unsafe { C = 1; 0 };
| ^^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires const-evaluating + checking `C`...
--> $DIR/write-to-static-mut-in-static.rs:5:34
|
LL | pub static mut C: u32 = unsafe { C = 1; 0 };
| ^^^^^
= note: ...which again requires const-evaluating + checking `C`, completing the cycle
|
= note: ...which immediately requires const-evaluating + checking `C` again
note: cycle used when linting top-level module
--> $DIR/write-to-static-mut-in-static.rs:1:1
|
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/impl-trait/in-ctfe/array-len-size-of.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! Check that const eval can use the size of opaque types.
// check-pass
use std::mem;
fn returns_opaque() -> impl Sized {
0u8
}

struct NamedOpaqueType {
data: [mem::MaybeUninit<u8>; size_of_fut(returns_opaque)],
}

const fn size_of_fut<FUT>(x: fn() -> FUT) -> usize {
mem::size_of::<FUT>()
}

fn main() {}
22 changes: 22 additions & 0 deletions tests/ui/impl-trait/in-ctfe/array-len.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! Check that array lengths can observe associated types of opaque types
// check-pass
trait MyTrait: Copy {
const ASSOC: usize;
}

impl MyTrait for u8 {
const ASSOC: usize = 32;
}

const fn yeet() -> impl MyTrait {
0u8
}

const fn output<T: MyTrait>(_: T) -> usize {
<T as MyTrait>::ASSOC
}

fn main() {
let x = [0u8; output(yeet())];
println!("{:?}", x);
}
26 changes: 26 additions & 0 deletions tests/ui/impl-trait/in-ctfe/enum-discr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//! check that const eval can observe associated types of opaque types.
// check-pass
trait MyTrait: Copy {
const ASSOC: usize;
}

impl MyTrait for u8 {
const ASSOC: usize = 32;
}

const fn yeet() -> impl MyTrait {
0u8
}

const fn output<T: MyTrait>(_: T) -> usize {
<T as MyTrait>::ASSOC
}

#[repr(usize)]
enum Foo {
Bar = output(yeet()),
}

fn main() {
println!("{}", Foo::Bar as usize);
}
29 changes: 29 additions & 0 deletions tests/ui/impl-trait/in-ctfe/fully_monomorphic_const_eval.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//! This test ensures that we do look at the hidden types of
//! opaque types during const eval in order to obtain the exact type
//! of associated types.

// check-pass

trait MyTrait: Copy {
const ASSOC: usize;
}

impl MyTrait for u8 {
const ASSOC: usize = 32;
}

const fn yeet() -> impl MyTrait {
0u8
}

const fn output<T: MyTrait>(_: T) -> usize {
<T as MyTrait>::ASSOC
}

struct Foo<'a>(&'a ());
const NEED_REVEAL_ALL: usize = output(yeet());

fn promote_div() -> &'static usize {
&(10 / NEED_REVEAL_ALL)
}
fn main() {}
24 changes: 24 additions & 0 deletions tests/ui/impl-trait/in-ctfe/match-arm-exhaustive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//! Check that pattern matching can observe the hidden type of opaque types.
// check-pass
trait MyTrait: Copy {
const ASSOC: u8;
}

impl MyTrait for () {
const ASSOC: u8 = 0;
}

const fn yeet() -> impl MyTrait {}

const fn output<T: MyTrait>(_: T) -> u8 {
<T as MyTrait>::ASSOC
}

const CT: u8 = output(yeet());

fn main() {
match 0 {
CT => (),
1.. => (),
}
}
14 changes: 14 additions & 0 deletions tests/ui/impl-trait/transmute/in-defining-scope.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// This causes a query cycle due to using `Reveal::All`,
// in #119821 const eval was changed to always use `Reveal::All`
//
// See that PR for more details.
use std::mem::transmute;
fn foo() -> impl Sized {
//~^ ERROR cycle detected when computing type of
unsafe {
transmute::<_, u8>(foo());
}
0u8
}

fn main() {}
29 changes: 29 additions & 0 deletions tests/ui/impl-trait/transmute/in-defining-scope.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
error[E0391]: cycle detected when computing type of `foo::{opaque#0}`
--> $DIR/in-defining-scope.rs:6:13
|
LL | fn foo() -> impl Sized {
| ^^^^^^^^^^
|
note: ...which requires computing type of opaque `foo::{opaque#0}`...
--> $DIR/in-defining-scope.rs:6:13
|
LL | fn foo() -> impl Sized {
| ^^^^^^^^^^
note: ...which requires type-checking `foo`...
--> $DIR/in-defining-scope.rs:6:1
|
LL | fn foo() -> impl Sized {
| ^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing layout of `foo::{opaque#0}`...
= note: ...which requires normalizing `foo::{opaque#0}`...
= note: ...which again requires computing type of `foo::{opaque#0}`, completing the cycle
note: cycle used when checking that `foo::{opaque#0}` is well-formed
--> $DIR/in-defining-scope.rs:6:13
|
LL | fn foo() -> impl Sized {
| ^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0391`.
12 changes: 12 additions & 0 deletions tests/ui/impl-trait/transmute/outside-of-defining-scope.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//! Check that typeck can observe the size of an opaque type.
// check-pass
use std::mem::transmute;
fn foo() -> impl Sized {
0u8
}

fn main() {
unsafe {
transmute::<_, u8>(foo());
}
}

0 comments on commit 5378c1c

Please sign in to comment.