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

Fix ICE caused by truncating a negative ZST enum discriminant #70126

Merged
merged 2 commits into from
Mar 22, 2020
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
7 changes: 6 additions & 1 deletion src/librustc_codegen_ssa/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if let Some(discr) =
operand.layout.ty.discriminant_for_variant(bx.tcx(), index)
{
let discr_val = bx.cx().const_uint_big(ll_t_out, discr.val);
let discr_layout = bx.cx().layout_of(discr.ty);
let discr_t = bx.cx().immediate_backend_type(discr_layout);
let discr_val = bx.cx().const_uint_big(discr_t, discr.val);
let discr_val =
bx.intcast(discr_val, ll_t_out, discr.ty.is_signed());

return (
bx,
OperandRef {
Expand Down
10 changes: 7 additions & 3 deletions src/librustc_mir/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use rustc::ty::layout::{self, Size, TyLayout};
use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable};
use rustc_ast::ast::FloatTy;
use rustc_span::symbol::sym;
use rustc_target::abi::LayoutOf;

use rustc::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
use rustc::mir::CastKind;
Expand Down Expand Up @@ -134,7 +135,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
layout::Variants::Single { index } => {
if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) {
assert!(src.layout.is_zst());
return Ok(Scalar::from_uint(discr.val, dest_layout.size).into());
let discr_layout = self.layout_of(discr.ty)?;
return Ok(self
.cast_from_int_like(discr.val, discr_layout, dest_layout)?
.into());
}
}
layout::Variants::Multiple { .. } => {}
Expand Down Expand Up @@ -171,10 +175,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// (b) cast from an integer-like (including bool, char, enums).
// In both cases we want the bits.
let bits = self.force_bits(src.to_scalar()?, src.layout.size)?;
Ok(self.cast_from_int(bits, src.layout, dest_layout)?.into())
Ok(self.cast_from_int_like(bits, src.layout, dest_layout)?.into())
}

fn cast_from_int(
fn cast_from_int_like(
&self,
v: u128, // raw bits
src_layout: TyLayout<'tcx>,
Expand Down
47 changes: 47 additions & 0 deletions src/test/ui/consts/cast-discriminant-zst-enum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// run-pass
// Test a ZST enum whose dicriminant is ~0i128. This caused an ICE when casting to a i32.

#[derive(Copy, Clone)]
enum Nums {
NegOne = -1,
}

const NEG_ONE_I8: i8 = Nums::NegOne as i8;
const NEG_ONE_I16: i16 = Nums::NegOne as i16;
const NEG_ONE_I32: i32 = Nums::NegOne as i32;
const NEG_ONE_I64: i64 = Nums::NegOne as i64;
const NEG_ONE_I128: i128 = Nums::NegOne as i128;

#[inline(never)]
fn identity<T>(t: T) -> T { t }

fn test_as_arg(n: Nums) {
assert_eq!(-1i8, n as i8);
assert_eq!(-1i16, n as i16);
assert_eq!(-1i32, n as i32);
assert_eq!(-1i64, n as i64);
assert_eq!(-1i128, n as i128);
}

fn main() {
let kind = Nums::NegOne;
assert_eq!(-1i8, kind as i8);
assert_eq!(-1i16, kind as i16);
assert_eq!(-1i32, kind as i32);
assert_eq!(-1i64, kind as i64);
assert_eq!(-1i128, kind as i128);

assert_eq!(-1i8, identity(kind) as i8);
assert_eq!(-1i16, identity(kind) as i16);
assert_eq!(-1i32, identity(kind) as i32);
assert_eq!(-1i64, identity(kind) as i64);
assert_eq!(-1i128, identity(kind) as i128);

test_as_arg(Nums::NegOne);

assert_eq!(-1i8, NEG_ONE_I8);
assert_eq!(-1i16, NEG_ONE_I16);
assert_eq!(-1i32, NEG_ONE_I32);
assert_eq!(-1i64, NEG_ONE_I64);
assert_eq!(-1i128, NEG_ONE_I128);
}