rustc: optimize out uninhabited types and variants.
This commit is contained in:
parent
f62e43da28
commit
ced5e04e8b
@ -755,6 +755,7 @@ impl FieldPlacement {
|
||||
/// in terms of categories of C types there are ABI rules for.
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum Abi {
|
||||
Uninhabited,
|
||||
Scalar(Scalar),
|
||||
Vector,
|
||||
Aggregate {
|
||||
@ -768,7 +769,7 @@ impl Abi {
|
||||
/// Returns true if the layout corresponds to an unsized type.
|
||||
pub fn is_unsized(&self) -> bool {
|
||||
match *self {
|
||||
Abi::Scalar(_) | Abi::Vector => false,
|
||||
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector => false,
|
||||
Abi::Aggregate { sized, .. } => !sized
|
||||
}
|
||||
}
|
||||
@ -776,7 +777,7 @@ impl Abi {
|
||||
/// Returns true if the fields of the layout are packed.
|
||||
pub fn is_packed(&self) -> bool {
|
||||
match *self {
|
||||
Abi::Scalar(_) | Abi::Vector => false,
|
||||
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector => false,
|
||||
Abi::Aggregate { packed, .. } => packed
|
||||
}
|
||||
}
|
||||
@ -807,6 +808,7 @@ pub enum Variants {
|
||||
/// `Some` is the identity function (with a non-null reference).
|
||||
NicheFilling {
|
||||
dataful_variant: usize,
|
||||
niche_variant: usize,
|
||||
niche: Scalar,
|
||||
niche_value: u128,
|
||||
variants: Vec<CachedLayout>,
|
||||
@ -855,6 +857,18 @@ impl CachedLayout {
|
||||
primitive_align: align
|
||||
}
|
||||
}
|
||||
|
||||
fn uninhabited(field_count: usize) -> Self {
|
||||
let align = Align::from_bytes(1, 1).unwrap();
|
||||
CachedLayout {
|
||||
variants: Variants::Single { index: 0 },
|
||||
fields: FieldPlacement::Union(field_count),
|
||||
abi: Abi::Uninhabited,
|
||||
align,
|
||||
primitive_align: align,
|
||||
size: Size::from_bytes(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
@ -915,13 +929,14 @@ impl<'a, 'tcx> CachedLayout {
|
||||
bug!("struct cannot be packed and aligned");
|
||||
}
|
||||
|
||||
let mut align = if packed {
|
||||
let base_align = if packed {
|
||||
dl.i8_align
|
||||
} else {
|
||||
dl.aggregate_align
|
||||
};
|
||||
|
||||
let mut primitive_align = align;
|
||||
let mut align = base_align;
|
||||
let mut primitive_align = base_align;
|
||||
let mut sized = true;
|
||||
|
||||
// Anything with repr(C) or repr(packed) doesn't optimize.
|
||||
@ -978,13 +993,17 @@ impl<'a, 'tcx> CachedLayout {
|
||||
}
|
||||
}
|
||||
|
||||
for i in inverse_memory_index.iter() {
|
||||
let field = fields[*i as usize];
|
||||
for &i in &inverse_memory_index {
|
||||
let field = fields[i as usize];
|
||||
if !sized {
|
||||
bug!("univariant: field #{} of `{}` comes after unsized field",
|
||||
offsets.len(), ty);
|
||||
}
|
||||
|
||||
if field.abi == Abi::Uninhabited {
|
||||
return Ok(CachedLayout::uninhabited(fields.len()));
|
||||
}
|
||||
|
||||
if field.is_unsized() {
|
||||
sized = false;
|
||||
}
|
||||
@ -997,7 +1016,7 @@ impl<'a, 'tcx> CachedLayout {
|
||||
}
|
||||
|
||||
debug!("univariant offset: {:?} field: {:#?}", offset, field);
|
||||
offsets[*i as usize] = offset;
|
||||
offsets[i as usize] = offset;
|
||||
|
||||
offset = offset.checked_add(field.size, dl)
|
||||
.ok_or(LayoutError::SizeOverflow(ty))?;
|
||||
@ -1124,7 +1143,7 @@ impl<'a, 'tcx> CachedLayout {
|
||||
|
||||
// The never type.
|
||||
ty::TyNever => {
|
||||
univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?
|
||||
tcx.intern_layout(CachedLayout::uninhabited(0))
|
||||
}
|
||||
|
||||
// Potentially-fat pointers.
|
||||
@ -1278,11 +1297,15 @@ impl<'a, 'tcx> CachedLayout {
|
||||
}).collect::<Result<Vec<_>, _>>()
|
||||
}).collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
if variants.is_empty() {
|
||||
// Uninhabitable; represent as unit
|
||||
// (Typechecking will reject discriminant-sizing attrs.)
|
||||
|
||||
return univariant(&[], &def.repr, StructKind::AlwaysSized);
|
||||
let (inh_first, inh_second, inh_third) = {
|
||||
let mut inh_variants = (0..variants.len()).filter(|&v| {
|
||||
variants[v].iter().all(|f| f.abi != Abi::Uninhabited)
|
||||
});
|
||||
(inh_variants.next(), inh_variants.next(), inh_variants.next())
|
||||
};
|
||||
if inh_first.is_none() {
|
||||
// Uninhabited because it has no variants, or only uninhabited ones.
|
||||
return Ok(tcx.intern_layout(CachedLayout::uninhabited(0)));
|
||||
}
|
||||
|
||||
if def.is_union() {
|
||||
@ -1329,49 +1352,58 @@ impl<'a, 'tcx> CachedLayout {
|
||||
}));
|
||||
}
|
||||
|
||||
if !def.is_enum() || (variants.len() == 1 &&
|
||||
!def.repr.inhibit_enum_layout_opt() &&
|
||||
!variants[0].is_empty()) {
|
||||
// Struct, or union, or univariant enum equivalent to a struct.
|
||||
let is_struct = !def.is_enum() ||
|
||||
// Only one variant is inhabited.
|
||||
(inh_second.is_none() &&
|
||||
// Representation optimizations are allowed.
|
||||
!def.repr.inhibit_enum_layout_opt() &&
|
||||
// Inhabited variant either has data ...
|
||||
(!variants[inh_first.unwrap()].is_empty() ||
|
||||
// ... or there other, uninhabited, variants.
|
||||
variants.len() > 1));
|
||||
if is_struct {
|
||||
// Struct, or univariant enum equivalent to a struct.
|
||||
// (Typechecking will reject discriminant-sizing attrs.)
|
||||
|
||||
let kind = if def.is_enum() || variants[0].len() == 0 {
|
||||
let v = inh_first.unwrap();
|
||||
let kind = if def.is_enum() || variants[v].len() == 0 {
|
||||
StructKind::AlwaysSized
|
||||
} else {
|
||||
let param_env = tcx.param_env(def.did);
|
||||
let last_field = def.variants[0].fields.last().unwrap();
|
||||
let last_field = def.variants[v].fields.last().unwrap();
|
||||
let always_sized = tcx.type_of(last_field.did)
|
||||
.is_sized(tcx, param_env, DUMMY_SP);
|
||||
if !always_sized { StructKind::MaybeUnsized }
|
||||
else { StructKind::AlwaysSized }
|
||||
};
|
||||
|
||||
return univariant(&variants[0], &def.repr, kind);
|
||||
let mut st = univariant_uninterned(&variants[v], &def.repr, kind)?;
|
||||
st.variants = Variants::Single { index: v };
|
||||
return Ok(tcx.intern_layout(st));
|
||||
}
|
||||
|
||||
let no_explicit_discriminants = def.variants.iter().enumerate()
|
||||
.all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i));
|
||||
|
||||
if variants.len() == 2 &&
|
||||
if inh_second.is_some() && inh_third.is_none() &&
|
||||
!def.repr.inhibit_enum_layout_opt() &&
|
||||
no_explicit_discriminants {
|
||||
// Nullable pointer optimization
|
||||
for i in 0..2 {
|
||||
if !variants[1 - i].iter().all(|f| f.is_zst()) {
|
||||
let (a, b) = (inh_first.unwrap(), inh_second.unwrap());
|
||||
for &(i, other) in &[(a, b), (b, a)] {
|
||||
if !variants[other].iter().all(|f| f.is_zst()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (field_index, field) in variants[i].iter().enumerate() {
|
||||
if let Some((offset, niche, niche_value)) = field.find_niche(cx)? {
|
||||
let mut st = vec![
|
||||
univariant_uninterned(&variants[0],
|
||||
&def.repr, StructKind::AlwaysSized)?,
|
||||
univariant_uninterned(&variants[1],
|
||||
&def.repr, StructKind::AlwaysSized)?
|
||||
];
|
||||
for (i, v) in st.iter_mut().enumerate() {
|
||||
v.variants = Variants::Single { index: i };
|
||||
}
|
||||
let st = variants.iter().enumerate().map(|(j, v)| {
|
||||
let mut st = univariant_uninterned(v,
|
||||
&def.repr, StructKind::AlwaysSized)?;
|
||||
st.variants = Variants::Single { index: j };
|
||||
Ok(st)
|
||||
}).collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let offset = st[i].fields.offset(field_index) + offset;
|
||||
let CachedLayout {
|
||||
size,
|
||||
@ -1400,6 +1432,7 @@ impl<'a, 'tcx> CachedLayout {
|
||||
return Ok(tcx.intern_layout(CachedLayout {
|
||||
variants: Variants::NicheFilling {
|
||||
dataful_variant: i,
|
||||
niche_variant: other,
|
||||
niche,
|
||||
niche_value,
|
||||
variants: st,
|
||||
@ -1419,11 +1452,15 @@ impl<'a, 'tcx> CachedLayout {
|
||||
}
|
||||
|
||||
let (mut min, mut max) = (i128::max_value(), i128::min_value());
|
||||
for discr in def.discriminants(tcx) {
|
||||
for (i, discr) in def.discriminants(tcx).enumerate() {
|
||||
if variants[i].iter().any(|f| f.abi == Abi::Uninhabited) {
|
||||
continue;
|
||||
}
|
||||
let x = discr.to_u128_unchecked() as i128;
|
||||
if x < min { min = x; }
|
||||
if x > max { max = x; }
|
||||
}
|
||||
assert!(min <= max, "discriminant range is {}...{}", min, max);
|
||||
let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max);
|
||||
|
||||
let mut align = dl.aggregate_align;
|
||||
@ -1498,6 +1535,9 @@ impl<'a, 'tcx> CachedLayout {
|
||||
let old_ity_size = min_ity.size();
|
||||
let new_ity_size = ity.size();
|
||||
for variant in &mut variants {
|
||||
if variant.abi == Abi::Uninhabited {
|
||||
continue;
|
||||
}
|
||||
match variant.fields {
|
||||
FieldPlacement::Arbitrary { ref mut offsets, .. } => {
|
||||
for i in offsets {
|
||||
@ -1663,16 +1703,11 @@ impl<'a, 'tcx> CachedLayout {
|
||||
};
|
||||
|
||||
match layout.variants {
|
||||
Variants::Single { .. } => {
|
||||
let variant_names = || {
|
||||
adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::<Vec<_>>()
|
||||
};
|
||||
debug!("print-type-size `{:#?}` variants: {:?}",
|
||||
layout, variant_names());
|
||||
assert!(adt_def.variants.len() <= 1,
|
||||
"univariant with variants {:?}", variant_names());
|
||||
if adt_def.variants.len() == 1 {
|
||||
let variant_def = &adt_def.variants[0];
|
||||
Variants::Single { index } => {
|
||||
debug!("print-type-size `{:#?}` variant {}",
|
||||
layout, adt_def.variants[index].name);
|
||||
if !adt_def.variants.is_empty() {
|
||||
let variant_def = &adt_def.variants[index];
|
||||
let fields: Vec<_> =
|
||||
variant_def.fields.iter().map(|f| f.name).collect();
|
||||
record(adt_kind.into(),
|
||||
@ -1697,7 +1732,7 @@ impl<'a, 'tcx> CachedLayout {
|
||||
variant_def.fields.iter().map(|f| f.name).collect();
|
||||
build_variant_info(Some(variant_def.name),
|
||||
&fields,
|
||||
layout.for_variant(i))
|
||||
layout.for_variant(cx, i))
|
||||
})
|
||||
.collect();
|
||||
record(adt_kind.into(), match layout.variants {
|
||||
@ -1989,15 +2024,35 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TyLayout<'tcx> {
|
||||
pub fn for_variant(&self, variant_index: usize) -> Self {
|
||||
pub fn for_variant<C>(&self, cx: C, variant_index: usize) -> Self
|
||||
where C: LayoutOf<Ty<'tcx>> + HasTyCtxt<'tcx>,
|
||||
C::TyLayout: MaybeResult<TyLayout<'tcx>>
|
||||
{
|
||||
let cached = match self.variants {
|
||||
Variants::Single { .. } => self.cached,
|
||||
Variants::Single { index } if index == variant_index => self.cached,
|
||||
|
||||
Variants::Single { index } => {
|
||||
// Deny calling for_variant more than once for non-Single enums.
|
||||
cx.layout_of(self.ty).map_same(|layout| {
|
||||
assert_eq!(layout.variants, Variants::Single { index });
|
||||
layout
|
||||
});
|
||||
|
||||
let fields = match self.ty.sty {
|
||||
ty::TyAdt(def, _) => def.variants[variant_index].fields.len(),
|
||||
_ => bug!()
|
||||
};
|
||||
let mut cached = CachedLayout::uninhabited(fields);
|
||||
cached.variants = Variants::Single { index: variant_index };
|
||||
cx.tcx().intern_layout(cached)
|
||||
}
|
||||
|
||||
Variants::NicheFilling { ref variants, .. } |
|
||||
Variants::Tagged { ref variants, .. } => {
|
||||
&variants[variant_index]
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(cached.variants, Variants::Single { index: variant_index });
|
||||
|
||||
TyLayout {
|
||||
@ -2138,6 +2193,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
||||
/// Returns true if the type is a ZST and not unsized.
|
||||
pub fn is_zst(&self) -> bool {
|
||||
match self.abi {
|
||||
Abi::Uninhabited => true,
|
||||
Abi::Scalar(_) => false,
|
||||
Abi::Vector => self.size.bytes() == 0,
|
||||
Abi::Aggregate { sized, .. } => sized && self.size.bytes() == 0
|
||||
@ -2241,11 +2297,13 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Variants {
|
||||
}
|
||||
NicheFilling {
|
||||
dataful_variant,
|
||||
niche_variant,
|
||||
ref niche,
|
||||
niche_value,
|
||||
ref variants,
|
||||
} => {
|
||||
dataful_variant.hash_stable(hcx, hasher);
|
||||
niche_variant.hash_stable(hcx, hasher);
|
||||
niche.hash_stable(hcx, hasher);
|
||||
niche_value.hash_stable(hcx, hasher);
|
||||
variants.hash_stable(hcx, hasher);
|
||||
@ -2285,6 +2343,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
||||
match *self {
|
||||
Uninhabited => {}
|
||||
Scalar(ref value) => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
|
@ -278,6 +278,7 @@ pub trait LayoutExt<'tcx> {
|
||||
impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
|
||||
fn is_aggregate(&self) -> bool {
|
||||
match self.abi {
|
||||
layout::Abi::Uninhabited |
|
||||
layout::Abi::Scalar(_) |
|
||||
layout::Abi::Vector => false,
|
||||
layout::Abi::Aggregate { .. } => true
|
||||
@ -286,6 +287,8 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
|
||||
|
||||
fn homogeneous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option<Reg> {
|
||||
match self.abi {
|
||||
layout::Abi::Uninhabited => None,
|
||||
|
||||
// The primitive for this algorithm.
|
||||
layout::Abi::Scalar(ref scalar) => {
|
||||
let kind = match scalar.value {
|
||||
|
@ -65,6 +65,8 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
|
||||
}
|
||||
|
||||
match layout.abi {
|
||||
layout::Abi::Uninhabited => {}
|
||||
|
||||
layout::Abi::Scalar(ref scalar) => {
|
||||
let reg = match scalar.value {
|
||||
layout::Int(..) |
|
||||
|
@ -17,6 +17,7 @@ use rustc::ty::layout;
|
||||
pub fn compute_abi_info(fty: &mut FnType) {
|
||||
let fixup = |a: &mut ArgType| {
|
||||
match a.layout.abi {
|
||||
layout::Abi::Uninhabited => {}
|
||||
layout::Abi::Aggregate { .. } => {
|
||||
match a.layout.size.bits() {
|
||||
8 => a.cast_to(Reg::i8()),
|
||||
|
@ -1130,43 +1130,38 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
-> Vec<MemberDescription> {
|
||||
let adt = &self.enum_type.ty_adt_def().unwrap();
|
||||
match self.layout.variants {
|
||||
layout::Variants::Single { .. } => {
|
||||
assert!(adt.variants.len() <= 1);
|
||||
layout::Variants::Single { .. } if adt.variants.is_empty() => vec![],
|
||||
layout::Variants::Single { index } => {
|
||||
let (variant_type_metadata, member_description_factory) =
|
||||
describe_enum_variant(cx,
|
||||
self.layout,
|
||||
&adt.variants[index],
|
||||
NoDiscriminant,
|
||||
self.containing_scope,
|
||||
self.span);
|
||||
|
||||
if adt.variants.is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
let (variant_type_metadata, member_description_factory) =
|
||||
describe_enum_variant(cx,
|
||||
self.layout,
|
||||
&adt.variants[0],
|
||||
NoDiscriminant,
|
||||
self.containing_scope,
|
||||
self.span);
|
||||
let member_descriptions =
|
||||
member_description_factory.create_member_descriptions(cx);
|
||||
|
||||
let member_descriptions =
|
||||
member_description_factory.create_member_descriptions(cx);
|
||||
|
||||
set_members_of_composite_type(cx,
|
||||
variant_type_metadata,
|
||||
&member_descriptions[..]);
|
||||
vec![
|
||||
MemberDescription {
|
||||
name: "".to_string(),
|
||||
type_metadata: variant_type_metadata,
|
||||
offset: Size::from_bytes(0),
|
||||
size: self.layout.size,
|
||||
align: self.layout.align,
|
||||
flags: DIFlags::FlagZero
|
||||
}
|
||||
]
|
||||
}
|
||||
set_members_of_composite_type(cx,
|
||||
variant_type_metadata,
|
||||
&member_descriptions[..]);
|
||||
vec![
|
||||
MemberDescription {
|
||||
name: "".to_string(),
|
||||
type_metadata: variant_type_metadata,
|
||||
offset: Size::from_bytes(0),
|
||||
size: self.layout.size,
|
||||
align: self.layout.align,
|
||||
flags: DIFlags::FlagZero
|
||||
}
|
||||
]
|
||||
}
|
||||
layout::Variants::Tagged { ref variants, .. } => {
|
||||
let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata
|
||||
.expect(""));
|
||||
(0..variants.len()).map(|i| {
|
||||
let variant = self.layout.for_variant(i);
|
||||
let variant = self.layout.for_variant(cx, i);
|
||||
let (variant_type_metadata, member_desc_factory) =
|
||||
describe_enum_variant(cx,
|
||||
variant,
|
||||
@ -1191,8 +1186,8 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
layout::Variants::NicheFilling { dataful_variant, .. } => {
|
||||
let variant = self.layout.for_variant(dataful_variant);
|
||||
layout::Variants::NicheFilling { dataful_variant, niche_variant, .. } => {
|
||||
let variant = self.layout.for_variant(cx, dataful_variant);
|
||||
// Create a description of the non-null variant
|
||||
let (variant_type_metadata, member_description_factory) =
|
||||
describe_enum_variant(cx,
|
||||
@ -1236,7 +1231,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
self.layout,
|
||||
self.layout.fields.offset(0),
|
||||
self.layout.field(cx, 0).size);
|
||||
name.push_str(&adt.variants[1 - dataful_variant].name.as_str());
|
||||
name.push_str(&adt.variants[niche_variant].name.as_str());
|
||||
|
||||
// Create the (singleton) list of descriptions of union members.
|
||||
vec![
|
||||
|
@ -710,7 +710,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
Immediate(llval) => {
|
||||
for i in 0..tuple.layout.fields.count() {
|
||||
let field = tuple.layout.field(bcx.ccx, i);
|
||||
let elem = bcx.extract_value(llval, tuple.layout.llvm_field_index(i));
|
||||
let elem = if field.is_zst() {
|
||||
C_undef(field.llvm_type(bcx.ccx))
|
||||
} else {
|
||||
bcx.extract_value(llval, tuple.layout.llvm_field_index(i))
|
||||
};
|
||||
// If the tuple is immediate, the elements are as well
|
||||
let op = OperandRef {
|
||||
val: Immediate(base::to_immediate(bcx, elem, field)),
|
||||
|
@ -1099,6 +1099,11 @@ fn trans_const_adt<'a, 'tcx>(
|
||||
mir::AggregateKind::Adt(_, index, _, _) => index,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
if let layout::Abi::Uninhabited = l.abi {
|
||||
return Const::new(C_undef(l.llvm_type(ccx)), t);
|
||||
}
|
||||
|
||||
match l.variants {
|
||||
layout::Variants::Single { index } => {
|
||||
assert_eq!(variant_index, index);
|
||||
@ -1114,7 +1119,6 @@ fn trans_const_adt<'a, 'tcx>(
|
||||
|
||||
Const::new(C_struct(ccx, &contents, l.is_packed()), t)
|
||||
} else {
|
||||
assert_eq!(variant_index, 0);
|
||||
build_const_struct(ccx, l, vals, None)
|
||||
}
|
||||
}
|
||||
@ -1132,12 +1136,12 @@ fn trans_const_adt<'a, 'tcx>(
|
||||
Const::new(discr, t)
|
||||
} else {
|
||||
let discr = Const::new(discr, discr_field.ty);
|
||||
build_const_struct(ccx, l.for_variant(variant_index), vals, Some(discr))
|
||||
build_const_struct(ccx, l.for_variant(ccx, variant_index), vals, Some(discr))
|
||||
}
|
||||
}
|
||||
layout::Variants::NicheFilling { dataful_variant, niche_value, .. } => {
|
||||
if variant_index == dataful_variant {
|
||||
build_const_struct(ccx, l.for_variant(dataful_variant), vals, None)
|
||||
build_const_struct(ccx, l.for_variant(ccx, dataful_variant), vals, None)
|
||||
} else {
|
||||
let niche = l.field(ccx, 0);
|
||||
let niche_llty = niche.llvm_type(ccx);
|
||||
|
@ -115,7 +115,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
assert_eq!(count, 0);
|
||||
self.llextra
|
||||
} else {
|
||||
common::C_usize(ccx, count)
|
||||
C_usize(ccx, count)
|
||||
}
|
||||
} else {
|
||||
bug!("unexpected layout `{:#?}` in LvalueRef::len", self.layout)
|
||||
@ -304,7 +304,12 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
};
|
||||
bcx.intcast(lldiscr, cast_to, signed)
|
||||
}
|
||||
layout::Variants::NicheFilling { dataful_variant, niche_value, .. } => {
|
||||
layout::Variants::NicheFilling {
|
||||
dataful_variant,
|
||||
niche_variant,
|
||||
niche_value,
|
||||
..
|
||||
} => {
|
||||
let niche_llty = discr.layout.llvm_type(bcx.ccx);
|
||||
// FIXME(eddyb) Check the actual primitive type here.
|
||||
let niche_llval = if niche_value == 0 {
|
||||
@ -313,8 +318,9 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
} else {
|
||||
C_uint_big(niche_llty, niche_value)
|
||||
};
|
||||
let cmp = if dataful_variant == 0 { llvm::IntEQ } else { llvm::IntNE };
|
||||
bcx.intcast(bcx.icmp(cmp, lldiscr, niche_llval), cast_to, false)
|
||||
bcx.select(bcx.icmp(llvm::IntEQ, lldiscr, niche_llval),
|
||||
C_uint(cast_to, niche_variant as u64),
|
||||
C_uint(cast_to, dataful_variant as u64))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -324,7 +330,12 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
pub fn trans_set_discr(&self, bcx: &Builder<'a, 'tcx>, variant_index: usize) {
|
||||
match self.layout.variants {
|
||||
layout::Variants::Single { index } => {
|
||||
assert_eq!(variant_index, index);
|
||||
if index != variant_index {
|
||||
// If the layout of an enum is `Single`, all
|
||||
// other variants are necessarily uninhabited.
|
||||
assert_eq!(self.layout.for_variant(bcx.ccx, variant_index).abi,
|
||||
layout::Abi::Uninhabited);
|
||||
}
|
||||
}
|
||||
layout::Variants::Tagged { .. } => {
|
||||
let ptr = self.project_field(bcx, 0);
|
||||
@ -366,7 +377,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
pub fn project_index(&self, bcx: &Builder<'a, 'tcx>, llindex: ValueRef)
|
||||
-> LvalueRef<'tcx> {
|
||||
LvalueRef {
|
||||
llval: bcx.inbounds_gep(self.llval, &[common::C_usize(bcx.ccx, 0), llindex]),
|
||||
llval: bcx.inbounds_gep(self.llval, &[C_usize(bcx.ccx, 0), llindex]),
|
||||
llextra: ptr::null_mut(),
|
||||
layout: self.layout.field(bcx.ccx, 0),
|
||||
alignment: self.alignment
|
||||
@ -376,7 +387,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
pub fn project_downcast(&self, bcx: &Builder<'a, 'tcx>, variant_index: usize)
|
||||
-> LvalueRef<'tcx> {
|
||||
let mut downcast = *self;
|
||||
downcast.layout = self.layout.for_variant(variant_index);
|
||||
downcast.layout = self.layout.for_variant(bcx.ccx, variant_index);
|
||||
|
||||
// Cast to the appropriate variant struct type.
|
||||
let variant_ty = downcast.layout.llvm_type(bcx.ccx);
|
||||
|
@ -27,6 +27,7 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
return Type::vector(&layout.field(ccx, 0).llvm_type(ccx),
|
||||
layout.fields.count() as u64);
|
||||
}
|
||||
layout::Abi::Uninhabited |
|
||||
layout::Abi::Aggregate { .. } => {}
|
||||
}
|
||||
|
||||
@ -158,7 +159,9 @@ pub trait LayoutLlvmExt<'tcx> {
|
||||
impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
|
||||
fn is_llvm_immediate(&self) -> bool {
|
||||
match self.abi {
|
||||
layout::Abi::Scalar(_) | layout::Abi::Vector => true,
|
||||
layout::Abi::Uninhabited |
|
||||
layout::Abi::Scalar(_) |
|
||||
layout::Abi::Vector => true,
|
||||
|
||||
layout::Abi::Aggregate { .. } => self.is_zst()
|
||||
}
|
||||
@ -230,7 +233,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
|
||||
let llty = if self.ty != normal_ty {
|
||||
let mut layout = ccx.layout_of(normal_ty);
|
||||
if let Some(v) = variant_index {
|
||||
layout = layout.for_variant(v);
|
||||
layout = layout.for_variant(ccx, v);
|
||||
}
|
||||
layout.llvm_type(ccx)
|
||||
} else {
|
||||
|
18
src/test/ui/print_type_sizes/uninhabited.rs
Normal file
18
src/test/ui/print_type_sizes/uninhabited.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags: -Z print-type-sizes
|
||||
|
||||
#![feature(never_type)]
|
||||
|
||||
pub fn main() {
|
||||
let _x: Option<!> = None;
|
||||
let _y: Result<u32, !> = Ok(42);
|
||||
}
|
5
src/test/ui/print_type_sizes/uninhabited.stdout
Normal file
5
src/test/ui/print_type_sizes/uninhabited.stdout
Normal file
@ -0,0 +1,5 @@
|
||||
print-type-size type: `std::result::Result<u32, !>`: 4 bytes, alignment: 4 bytes
|
||||
print-type-size variant `Ok`: 4 bytes
|
||||
print-type-size field `.0`: 4 bytes
|
||||
print-type-size type: `std::option::Option<!>`: 0 bytes, alignment: 1 bytes
|
||||
print-type-size variant `None`: 0 bytes
|
Loading…
Reference in New Issue
Block a user