diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index a9e7b2732079b96e0c3d7a231c01e39529cd15b8..9cea6d0249cc4374d8ea550ca31388a310e5acaa 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -85,20 +85,30 @@ pub enum Repr { * all start with a field for the discriminant. */ General(IntType, Vec), + /** + * Two cases distinguished by a nullable pointer: the case with discriminant + * `nndiscr` must have single field which is known to be nonnull due to its type. + * The other case is known to be zero sized. Hence we represent the enum + * as simply a nullable pointer: if not null it indicates the `nndiscr` variant, + * otherwise it indicates the other case. + */ + RawNullablePointer { + pub nndiscr: Disr, + pub nnty: ty::t, + pub nullfields: Vec + }, /** * Two cases distinguished by a nullable pointer: the case with discriminant * `nndiscr` is represented by the struct `nonnull`, where the `ptrfield`th * field is known to be nonnull due to its type; if that field is null, then * it represents the other case, which is inhabited by at most one value * (and all other fields are undefined/unused). - * If the case with the nullable pointer has a single field then we don't - * wrap it in a struct and instead just deal with it directly as a pointer. * * For example, `std::option::Option` instantiated at a safe pointer type * is represented such that `None` is a null pointer and `Some` is the * identity function. */ - NullablePointer { + StructWrappedNullablePointer { pub nonnull: Struct, pub nndiscr: Disr, pub ptrfield: uint, @@ -202,17 +212,23 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr { if cases.get(1 - discr).is_zerolen(cx) { match cases.get(discr).find_ptr() { Some(ptrfield) => { - return NullablePointer { - nndiscr: discr as u64, - nonnull: mk_struct(cx, - cases.get(discr) - .tys - .as_slice(), - false), - ptrfield: ptrfield, - nullfields: cases.get(1 - discr).tys - .clone() - } + let st = mk_struct(cx, cases.get(discr).tys.as_slice(), + false); + + return if st.fields.len() == 1 { + RawNullablePointer { + nndiscr: discr as Disr, + nnty: *st.fields.get(0), + nullfields: cases.get(1 - discr).tys.clone() + } + } else { + StructWrappedNullablePointer { + nndiscr: discr as Disr, + nonnull: st, + ptrfield: ptrfield, + nullfields: cases.get(1 - discr).tys.clone() + } + }; } None => { } } @@ -415,11 +431,8 @@ pub fn incomplete_type_of(cx: &CrateContext, r: &Repr, name: &str) -> Type { } pub fn finish_type_of(cx: &CrateContext, r: &Repr, llty: &mut Type) { match *r { - CEnum(..) | General(..) => { - } - NullablePointer { nonnull: ref st, .. } if st.fields.len() == 1 => { - } - Univariant(ref st, _) | NullablePointer { nonnull: ref st, .. } => + CEnum(..) | General(..) | RawNullablePointer { .. } => { } + Univariant(ref st, _) | StructWrappedNullablePointer { nonnull: ref st, .. } => llty.set_struct_body(struct_llfields(cx, st, false).as_slice(), st.packed) } @@ -428,14 +441,8 @@ pub fn finish_type_of(cx: &CrateContext, r: &Repr, llty: &mut Type) { fn generic_type_of(cx: &CrateContext, r: &Repr, name: Option<&str>, sizing: bool) -> Type { match *r { CEnum(ity, _, _) => ll_inttype(cx, ity), - NullablePointer { nonnull: ref st, .. } if st.fields.len() == 1 => { - if sizing { - type_of::sizing_type_of(cx, *st.fields.get(0)) - } else { - type_of::type_of(cx, *st.fields.get(0)) - } - } - Univariant(ref st, _) | NullablePointer { nonnull: ref st, .. } => { + RawNullablePointer { nnty, .. } => type_of::sizing_type_of(cx, nnty), + Univariant(ref st, _) | StructWrappedNullablePointer { nonnull: ref st, .. } => { match name { None => { Type::struct_(cx, struct_llfields(cx, st, sizing).as_slice(), @@ -507,12 +514,10 @@ fn struct_llfields(cx: &CrateContext, st: &Struct, sizing: bool) -> Vec { pub fn trans_switch(bcx: &Block, r: &Repr, scrutinee: ValueRef) -> (_match::branch_kind, Option) { match *r { - CEnum(..) | General(..) => { + CEnum(..) | General(..) | + RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => { (_match::switch, Some(trans_get_discr(bcx, r, scrutinee, None))) } - NullablePointer { nonnull: ref nonnull, nndiscr, ptrfield, .. } => { - (_match::switch, Some(nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee))) - } Univariant(..) => { (_match::single, None) } @@ -540,8 +545,14 @@ pub fn trans_get_discr(bcx: &Block, r: &Repr, scrutinee: ValueRef, cast_to: Opti val = C_u8(bcx.ccx(), 0); signed = false; } - NullablePointer { nonnull: ref nonnull, nndiscr, ptrfield, .. } => { - val = nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee); + RawNullablePointer { nndiscr, nnty, .. } => { + let cmp = if nndiscr == 0 { IntEQ } else { IntNE }; + let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty); + val = ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty)); + signed = false; + } + StructWrappedNullablePointer { nonnull: ref nonnull, nndiscr, ptrfield, .. } => { + val = struct_wrapped_nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee); signed = false; } } @@ -551,13 +562,9 @@ pub fn trans_get_discr(bcx: &Block, r: &Repr, scrutinee: ValueRef, cast_to: Opti } } -fn nullable_bitdiscr(bcx: &Block, nonnull: &Struct, nndiscr: Disr, ptrfield: uint, - scrutinee: ValueRef) -> ValueRef { - let llptr = if nonnull.fields.len() == 1 { - Load(bcx, scrutinee) - } else { - Load(bcx, GEPi(bcx, scrutinee, [0, ptrfield])) - }; +fn struct_wrapped_nullable_bitdiscr(bcx: &Block, nonnull: &Struct, nndiscr: Disr, ptrfield: uint, + scrutinee: ValueRef) -> ValueRef { + let llptr = Load(bcx, GEPi(bcx, scrutinee, [0, ptrfield])); let cmp = if nndiscr == 0 { IntEQ } else { IntNE }; let llptrty = type_of::type_of(bcx.ccx(), *nonnull.fields.get(ptrfield)); ICmp(bcx, cmp, llptr, C_null(llptrty)) @@ -606,7 +613,8 @@ pub fn trans_case<'a>(bcx: &'a Block<'a>, r: &Repr, discr: Disr) Univariant(..) => { bcx.ccx().sess().bug("no cases for univariants or structs") } - NullablePointer { .. } => { + RawNullablePointer { .. } | + StructWrappedNullablePointer { .. } => { assert!(discr == 0 || discr == 1); _match::single_result(Result::new(bcx, C_i1(bcx.ccx(), discr != 0))) } @@ -637,13 +645,15 @@ pub fn trans_start_init(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) { Univariant(..) => { assert_eq!(discr, 0); } - NullablePointer { nonnull: ref nonnull, nndiscr, ptrfield, .. } => { + RawNullablePointer { nndiscr, nnty, ..} => { if discr != nndiscr { - let llptrptr = if nonnull.fields.len() == 1 { - val - } else { - GEPi(bcx, val, [0, ptrfield]) - }; + let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty); + Store(bcx, C_null(llptrty), val) + } + } + StructWrappedNullablePointer { nonnull: ref nonnull, nndiscr, ptrfield, .. } => { + if discr != nndiscr { + let llptrptr = GEPi(bcx, val, [0, ptrfield]); let llptrty = type_of::type_of(bcx.ccx(), *nonnull.fields.get(ptrfield)); Store(bcx, C_null(llptrty), llptrptr) @@ -671,8 +681,11 @@ pub fn num_args(r: &Repr, discr: Disr) -> uint { st.fields.len() - (if dtor { 1 } else { 0 }) } General(_, ref cases) => cases.get(discr as uint).fields.len() - 1, - NullablePointer { nonnull: ref nonnull, nndiscr, - nullfields: ref nullfields, .. } => { + RawNullablePointer { nndiscr, ref nullfields, .. } => { + if discr == nndiscr { 1 } else { nullfields.len() } + } + StructWrappedNullablePointer { nonnull: ref nonnull, nndiscr, + nullfields: ref nullfields, .. } => { if discr == nndiscr { nonnull.fields.len() } else { nullfields.len() } } } @@ -695,24 +708,25 @@ pub fn trans_field_ptr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr, General(_, ref cases) => { struct_field_ptr(bcx, cases.get(discr as uint), val, ix + 1, true) } - NullablePointer { nonnull: ref nonnull, nullfields: ref nullfields, - nndiscr, .. } => { - if discr == nndiscr { - if nonnull.fields.len() == 1 { - assert_eq!(ix, 0); - val - } else { - struct_field_ptr(bcx, nonnull, val, ix, false) - } - } else { - // The unit-like case might have a nonzero number of unit-like fields. - // (e.g., Result or Either with () as one side.) - let ty = type_of::type_of(bcx.ccx(), *nullfields.get(ix)); - assert_eq!(machine::llsize_of_alloc(bcx.ccx(), ty), 0); - // The contents of memory at this pointer can't matter, but use - // the value that's "reasonable" in case of pointer comparison. - PointerCast(bcx, val, ty.ptr_to()) - } + RawNullablePointer { nndiscr, ref nullfields, .. } | + StructWrappedNullablePointer { nndiscr, ref nullfields, .. } if discr != nndiscr => { + // The unit-like case might have a nonzero number of unit-like fields. + // (e.d., Result of Either with (), as one side.) + let ty = type_of::type_of(bcx.ccx(), *nullfields.get(ix)); + assert_eq!(machine::llsize_of_alloc(bcx.ccx(), ty), 0); + // The contents of memory at this pointer can't matter, but use + // the value that's "reasonable" in case of pointer comparision. + PointerCast(bcx, val, ty.ptr_to()) + } + RawNullablePointer { nndiscr, nnty, .. } => { + assert_eq!(ix, 0); + assert_eq!(discr, nndiscr); + let ty = type_of::type_of(bcx.ccx(), nnty); + PointerCast(bcx, val, ty.ptr_to()) + } + StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => { + assert_eq!(discr, nndiscr); + struct_field_ptr(bcx, nonnull, val, ix, false) } } } @@ -784,15 +798,15 @@ pub fn trans_const(ccx: &CrateContext, r: &Repr, discr: Disr, let contents = build_const_struct(ccx, st, vals); C_struct(ccx, contents.as_slice(), st.packed) } - NullablePointer { nonnull: ref st, nndiscr, .. } if st.fields.len() == 1 => { + RawNullablePointer { nndiscr, nnty, .. } => { if discr == nndiscr { assert_eq!(vals.len(), 1); vals[0] } else { - C_null(type_of::sizing_type_of(ccx, *st.fields.get(0))) + C_null(type_of::sizing_type_of(ccx, nnty)) } } - NullablePointer { nonnull: ref nonnull, nndiscr, .. } => { + StructWrappedNullablePointer { nonnull: ref nonnull, nndiscr, .. } => { if discr == nndiscr { C_struct(ccx, build_const_struct(ccx, nonnull, @@ -900,7 +914,7 @@ pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef) } } Univariant(..) => 0, - NullablePointer { nonnull: ref st, nndiscr, .. } if st.fields.len() == 1 => { + RawNullablePointer { nndiscr, .. } => { if is_null(val) { /* subtraction as uint is ok because nndiscr is either 0 or 1 */ (1 - nndiscr) as Disr @@ -908,7 +922,7 @@ pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef) nndiscr } } - NullablePointer { nndiscr, ptrfield, .. } => { + StructWrappedNullablePointer { nndiscr, ptrfield, .. } => { if is_null(const_struct_field(ccx, val, ptrfield)) { /* subtraction as uint is ok because nndiscr is either 0 or 1 */ (1 - nndiscr) as Disr @@ -932,11 +946,11 @@ pub fn const_get_field(ccx: &CrateContext, r: &Repr, val: ValueRef, CEnum(..) => ccx.sess().bug("element access in C-like enum const"), Univariant(..) => const_struct_field(ccx, val, ix), General(..) => const_struct_field(ccx, val, ix + 1), - NullablePointer { nonnull: ref st, .. } if st.fields.len() == 1 => { + RawNullablePointer { .. } => { assert_eq!(ix, 0); val } - NullablePointer{ .. } => const_struct_field(ccx, val, ix) + StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix) } } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index e185d7702ff4d5d4789cb43654eb9b09ca51e4a4..12c7c22b9a18367e8832e25c7f81490aa2875e0b 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -1657,7 +1657,10 @@ fn prepare_enum_metadata(cx: &CrateContext, }), } } - adt::NullablePointer { nonnull: ref struct_def, nndiscr, .. } => { + adt::RawNullablePointer { nnty, .. } => { + FinalMetadata(type_metadata(cx, nnty, span)) + } + adt::StructWrappedNullablePointer { nonnull: ref struct_def, nndiscr, .. } => { let (metadata_stub, variant_llvm_type, member_description_factory) =