Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always use RevealAll for const eval queries #119821

Merged
merged 1 commit into from
Jan 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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());
}
}