Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions compiler/rustc_const_eval/src/interpret/discriminant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,20 +121,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// discriminants are int-like.
let discr_val = self.int_to_int_or_float(&tag_val, discr_layout).unwrap();
let discr_bits = discr_val.to_scalar().to_bits(discr_layout.size)?;
// Convert discriminant to variant index. Since we validated the tag against the
// layout range above, this cannot fail.
// Convert discriminant to variant index. The tag may pass the layout range
// check above but still not match any actual variant discriminant (e.g.,
// non-contiguous discriminants with a wrapping valid_range).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I got that wrong in b840338.

let index = match *ty.kind() {
ty::Adt(adt, _) => {
adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits).unwrap()
adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits)
}
ty::Coroutine(def_id, args) => {
let args = args.as_coroutine();
args.discriminants(def_id, *self.tcx)
.find(|(_, var)| var.val == discr_bits)
.unwrap()
args.discriminants(def_id, *self.tcx).find(|(_, var)| var.val == discr_bits)
}
_ => span_bug!(self.cur_span(), "tagged layout for non-adt non-coroutine"),
};
}
.ok_or_else(|| err_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))))?;
// Return the cast value, and the index.
index.0
}
Expand Down
13 changes: 13 additions & 0 deletions tests/ui/consts/const-eval/ub-enum.rs
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this have to do with #153758 ? #153758 is about a program that doesn't even typecheck, which then erroneously reaches the interpreter. But here you have an example that apparently does typecheck?

Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,17 @@ const TEST_ICE_89765: () = {
};
};

// # Regression test for https://github.com/rust-lang/rust/issues/153758
// Discriminants at i64::MIN and i64::MAX produce a wrapping valid_range that covers
// all values. A value like 0 passes the range check but doesn't match any variant.
#[repr(i64)]
#[derive(Copy, Clone)]
enum WideRangeDiscriminants {
A = i64::MIN,
B = i64::MAX,
}

const BAD_WIDE_RANGE_ENUM: WideRangeDiscriminants = unsafe { mem::transmute(0_i64) };
//~^ ERROR expected a valid enum tag

fn main() {}
13 changes: 12 additions & 1 deletion tests/ui/consts/const-eval/ub-enum.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,17 @@ LL | std::mem::discriminant(&*(&() as *const () as *const Never));
note: inside `discriminant::<Never>`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL

error: aborting due to 14 previous errors
error[E0080]: constructing invalid value of type WideRangeDiscriminants: at .<enum-tag>, encountered 0x0, but expected a valid enum tag
--> $DIR/ub-enum.rs:121:1
|
LL | const BAD_WIDE_RANGE_ENUM: WideRangeDiscriminants = unsafe { mem::transmute(0_i64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
= note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
HEX_DUMP
}

error: aborting due to 15 previous errors

For more information about this error, try `rustc --explain E0080`.
Loading