Skip to content

Commit 0be80f2

Browse files
committed
[const-prop] Fix ICE calculating enum discriminant
Fixes #66787
1 parent 4007d4e commit 0be80f2

File tree

2 files changed

+52
-10
lines changed

2 files changed

+52
-10
lines changed

Diff for: src/librustc_mir/interpret/place.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -1038,23 +1038,26 @@ where
10381038
variant_index: VariantIdx,
10391039
dest: PlaceTy<'tcx, M::PointerTag>,
10401040
) -> InterpResult<'tcx> {
1041-
let variant_scalar = Scalar::from_u32(variant_index.as_u32()).into();
1041+
1042+
// Layout computation excludes uninhabited variants from consideration
1043+
// therefore there's no way to represent those variants in the given layout.
1044+
if dest.layout.for_variant(self, variant_index).abi.is_uninhabited() {
1045+
throw_ub!(Unreachable);
1046+
}
10421047

10431048
match dest.layout.variants {
10441049
layout::Variants::Single { index } => {
1045-
if index != variant_index {
1046-
throw_ub!(InvalidDiscriminant(variant_scalar));
1047-
}
1050+
assert_eq!(index, variant_index);
10481051
}
10491052
layout::Variants::Multiple {
10501053
discr_kind: layout::DiscriminantKind::Tag,
10511054
discr: ref discr_layout,
10521055
discr_index,
10531056
..
10541057
} => {
1055-
if !dest.layout.ty.variant_range(*self.tcx).unwrap().contains(&variant_index) {
1056-
throw_ub!(InvalidDiscriminant(variant_scalar));
1057-
}
1058+
// No need to validate that the discriminant here because the
1059+
// `TyLayout::for_variant()` call earlier already checks the variant is valid.
1060+
10581061
let discr_val =
10591062
dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val;
10601063

@@ -1077,9 +1080,9 @@ where
10771080
discr_index,
10781081
..
10791082
} => {
1080-
if !variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len() {
1081-
throw_ub!(InvalidDiscriminant(variant_scalar));
1082-
}
1083+
// No need to validate that the discriminant here because the
1084+
// `TyLayout::for_variant()` call earlier already checks the variant is valid.
1085+
10831086
if variant_index != dataful_variant {
10841087
let variants_start = niche_variants.start().as_u32();
10851088
let variant_index_relative = variant_index.as_u32()

Diff for: src/test/ui/consts/issue-66787.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// build-pass
2+
// compile-flags: --crate-type lib
3+
4+
// Regression test for ICE which occurred when const propagating an enum with three variants
5+
// one of which is uninhabited.
6+
7+
pub enum ApiError {}
8+
#[allow(dead_code)]
9+
pub struct TokioError {
10+
b: bool,
11+
}
12+
pub enum Error {
13+
Api {
14+
source: ApiError,
15+
},
16+
Ethereum,
17+
Tokio {
18+
source: TokioError,
19+
},
20+
}
21+
struct Api;
22+
impl IntoError<Error> for Api
23+
{
24+
type Source = ApiError;
25+
fn into_error(self, error: Self::Source) -> Error {
26+
Error::Api {
27+
source: (|v| v)(error),
28+
}
29+
}
30+
}
31+
32+
pub trait IntoError<E>
33+
{
34+
/// The underlying error
35+
type Source;
36+
37+
/// Combine the information to produce the error
38+
fn into_error(self, source: Self::Source) -> E;
39+
}

0 commit comments

Comments
 (0)