When casting enum to integer sign extend the discriminant if necessary

This commit is contained in:
bjorn3 2020-05-01 17:06:59 +02:00
parent cc0268fa1a
commit bf2ba15972

View File

@ -515,12 +515,43 @@ fn is_fat_ptr<'tcx>(
_ => unreachable!("cast adt {} -> {}", from_ty, to_ty),
}
let discr = crate::discriminant::codegen_get_discriminant(
fx,
operand,
fx.layout_of(to_ty),
);
lval.write_cvalue(fx, discr);
use rustc_target::abi::{TagEncoding, Int, Variants};
match &operand.layout().variants {
Variants::Single { index } => {
let discr = operand.layout().ty.discriminant_for_variant(fx.tcx, *index).unwrap();
let discr = if discr.ty.is_signed() {
rustc_middle::mir::interpret::sign_extend(discr.val, fx.layout_of(discr.ty).size)
} else {
discr.val
};
let discr = CValue::const_val(fx, fx.layout_of(to_ty), discr);
lval.write_cvalue(fx, discr);
}
Variants::Multiple {
tag,
tag_field,
tag_encoding: TagEncoding::Direct,
variants: _,
} => {
let cast_to = fx.clif_type(dest_layout.ty).unwrap();
// Read the tag/niche-encoded discriminant from memory.
let encoded_discr = operand.value_field(fx, mir::Field::new(*tag_field));
let encoded_discr = encoded_discr.load_scalar(fx);
// Decode the discriminant (specifically if it's niche-encoded).
let signed = match tag.value {
Int(_, signed) => signed,
_ => false,
};
let val = clif_intcast(fx, encoded_discr, cast_to, signed);
let val = CValue::by_val(val, dest_layout);
lval.write_cvalue(fx, val);
}
Variants::Multiple { ..} => unreachable!(),
}
} else {
let to_clif_ty = fx.clif_type(to_ty).unwrap();
let from = operand.load_scalar(fx);