Skip to content

Commit 658ebfc

Browse files
committed
rustc: give Layout::CEnum a discriminant field like Layout::General.
1 parent d318b9c commit 658ebfc

File tree

2 files changed

+55
-55
lines changed

2 files changed

+55
-55
lines changed

src/librustc/ty/layout.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,8 +1203,7 @@ impl<'a, 'tcx> Layout {
12031203
let success = |layout| {
12041204
let layout = tcx.intern_layout(layout);
12051205
let fields = match *layout {
1206-
Scalar(_) |
1207-
CEnum { .. } => {
1206+
Scalar(_) => {
12081207
FieldPlacement::union(0)
12091208
}
12101209

@@ -1241,6 +1240,7 @@ impl<'a, 'tcx> Layout {
12411240
FieldPlacement::union(def.struct_variant().fields.len())
12421241
}
12431242

1243+
CEnum { .. } |
12441244
General { .. } => FieldPlacement::union(1),
12451245

12461246
NullablePointer { ref discr_offset, .. } => {
@@ -2356,6 +2356,7 @@ impl<'a, 'tcx> FullLayout<'tcx> {
23562356
match self.variant_index {
23572357
None => match *self.layout {
23582358
// Discriminant field for enums (where applicable).
2359+
CEnum { discr, .. } |
23592360
General { discr, .. } |
23602361
NullablePointer { discr, .. } => {
23612362
return [discr.to_ty(tcx)][i];

src/librustc_trans/mir/lvalue.rs

Lines changed: 52 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,6 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
235235

236236
// Discriminant field of enums.
237237
match *l {
238-
layout::General { .. } |
239238
layout::NullablePointer { .. } if l.variant_index.is_none() => {
240239
let ty = ccx.llvm_type_of(field.ty);
241240
let size = field.size(ccx).bytes();
@@ -350,60 +349,66 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
350349
}
351350
}
352351

353-
/// Helper for cases where the discriminant is simply loaded.
354-
fn load_discr(self, bcx: &Builder, discr: layout::Primitive, min: u64, max: u64) -> ValueRef {
355-
if let layout::Int(ity, _) = discr {
356-
let bits = ity.size().bits();
357-
assert!(bits <= 64);
358-
let bits = bits as usize;
359-
let mask = !0u64 >> (64 - bits);
360-
// For a (max) discr of -1, max will be `-1 as usize`, which overflows.
361-
// However, that is fine here (it would still represent the full range),
362-
if max.wrapping_add(1) & mask == min & mask {
363-
// i.e., if the range is everything. The lo==hi case would be
364-
// rejected by the LLVM verifier (it would mean either an
365-
// empty set, which is impossible, or the entire range of the
366-
// type, which is pointless).
367-
} else {
368-
// llvm::ConstantRange can deal with ranges that wrap around,
369-
// so an overflow on (max + 1) is fine.
370-
return bcx.load_range_assert(self.llval, min, max.wrapping_add(1),
371-
/* signed: */ llvm::True,
372-
self.alignment.non_abi());
373-
}
374-
}
375-
bcx.load(self.llval, self.alignment.non_abi())
376-
}
377-
378352
/// Obtain the actual discriminant of a value.
379353
pub fn trans_get_discr(self, bcx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef {
380354
let l = bcx.ccx.layout_of(self.ty.to_ty(bcx.tcx()));
381355

382356
let cast_to = bcx.ccx.immediate_llvm_type_of(cast_to);
383-
let (val, discr) = match *l {
357+
match *l {
384358
layout::Univariant { .. } |
385359
layout::UntaggedUnion { .. } => return C_uint(cast_to, 0),
386-
layout::CEnum { discr, min, max, .. } => {
387-
(self.load_discr(bcx, discr, min, max), discr)
360+
_ => {}
361+
}
362+
363+
let discr = self.project_field(bcx, 0);
364+
let discr_layout = bcx.ccx.layout_of(discr.ty.to_ty(bcx.tcx()));
365+
let discr_scalar = match discr_layout.abi {
366+
layout::Abi::Scalar(discr) => discr,
367+
_ => bug!("discriminant not scalar: {:#?}", discr_layout)
368+
};
369+
let (min, max) = match *l {
370+
layout::CEnum { min, max, .. } => (min, max),
371+
layout::General { ref variants, .. } => (0, variants.len() as u64 - 1),
372+
_ => (0, u64::max_value()),
373+
};
374+
let max_next = max.wrapping_add(1);
375+
let bits = discr_scalar.size(bcx.ccx).bits();
376+
assert!(bits <= 64);
377+
let mask = !0u64 >> (64 - bits);
378+
let lldiscr = match discr_scalar {
379+
// For a (max) discr of -1, max will be `-1 as usize`, which overflows.
380+
// However, that is fine here (it would still represent the full range),
381+
layout::Int(..) if max_next & mask != min & mask => {
382+
// llvm::ConstantRange can deal with ranges that wrap around,
383+
// so an overflow on (max + 1) is fine.
384+
bcx.load_range_assert(discr.llval, min, max_next,
385+
/* signed: */ llvm::True,
386+
discr.alignment.non_abi())
388387
}
389-
layout::General { discr, ref variants, .. } => {
390-
let ptr = self.project_field(bcx, 0);
391-
(ptr.load_discr(bcx, discr, 0, variants.len() as u64 - 1), discr)
388+
_ => {
389+
// i.e., if the range is everything. The lo==hi case would be
390+
// rejected by the LLVM verifier (it would mean either an
391+
// empty set, which is impossible, or the entire range of the
392+
// type, which is pointless).
393+
bcx.load(discr.llval, discr.alignment.non_abi())
394+
}
395+
};
396+
match *l {
397+
layout::CEnum { .. } |
398+
layout::General { .. } => {
399+
let signed = match discr_scalar {
400+
layout::Int(_, signed) => signed,
401+
_ => false
402+
};
403+
bcx.intcast(lldiscr, cast_to, signed)
392404
}
393405
layout::NullablePointer { nndiscr, .. } => {
394-
let ptr = self.project_field(bcx, 0);
395-
let lldiscr = bcx.load(ptr.llval, ptr.alignment.non_abi());
396406
let cmp = if nndiscr == 0 { llvm::IntEQ } else { llvm::IntNE };
397-
(bcx.icmp(cmp, lldiscr, C_null(bcx.ccx.llvm_type_of(ptr.ty.to_ty(bcx.tcx())))),
398-
layout::Int(layout::I1, false))
399-
},
407+
let zero = C_null(bcx.ccx.llvm_type_of(discr_layout.ty));
408+
bcx.intcast(bcx.icmp(cmp, lldiscr, zero), cast_to, false)
409+
}
400410
_ => bug!("{} is not an enum", l.ty)
401-
};
402-
let signed = match discr {
403-
layout::Int(_, signed) => signed,
404-
_ => false
405-
};
406-
bcx.intcast(val, cast_to, signed)
411+
}
407412
}
408413

409414
/// Set the discriminant for a new value of the given case of the given
@@ -414,20 +419,12 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
414419
.discriminant_for_variant(bcx.tcx(), variant_index)
415420
.to_u128_unchecked() as u64;
416421
match *l {
417-
layout::CEnum { .. } => {
418-
bcx.store(C_int(bcx.ccx.llvm_type_of(self.ty.to_ty(bcx.tcx())), to as i64),
419-
self.llval, self.alignment.non_abi());
420-
}
422+
layout::CEnum { .. } |
421423
layout::General { .. } => {
422424
let ptr = self.project_field(bcx, 0);
423425
bcx.store(C_int(bcx.ccx.llvm_type_of(ptr.ty.to_ty(bcx.tcx())), to as i64),
424426
ptr.llval, ptr.alignment.non_abi());
425427
}
426-
layout::Univariant { .. }
427-
| layout::UntaggedUnion { .. }
428-
| layout::Vector { .. } => {
429-
assert_eq!(to, 0);
430-
}
431428
layout::NullablePointer { nndiscr, .. } => {
432429
if to != nndiscr {
433430
let use_memset = match l.abi {
@@ -451,7 +448,9 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
451448
}
452449
}
453450
}
454-
_ => bug!("Cannot handle {} represented as {:#?}", l.ty, l)
451+
_ => {
452+
assert_eq!(to, 0);
453+
}
455454
}
456455
}
457456

0 commit comments

Comments
 (0)