Skip to content

Commit 70b9165

Browse files
committed
interpret: project_downcast: do not ICE for uninhabited variants
1 parent 69db514 commit 70b9165

File tree

4 files changed

+31
-21
lines changed

4 files changed

+31
-21
lines changed

compiler/rustc_const_eval/src/interpret/projection.rs

+2-19
Original file line numberDiff line numberDiff line change
@@ -201,25 +201,8 @@ where
201201
// see https://github.com/rust-lang/rust/issues/93688#issuecomment-1032929496.)
202202
// So we just "offset" by 0.
203203
let layout = base.layout().for_variant(self, variant);
204-
// In the future we might want to allow this to permit code like this:
205-
// (this is a Rust/MIR pseudocode mix)
206-
// ```
207-
// enum Option2 {
208-
// Some(i32, !),
209-
// None,
210-
// }
211-
//
212-
// fn panic() -> ! { panic!() }
213-
//
214-
// let x: Option2;
215-
// x.Some.0 = 42;
216-
// x.Some.1 = panic();
217-
// SetDiscriminant(x, Some);
218-
// ```
219-
// However, for now we don't generate such MIR, and this check here *has* found real
220-
// bugs (see https://github.com/rust-lang/rust/issues/115145), so we will keep rejecting
221-
// it.
222-
assert!(!layout.abi.is_uninhabited());
204+
// This variant may in fact be uninhabited.
205+
// See <https://github.com/rust-lang/rust/issues/120337>.
223206

224207
// This cannot be `transmute` as variants *can* have a smaller size than the entire enum.
225208
base.offset(Size::ZERO, layout, self)

compiler/rustc_middle/src/mir/syntax.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -956,8 +956,7 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
956956
/// element:
957957
///
958958
/// - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the
959-
/// given one, and makes no other changes. A `Downcast` projection on a place with its variant
960-
/// index already set is not well-formed.
959+
/// given one, and makes no other changes.
961960
/// - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a
962961
/// place referring to one of the fields of the type. The resulting address is the parent
963962
/// address, plus the offset of the field. The type becomes the type of the field. If the parent
@@ -1074,6 +1073,8 @@ pub enum ProjectionElem<V, T> {
10741073
/// "Downcast" to a variant of an enum or a coroutine.
10751074
///
10761075
/// The included Symbol is the name of the variant, used for printing MIR.
1076+
///
1077+
/// This operation itself is never UB, all it does is change the type of the place.
10771078
Downcast(Option<Symbol>, VariantIdx),
10781079

10791080
/// Like an explicit cast from an opaque type to a concrete type, but without
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Validation stops the test before the ICE we used to hit
2+
//@compile-flags: -Zmiri-disable-validation
3+
4+
#![feature(never_type)]
5+
#[derive(Copy, Clone)]
6+
pub enum E {
7+
A(!),
8+
}
9+
pub union U {
10+
u: (),
11+
e: E,
12+
}
13+
14+
fn main() {
15+
let E::A(ref _a) = unsafe { &(&U { u: () }).e };
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// check-pass
2+
#![feature(never_type)]
3+
#[derive(Copy, Clone)]
4+
pub enum E { A(!), }
5+
pub union U { u: (), e: E, }
6+
pub const C: () = {
7+
let E::A(ref a) = unsafe { &(&U { u: () }).e};
8+
};
9+
10+
fn main() {}

0 commit comments

Comments
 (0)