Skip to content

Commit 4a9ab29

Browse files
committed
properly fill a promoted's required_consts
1 parent 7092891 commit 4a9ab29

File tree

9 files changed

+150
-36
lines changed

9 files changed

+150
-36
lines changed

compiler/rustc_const_eval/src/const_eval/machine.rs

+2-11
Original file line numberDiff line numberDiff line change
@@ -376,17 +376,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
376376
const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
377377

378378
#[inline]
379-
fn all_required_consts_are_checked(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
380-
// Generally we expect required_consts to be properly filled, except for promoteds where
381-
// storing these consts shows up negatively in benchmarks. A promoted can only be relevant
382-
// if its parent MIR is relevant, and the consts in the promoted will be in the parent's
383-
// `required_consts`, so we are still sure to catch any const-eval bugs, just a bit less
384-
// directly.
385-
if ecx.frame_idx() == 0 && ecx.frame().body.source.promoted.is_some() {
386-
false
387-
} else {
388-
true
389-
}
379+
fn all_required_consts_are_checked(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
380+
true
390381
}
391382

392383
#[inline(always)]

compiler/rustc_middle/src/mir/consts.rs

+18
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,24 @@ impl<'tcx> Const<'tcx> {
238238
}
239239
}
240240

241+
/// Determines whether we need to add this const to `required_consts`. This is the case if and
242+
/// only if evaluating it may error.
243+
#[inline]
244+
pub fn is_required_const(&self) -> bool {
245+
match self {
246+
Const::Ty(c) => match c.kind() {
247+
ty::ConstKind::Value(_) => false, // already a value, cannot error
248+
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) => true, // these are errors or could be replaced by errors
249+
_ => bug!(
250+
"only ConstKind::Param/Value/Error should be encountered here, got {:#?}",
251+
c
252+
),
253+
},
254+
Const::Unevaluated(..) => true,
255+
Const::Val(..) => false, // already a value, cannot error
256+
}
257+
}
258+
241259
#[inline]
242260
pub fn try_to_scalar(self) -> Option<Scalar> {
243261
match self {

compiler/rustc_mir_transform/src/promote_consts.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
953953
*local = self.promote_temp(*local);
954954
}
955955
}
956+
957+
fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, _location: Location) {
958+
if constant.const_.is_required_const() {
959+
self.promoted.required_consts.push(*constant);
960+
}
961+
962+
// Skipping `super_constant` as the visitor is otherwise only looking for locals.
963+
}
956964
}
957965

958966
fn promote_candidates<'tcx>(
@@ -997,11 +1005,6 @@ fn promote_candidates<'tcx>(
9971005
None,
9981006
body.tainted_by_errors,
9991007
);
1000-
// We keep `required_consts` of the new MIR body empty. All consts mentioned here have
1001-
// already been added to the parent MIR's `required_consts` (that is computed before
1002-
// promotion), and no matter where this promoted const ends up, our parent MIR must be
1003-
// somewhere in the reachable dependency chain so we can rely on its required consts being
1004-
// evaluated.
10051008
promoted.phase = MirPhase::Analysis(AnalysisPhase::Initial);
10061009

10071010
let promoter = Promoter {
@@ -1014,6 +1017,7 @@ fn promote_candidates<'tcx>(
10141017
add_to_required: false,
10151018
};
10161019

1020+
// `required_consts` of the promoted itself gets filled while building the MIR body.
10171021
let mut promoted = promoter.promote_candidate(candidate, promotions.len());
10181022
promoted.source.promoted = Some(promotions.next_index());
10191023
promotions.push(promoted);

compiler/rustc_mir_transform/src/required_consts.rs

+2-17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use rustc_middle::mir::visit::Visitor;
2-
use rustc_middle::mir::{Const, ConstOperand, Location};
3-
use rustc_middle::ty;
2+
use rustc_middle::mir::{ConstOperand, Location};
43

54
pub struct RequiredConstsVisitor<'a, 'tcx> {
65
required_consts: &'a mut Vec<ConstOperand<'tcx>>,
@@ -14,21 +13,7 @@ impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> {
1413

1514
impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> {
1615
fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _: Location) {
17-
// Only unevaluated consts have to be added to `required_consts` as only those can possibly
18-
// still have latent const-eval errors.
19-
let is_required = match constant.const_ {
20-
Const::Ty(c) => match c.kind() {
21-
ty::ConstKind::Value(_) => false, // already a value, cannot error
22-
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) => true, // these are errors or could be replaced by errors
23-
_ => bug!(
24-
"only ConstKind::Param/Value/Error should be encountered here, got {:#?}",
25-
c
26-
),
27-
},
28-
Const::Unevaluated(..) => true,
29-
Const::Val(..) => false, // already a value, cannot error
30-
};
31-
if is_required {
16+
if constant.const_.is_required_const() {
3217
self.required_consts.push(*constant);
3318
}
3419
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
error[E0080]: evaluation of `Fail::<i32>::C` failed
2+
--> $DIR/collect-in-promoted-const.rs:9:19
3+
|
4+
LL | const C: () = panic!();
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-promoted-const.rs:9:19
6+
|
7+
= note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
8+
9+
note: erroneous constant encountered
10+
--> $DIR/collect-in-promoted-const.rs:20:21
11+
|
12+
LL | let _val = &Fail::<T>::C;
13+
| ^^^^^^^^^^^^
14+
15+
note: erroneous constant encountered
16+
--> $DIR/collect-in-promoted-const.rs:20:20
17+
|
18+
LL | let _val = &Fail::<T>::C;
19+
| ^^^^^^^^^^^^^
20+
21+
note: erroneous constant encountered
22+
--> $DIR/collect-in-promoted-const.rs:20:21
23+
|
24+
LL | let _val = &Fail::<T>::C;
25+
| ^^^^^^^^^^^^
26+
|
27+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
28+
29+
note: the above error was encountered while instantiating `fn f::<i32>`
30+
--> $DIR/collect-in-promoted-const.rs:25:5
31+
|
32+
LL | f::<i32>();
33+
| ^^^^^^^^^^
34+
35+
error: aborting due to 1 previous error
36+
37+
For more information about this error, try `rustc --explain E0080`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
error[E0080]: evaluation of `Fail::<T>::C` failed
2+
--> $DIR/collect-in-promoted-const.rs:9:19
3+
|
4+
LL | const C: () = panic!();
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-promoted-const.rs:9:19
6+
|
7+
= note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
8+
9+
note: erroneous constant encountered
10+
--> $DIR/collect-in-promoted-const.rs:20:21
11+
|
12+
LL | let _val = &Fail::<T>::C;
13+
| ^^^^^^^^^^^^
14+
15+
error[E0080]: evaluation of `Fail::<i32>::C` failed
16+
--> $DIR/collect-in-promoted-const.rs:9:19
17+
|
18+
LL | const C: () = panic!();
19+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-promoted-const.rs:9:19
20+
|
21+
= note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
22+
23+
note: erroneous constant encountered
24+
--> $DIR/collect-in-promoted-const.rs:20:21
25+
|
26+
LL | let _val = &Fail::<T>::C;
27+
| ^^^^^^^^^^^^
28+
|
29+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
30+
31+
note: erroneous constant encountered
32+
--> $DIR/collect-in-promoted-const.rs:20:20
33+
|
34+
LL | let _val = &Fail::<T>::C;
35+
| ^^^^^^^^^^^^^
36+
37+
note: erroneous constant encountered
38+
--> $DIR/collect-in-promoted-const.rs:20:21
39+
|
40+
LL | let _val = &Fail::<T>::C;
41+
| ^^^^^^^^^^^^
42+
|
43+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
44+
45+
note: the above error was encountered while instantiating `fn f::<i32>`
46+
--> $DIR/collect-in-promoted-const.rs:25:5
47+
|
48+
LL | f::<i32>();
49+
| ^^^^^^^^^^
50+
51+
error: aborting due to 2 previous errors
52+
53+
For more information about this error, try `rustc --explain E0080`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//@revisions: noopt opt
2+
//@ build-fail
3+
//@[noopt] compile-flags: -Copt-level=0
4+
//@[opt] compile-flags: -O
5+
//! Make sure we error on erroneous consts even if they get promoted.
6+
7+
struct Fail<T>(T);
8+
impl<T> Fail<T> {
9+
const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
10+
//[opt]~^ ERROR evaluation of `Fail::<T>::C` failed
11+
// (Not sure why optimizations lead to this being emitted twice, but as long as compilation
12+
// fails either way it's fine.)
13+
}
14+
15+
#[inline(never)]
16+
fn f<T>() {
17+
if false {
18+
// If promotion moved `C` from our required_consts to its own, without adding itself to
19+
// our required_consts, then we'd miss the const-eval failure here.
20+
let _val = &Fail::<T>::C;
21+
}
22+
}
23+
24+
fn main() {
25+
f::<i32>();
26+
}

tests/ui/consts/required-consts/interpret-in-promoted.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@revisions: noopt opt
22
//@[opt] compile-flags: -O
3-
//! Make sure we error on erroneous consts even if they are unused.
3+
//! Make sure we evaluate const fn calls even if they get promoted and their result ignored.
44
55
const unsafe fn ub() {
66
std::hint::unreachable_unchecked();

tests/ui/rfcs/rfc-1623-static/rfc1623-2.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ static SOME_STRUCT: &SomeStruct = &SomeStruct {
2626
foo: &Foo { bools: &[false, true] },
2727
bar: &Bar { bools: &[true, true] },
2828
f: &id,
29-
//~^ ERROR mismatched types
30-
//~| ERROR mismatched types
29+
//~^ ERROR implementation of `FnOnce` is not general enough
30+
//~| ERROR implementation of `FnOnce` is not general enough
3131
//~| ERROR implementation of `Fn` is not general enough
3232
//~| ERROR implementation of `Fn` is not general enough
3333
};

0 commit comments

Comments
 (0)