type Hint = attr::ReprAttr;
+// Representation of the context surrounding an unsized type. I want
+// to be able to track the drop flags that are injected by trans.
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub struct TypeContext {
+ prefix: Type,
+ needs_drop_flag: bool,
+}
+
+impl TypeContext {
+ pub fn prefix(&self) -> Type { self.prefix }
+ pub fn needs_drop_flag(&self) -> bool { self.needs_drop_flag }
+
+ fn direct(t: Type) -> TypeContext {
+ TypeContext { prefix: t, needs_drop_flag: false }
+ }
+ fn may_need_drop_flag(t: Type, needs_drop_flag: bool) -> TypeContext {
+ TypeContext { prefix: t, needs_drop_flag: needs_drop_flag }
+ }
+ pub fn to_string(self) -> String {
+ let TypeContext { prefix, needs_drop_flag } = self;
+ format!("TypeContext {{ prefix: {}, needs_drop_flag: {} }}",
+ prefix.to_string(), needs_drop_flag)
+ }
+}
+
/// Representations.
#[derive(Eq, PartialEq, Debug)]
pub enum Repr<'tcx> {
pub align: u32,
pub sized: bool,
pub packed: bool,
- pub fields: Vec<Ty<'tcx>>
+ pub fields: Vec<Ty<'tcx>>,
}
/// Convenience for `represent_type`. There should probably be more or
/// and fill in the actual contents in a second pass to prevent
/// unbounded recursion; see also the comments in `trans::type_of`.
pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>) -> Type {
- generic_type_of(cx, r, None, false, false)
+ let c = generic_type_of(cx, r, None, false, false, false);
+ assert!(!c.needs_drop_flag);
+ c.prefix
}
+
+
// Pass dst=true if the type you are passing is a DST. Yes, we could figure
// this out, but if you call this on an unsized type without realising it, you
// are going to get the wrong type (it will not include the unsized parts of it).
pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
r: &Repr<'tcx>, dst: bool) -> Type {
- generic_type_of(cx, r, None, true, dst)
+ let c = generic_type_of(cx, r, None, true, dst, false);
+ assert!(!c.needs_drop_flag);
+ c.prefix
+}
+pub fn sizing_type_context_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
+ r: &Repr<'tcx>, dst: bool) -> TypeContext {
+ generic_type_of(cx, r, None, true, dst, true)
}
pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
r: &Repr<'tcx>, name: &str) -> Type {
- generic_type_of(cx, r, Some(name), false, false)
+ let c = generic_type_of(cx, r, Some(name), false, false, false);
+ assert!(!c.needs_drop_flag);
+ c.prefix
}
pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
r: &Repr<'tcx>, llty: &mut Type) {
r: &Repr<'tcx>,
name: Option<&str>,
sizing: bool,
- dst: bool) -> Type {
+ dst: bool,
+ delay_drop_flag: bool) -> TypeContext {
+ debug!("adt::generic_type_of r: {:?} name: {:?} sizing: {} dst: {} delay_drop_flag: {}",
+ r, name, sizing, dst, delay_drop_flag);
match *r {
- CEnum(ity, _, _) => ll_inttype(cx, ity),
- RawNullablePointer { nnty, .. } => type_of::sizing_type_of(cx, nnty),
- Univariant(ref st, _) | StructWrappedNullablePointer { nonnull: ref st, .. } => {
+ CEnum(ity, _, _) => TypeContext::direct(ll_inttype(cx, ity)),
+ RawNullablePointer { nnty, .. } =>
+ TypeContext::direct(type_of::sizing_type_of(cx, nnty)),
+ StructWrappedNullablePointer { nonnull: ref st, .. } => {
+ match name {
+ None => {
+ TypeContext::direct(
+ Type::struct_(cx, &struct_llfields(cx, st, sizing, dst),
+ st.packed))
+ }
+ Some(name) => {
+ assert_eq!(sizing, false);
+ TypeContext::direct(Type::named_struct(cx, name))
+ }
+ }
+ }
+ Univariant(ref st, dtor_needed) => {
+ let dtor_needed = dtor_needed != 0;
match name {
None => {
- Type::struct_(cx, &struct_llfields(cx, st, sizing, dst),
- st.packed)
+ let mut fields = struct_llfields(cx, st, sizing, dst);
+ if delay_drop_flag && dtor_needed {
+ fields.pop();
+ }
+ TypeContext::may_need_drop_flag(
+ Type::struct_(cx, &fields,
+ st.packed),
+ delay_drop_flag && dtor_needed)
+ }
+ Some(name) => {
+ // Hypothesis: named_struct's can never need a
+ // drop flag. (... needs validation.)
+ assert_eq!(sizing, false);
+ TypeContext::direct(Type::named_struct(cx, name))
}
- Some(name) => { assert_eq!(sizing, false); Type::named_struct(cx, name) }
}
}
- General(ity, ref sts, _) => {
+ General(ity, ref sts, dtor_needed) => {
+ let dtor_needed = dtor_needed != 0;
// We need a representation that has:
// * The alignment of the most-aligned field
// * The size of the largest variant (rounded up to that alignment)
};
assert_eq!(machine::llalign_of_min(cx, fill_ty), align);
assert_eq!(align_s % discr_size, 0);
- let fields = [discr_ty,
- Type::array(&discr_ty, align_s / discr_size - 1),
- fill_ty];
+ let mut fields: Vec<Type> =
+ [discr_ty,
+ Type::array(&discr_ty, align_s / discr_size - 1),
+ fill_ty].iter().cloned().collect();
+ if delay_drop_flag && dtor_needed {
+ fields.pop();
+ }
match name {
- None => Type::struct_(cx, &fields[..], false),
+ None => {
+ TypeContext::may_need_drop_flag(
+ Type::struct_(cx, &fields[..], false),
+ delay_drop_flag && dtor_needed)
+ }
Some(name) => {
let mut llty = Type::named_struct(cx, name);
llty.set_struct_body(&fields[..], false);
- llty
+ TypeContext::may_need_drop_flag(
+ llty,
+ delay_drop_flag && dtor_needed)
}
}
}
t, bcx.val_to_string(info));
if type_is_sized(bcx.tcx(), t) {
let sizing_type = sizing_type_of(bcx.ccx(), t);
- let size = C_uint(bcx.ccx(), llsize_of_alloc(bcx.ccx(), sizing_type));
- let align = C_uint(bcx.ccx(), align_of(bcx.ccx(), t));
+ let size = llsize_of_alloc(bcx.ccx(), sizing_type);
+ let align = align_of(bcx.ccx(), t);
+ debug!("size_and_align_of_dst t={} info={} size: {} align: {}",
+ t, bcx.val_to_string(info), size, align);
+ let size = C_uint(bcx.ccx(), size);
+ let align = C_uint(bcx.ccx(), align);
return (size, align);
}
match t.sty {
// Don't use type_of::sizing_type_of because that expects t to be sized.
assert!(!t.is_simd(bcx.tcx()));
let repr = adt::represent_type(ccx, t);
- let sizing_type = adt::sizing_type_of(ccx, &*repr, true);
- let sized_size = C_uint(ccx, llsize_of_alloc(ccx, sizing_type));
- let sized_align = C_uint(ccx, llalign_of_min(ccx, sizing_type));
+ let sizing_type = adt::sizing_type_context_of(ccx, &*repr, true);
+ debug!("DST {} sizing_type: {}", t, sizing_type.to_string());
+ let sized_size = llsize_of_alloc(ccx, sizing_type.prefix());
+ let sized_align = llalign_of_min(ccx, sizing_type.prefix());
+ debug!("DST {} statically sized prefix size: {} align: {}",
+ t, sized_size, sized_align);
+ let sized_size = C_uint(ccx, sized_size);
+ let sized_align = C_uint(ccx, sized_align);
// Recurse to get the size of the dynamically sized field (must be
// the last field).
let field_ty = last_field.mt.ty;
let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
+ // #27023 FIXME: We should be adding any necessary padding
+ // to `sized_size` (to accommodate the `unsized_align`
+ // required of the unsized field that follows) before
+ // summing it with `sized_size`.
+
// Return the sum of sizes and max of aligns.
- let size = Add(bcx, sized_size, unsized_size, DebugLoc::None);
+ let mut size = Add(bcx, sized_size, unsized_size, DebugLoc::None);
+
+ // Issue #27023: If there is a drop flag, *now* we add 1
+ // to the size. (We can do this without adding any
+ // padding because drop flags do not have any alignment
+ // constraints.)
+ if sizing_type.needs_drop_flag() {
+ size = Add(bcx, size, C_uint(bcx.ccx(), 1_u64), DebugLoc::None);
+ }
+
let align = Select(bcx,
ICmp(bcx,
llvm::IntULT,
DebugLoc::None),
sized_align,
unsized_align);
+
+ // #27023 FIXME: We should be adding any necessary padding
+ // to `size` (to make it a multiple of `align`) before
+ // returning it.
+
(size, align)
}
ty::TyTrait(..) => {