Skip to content

Commit

Permalink
Auto merge of #49513 - nox:univariant-fieldless-enum-as-zst, r=eddyb
Browse files Browse the repository at this point in the history
Treat repr(Rust) univariant fieldless enums as ZSTs

This makes all those enums be represented the same way:

```rust
enum A1 { B1 }
enum A2 { B2 = 0 }
enum A3 { B3, C3(!) }
```

Related to #15747.

Cc @rust-lang/wg-codegen @rust-lang/lang
  • Loading branch information
bors committed Apr 26, 2018
2 parents 949010d + 1c09977 commit 7f3444e
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 15 deletions.
9 changes: 4 additions & 5 deletions src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -727,11 +727,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
// 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));
!def.repr.inhibit_enum_layout_opt());
if is_struct {
// Struct, or univariant enum equivalent to a struct.
// (Typechecking will reject discriminant-sizing attrs.)
Expand Down Expand Up @@ -765,6 +761,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
return Ok(tcx.intern_layout(st));
}

// The current code for niche-filling relies on variant indices
// instead of actual discriminants, so dataful enums with
// explicit discriminants (RFC #2363) would misbehave.
let no_explicit_discriminants = def.variants.iter().enumerate()
.all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i));

Expand Down
34 changes: 33 additions & 1 deletion src/librustc_mir/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,23 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
(Value::ByVal(_), _) => bug!("expected fat ptr"),
}
} else {
let src_layout = self.layout_of(src.ty)?;
match src_layout.variants {
layout::Variants::Single { index } => {
if let Some(def) = src.ty.ty_adt_def() {
let discr_val = def
.discriminant_for_variant(*self.tcx, index)
.val;
return self.write_primval(
dest,
PrimVal::Bytes(discr_val),
dest_ty);
}
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => {},
}

let src_val = self.value_to_primval(src)?;
let dest_val = self.cast_primval(src_val, src.ty, dest_ty)?;
let valty = ValTy {
Expand Down Expand Up @@ -852,10 +869,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
) -> EvalResult<'tcx, u128> {
let layout = self.layout_of(ty)?;
trace!("read_discriminant_value {:#?}", layout);
if layout.abi == layout::Abi::Uninhabited {
return Ok(0);
}

match layout.variants {
layout::Variants::Single { index } => {
return Ok(index as u128);
let discr_val = ty.ty_adt_def().map_or(
index as u128,
|def| def.discriminant_for_variant(*self.tcx, index).val);
return Ok(discr_val);
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => {},
Expand Down Expand Up @@ -1318,6 +1341,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
use syntax::ast::FloatTy;

let layout = self.layout_of(ty)?;
// do the strongest layout check of the two
let align = layout.align.max(ptr_align);
self.memory.check_align(ptr, align)?;

if layout.size.bytes() == 0 {
return Ok(Some(Value::ByVal(PrimVal::Undef)));
}

let ptr = ptr.to_ptr()?;
let val = match ty.sty {
ty::TyBool => {
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
let val = [a, b][field_index];
Ok(Some((Value::ByVal(val), field.ty)))
},
// FIXME(oli-obk): figure out whether we should be calling `try_read_value` here
_ => Ok(None),
}
}
Expand Down
18 changes: 13 additions & 5 deletions src/librustc_trans/mir/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use rustc::mir::tcx::PlaceTy;
use rustc_data_structures::indexed_vec::Idx;
use base;
use builder::Builder;
use common::{CodegenCx, C_usize, C_u8, C_u32, C_uint, C_int, C_null, C_uint_big};
use common::{CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big};
use consts;
use type_of::LayoutLlvmExt;
use type_::Type;
Expand Down Expand Up @@ -264,9 +264,15 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
/// Obtain the actual discriminant of a value.
pub fn trans_get_discr(self, bx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef {
let cast_to = bx.cx.layout_of(cast_to).immediate_llvm_type(bx.cx);
if self.layout.abi == layout::Abi::Uninhabited {
return C_undef(cast_to);
}
match self.layout.variants {
layout::Variants::Single { index } => {
return C_uint(cast_to, index as u64);
let discr_val = self.layout.ty.ty_adt_def().map_or(
index as u128,
|def| def.discriminant_for_variant(bx.cx.tcx, index).val);
return C_uint_big(cast_to, discr_val);
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => {},
Expand Down Expand Up @@ -328,9 +334,11 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
let ptr = self.project_field(bx, 0);
let to = self.layout.ty.ty_adt_def().unwrap()
.discriminant_for_variant(bx.tcx(), variant_index)
.val as u64;
bx.store(C_int(ptr.layout.llvm_type(bx.cx), to as i64),
ptr.llval, ptr.align);
.val;
bx.store(
C_uint_big(ptr.layout.llvm_type(bx.cx), to),
ptr.llval,
ptr.align);
}
layout::Variants::NicheFilling {
dataful_variant,
Expand Down
26 changes: 24 additions & 2 deletions src/librustc_trans/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use base;
use builder::Builder;
use callee;
use common::{self, val_ty};
use common::{C_bool, C_u8, C_i32, C_u32, C_u64, C_null, C_usize, C_uint, C_uint_big};
use common::{C_bool, C_u8, C_i32, C_u32, C_u64, C_undef, C_null, C_usize, C_uint, C_uint_big};
use consts;
use monomorphize;
use type_::Type;
Expand Down Expand Up @@ -267,11 +267,33 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
}
mir::CastKind::Misc => {
assert!(cast.is_llvm_immediate());
let ll_t_out = cast.immediate_llvm_type(bx.cx);
if operand.layout.abi == layout::Abi::Uninhabited {
return (bx, OperandRef {
val: OperandValue::Immediate(C_undef(ll_t_out)),
layout: cast,
});
}
let r_t_in = CastTy::from_ty(operand.layout.ty)
.expect("bad input type for cast");
let r_t_out = CastTy::from_ty(cast.ty).expect("bad output type for cast");
let ll_t_in = operand.layout.immediate_llvm_type(bx.cx);
let ll_t_out = cast.immediate_llvm_type(bx.cx);
match operand.layout.variants {
layout::Variants::Single { index } => {
if let Some(def) = operand.layout.ty.ty_adt_def() {
let discr_val = def
.discriminant_for_variant(bx.cx.tcx, index)
.val;
let discr = C_uint_big(ll_t_out, discr_val);
return (bx, OperandRef {
val: OperandValue::Immediate(discr),
layout: cast,
});
}
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => {},
}
let llval = operand.immediate();

let mut signed = false;
Expand Down
1 change: 1 addition & 0 deletions src/test/debuginfo/c-style-enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ enum ManualDiscriminant {
}

#[derive(Copy, Clone)]
#[repr(u8)]
enum SingleVariant {
TheOnlyVariant
}
Expand Down
9 changes: 7 additions & 2 deletions src/test/run-pass/issue-23304-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@

#![allow(dead_code)]

enum X { A = 0 as isize }
enum X { A = 42 as isize }

enum Y { A = X::A as isize }

fn main() { }
fn main() {
let x = X::A;
let x = x as isize;
assert_eq!(x, 42);
assert_eq!(Y::A as isize, 42);
}
33 changes: 33 additions & 0 deletions src/test/run-pass/type-sizes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,31 @@ enum ReorderedEnum {
B(u8, u16, u8),
}

enum EnumEmpty {}

enum EnumSingle1 {
A,
}

enum EnumSingle2 {
A = 42 as isize,
}

enum EnumSingle3 {
A,
B(!),
}

#[repr(u8)]
enum EnumSingle4 {
A,
}

#[repr(u8)]
enum EnumSingle5 {
A = 42 as u8,
}

enum NicheFilledEnumWithInhabitedVariant {
A(&'static ()),
B(&'static (), !),
Expand Down Expand Up @@ -74,5 +99,13 @@ pub fn main() {
assert_eq!(size_of::<e3>(), 4 as usize);
assert_eq!(size_of::<ReorderedStruct>(), 4);
assert_eq!(size_of::<ReorderedEnum>(), 6);

assert_eq!(size_of::<EnumEmpty>(), 0);
assert_eq!(size_of::<EnumSingle1>(), 0);
assert_eq!(size_of::<EnumSingle2>(), 0);
assert_eq!(size_of::<EnumSingle3>(), 0);
assert_eq!(size_of::<EnumSingle4>(), 1);
assert_eq!(size_of::<EnumSingle5>(), 1);

assert_eq!(size_of::<NicheFilledEnumWithInhabitedVariant>(), size_of::<&'static ()>());
}

0 comments on commit 7f3444e

Please sign in to comment.