rustc: give Layout::CEnum a discriminant field like Layout::General.
This commit is contained in:
parent
d318b9c27b
commit
658ebfc788
2 changed files with 55 additions and 55 deletions
|
@ -1203,8 +1203,7 @@ impl<'a, 'tcx> Layout {
|
|||
let success = |layout| {
|
||||
let layout = tcx.intern_layout(layout);
|
||||
let fields = match *layout {
|
||||
Scalar(_) |
|
||||
CEnum { .. } => {
|
||||
Scalar(_) => {
|
||||
FieldPlacement::union(0)
|
||||
}
|
||||
|
||||
|
@ -1241,6 +1240,7 @@ impl<'a, 'tcx> Layout {
|
|||
FieldPlacement::union(def.struct_variant().fields.len())
|
||||
}
|
||||
|
||||
CEnum { .. } |
|
||||
General { .. } => FieldPlacement::union(1),
|
||||
|
||||
NullablePointer { ref discr_offset, .. } => {
|
||||
|
@ -2356,6 +2356,7 @@ impl<'a, 'tcx> FullLayout<'tcx> {
|
|||
match self.variant_index {
|
||||
None => match *self.layout {
|
||||
// Discriminant field for enums (where applicable).
|
||||
CEnum { discr, .. } |
|
||||
General { discr, .. } |
|
||||
NullablePointer { discr, .. } => {
|
||||
return [discr.to_ty(tcx)][i];
|
||||
|
|
|
@ -235,7 +235,6 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
|||
|
||||
// Discriminant field of enums.
|
||||
match *l {
|
||||
layout::General { .. } |
|
||||
layout::NullablePointer { .. } if l.variant_index.is_none() => {
|
||||
let ty = ccx.llvm_type_of(field.ty);
|
||||
let size = field.size(ccx).bytes();
|
||||
|
@ -350,60 +349,66 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Helper for cases where the discriminant is simply loaded.
|
||||
fn load_discr(self, bcx: &Builder, discr: layout::Primitive, min: u64, max: u64) -> ValueRef {
|
||||
if let layout::Int(ity, _) = discr {
|
||||
let bits = ity.size().bits();
|
||||
assert!(bits <= 64);
|
||||
let bits = bits as usize;
|
||||
let mask = !0u64 >> (64 - bits);
|
||||
// For a (max) discr of -1, max will be `-1 as usize`, which overflows.
|
||||
// However, that is fine here (it would still represent the full range),
|
||||
if max.wrapping_add(1) & mask == min & mask {
|
||||
// i.e., if the range is everything. The lo==hi case would be
|
||||
// rejected by the LLVM verifier (it would mean either an
|
||||
// empty set, which is impossible, or the entire range of the
|
||||
// type, which is pointless).
|
||||
} else {
|
||||
// llvm::ConstantRange can deal with ranges that wrap around,
|
||||
// so an overflow on (max + 1) is fine.
|
||||
return bcx.load_range_assert(self.llval, min, max.wrapping_add(1),
|
||||
/* signed: */ llvm::True,
|
||||
self.alignment.non_abi());
|
||||
}
|
||||
}
|
||||
bcx.load(self.llval, self.alignment.non_abi())
|
||||
}
|
||||
|
||||
/// Obtain the actual discriminant of a value.
|
||||
pub fn trans_get_discr(self, bcx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef {
|
||||
let l = bcx.ccx.layout_of(self.ty.to_ty(bcx.tcx()));
|
||||
|
||||
let cast_to = bcx.ccx.immediate_llvm_type_of(cast_to);
|
||||
let (val, discr) = match *l {
|
||||
match *l {
|
||||
layout::Univariant { .. } |
|
||||
layout::UntaggedUnion { .. } => return C_uint(cast_to, 0),
|
||||
layout::CEnum { discr, min, max, .. } => {
|
||||
(self.load_discr(bcx, discr, min, max), discr)
|
||||
_ => {}
|
||||
}
|
||||
layout::General { discr, ref variants, .. } => {
|
||||
let ptr = self.project_field(bcx, 0);
|
||||
(ptr.load_discr(bcx, discr, 0, variants.len() as u64 - 1), discr)
|
||||
}
|
||||
layout::NullablePointer { nndiscr, .. } => {
|
||||
let ptr = self.project_field(bcx, 0);
|
||||
let lldiscr = bcx.load(ptr.llval, ptr.alignment.non_abi());
|
||||
let cmp = if nndiscr == 0 { llvm::IntEQ } else { llvm::IntNE };
|
||||
(bcx.icmp(cmp, lldiscr, C_null(bcx.ccx.llvm_type_of(ptr.ty.to_ty(bcx.tcx())))),
|
||||
layout::Int(layout::I1, false))
|
||||
},
|
||||
_ => bug!("{} is not an enum", l.ty)
|
||||
|
||||
let discr = self.project_field(bcx, 0);
|
||||
let discr_layout = bcx.ccx.layout_of(discr.ty.to_ty(bcx.tcx()));
|
||||
let discr_scalar = match discr_layout.abi {
|
||||
layout::Abi::Scalar(discr) => discr,
|
||||
_ => bug!("discriminant not scalar: {:#?}", discr_layout)
|
||||
};
|
||||
let signed = match discr {
|
||||
let (min, max) = match *l {
|
||||
layout::CEnum { min, max, .. } => (min, max),
|
||||
layout::General { ref variants, .. } => (0, variants.len() as u64 - 1),
|
||||
_ => (0, u64::max_value()),
|
||||
};
|
||||
let max_next = max.wrapping_add(1);
|
||||
let bits = discr_scalar.size(bcx.ccx).bits();
|
||||
assert!(bits <= 64);
|
||||
let mask = !0u64 >> (64 - bits);
|
||||
let lldiscr = match discr_scalar {
|
||||
// For a (max) discr of -1, max will be `-1 as usize`, which overflows.
|
||||
// However, that is fine here (it would still represent the full range),
|
||||
layout::Int(..) if max_next & mask != min & mask => {
|
||||
// llvm::ConstantRange can deal with ranges that wrap around,
|
||||
// so an overflow on (max + 1) is fine.
|
||||
bcx.load_range_assert(discr.llval, min, max_next,
|
||||
/* signed: */ llvm::True,
|
||||
discr.alignment.non_abi())
|
||||
}
|
||||
_ => {
|
||||
// i.e., if the range is everything. The lo==hi case would be
|
||||
// rejected by the LLVM verifier (it would mean either an
|
||||
// empty set, which is impossible, or the entire range of the
|
||||
// type, which is pointless).
|
||||
bcx.load(discr.llval, discr.alignment.non_abi())
|
||||
}
|
||||
};
|
||||
match *l {
|
||||
layout::CEnum { .. } |
|
||||
layout::General { .. } => {
|
||||
let signed = match discr_scalar {
|
||||
layout::Int(_, signed) => signed,
|
||||
_ => false
|
||||
};
|
||||
bcx.intcast(val, cast_to, signed)
|
||||
bcx.intcast(lldiscr, cast_to, signed)
|
||||
}
|
||||
layout::NullablePointer { nndiscr, .. } => {
|
||||
let cmp = if nndiscr == 0 { llvm::IntEQ } else { llvm::IntNE };
|
||||
let zero = C_null(bcx.ccx.llvm_type_of(discr_layout.ty));
|
||||
bcx.intcast(bcx.icmp(cmp, lldiscr, zero), cast_to, false)
|
||||
}
|
||||
_ => bug!("{} is not an enum", l.ty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the discriminant for a new value of the given case of the given
|
||||
|
@ -414,20 +419,12 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
|||
.discriminant_for_variant(bcx.tcx(), variant_index)
|
||||
.to_u128_unchecked() as u64;
|
||||
match *l {
|
||||
layout::CEnum { .. } => {
|
||||
bcx.store(C_int(bcx.ccx.llvm_type_of(self.ty.to_ty(bcx.tcx())), to as i64),
|
||||
self.llval, self.alignment.non_abi());
|
||||
}
|
||||
layout::CEnum { .. } |
|
||||
layout::General { .. } => {
|
||||
let ptr = self.project_field(bcx, 0);
|
||||
bcx.store(C_int(bcx.ccx.llvm_type_of(ptr.ty.to_ty(bcx.tcx())), to as i64),
|
||||
ptr.llval, ptr.alignment.non_abi());
|
||||
}
|
||||
layout::Univariant { .. }
|
||||
| layout::UntaggedUnion { .. }
|
||||
| layout::Vector { .. } => {
|
||||
assert_eq!(to, 0);
|
||||
}
|
||||
layout::NullablePointer { nndiscr, .. } => {
|
||||
if to != nndiscr {
|
||||
let use_memset = match l.abi {
|
||||
|
@ -451,7 +448,9 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => bug!("Cannot handle {} represented as {:#?}", l.ty, l)
|
||||
_ => {
|
||||
assert_eq!(to, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue