4343
4444pub use self :: Repr :: * ;
4545
46+ use std;
4647use std:: rc:: Rc ;
4748
4849use llvm:: { ValueRef , True , IntEQ , IntNE } ;
@@ -60,6 +61,7 @@ use trans::cleanup::CleanupMethods;
6061use trans:: common:: * ;
6162use trans:: datum;
6263use trans:: debuginfo:: DebugLoc ;
64+ use trans:: glue;
6365use trans:: machine;
6466use trans:: monomorphize;
6567use trans:: type_:: Type ;
@@ -153,6 +155,32 @@ pub struct Struct<'tcx> {
153155 pub fields : Vec < Ty < ' tcx > > ,
154156}
155157
158+ #[ derive( Copy , Clone ) ]
159+ pub struct MaybeSizedValue {
160+ pub value : ValueRef ,
161+ pub meta : ValueRef ,
162+ }
163+
164+ impl MaybeSizedValue {
165+ pub fn sized ( value : ValueRef ) -> MaybeSizedValue {
166+ MaybeSizedValue {
167+ value : value,
168+ meta : std:: ptr:: null_mut ( )
169+ }
170+ }
171+
172+ pub fn unsized_ ( value : ValueRef , meta : ValueRef ) -> MaybeSizedValue {
173+ MaybeSizedValue {
174+ value : value,
175+ meta : meta
176+ }
177+ }
178+
179+ pub fn has_meta ( & self ) -> bool {
180+ !self . meta . is_null ( )
181+ }
182+ }
183+
156184/// Convenience for `represent_type`. There should probably be more or
157185/// these, for places in trans where the `Ty` isn't directly
158186/// available.
@@ -976,7 +1004,7 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
9761004 }
9771005 General ( ity, ref cases, dtor) => {
9781006 if dtor_active ( dtor) {
979- let ptr = trans_field_ptr ( bcx, r, val, discr,
1007+ let ptr = trans_field_ptr ( bcx, r, MaybeSizedValue :: sized ( val) , discr,
9801008 cases[ discr as usize ] . fields . len ( ) - 2 ) ;
9811009 Store ( bcx, C_u8 ( bcx. ccx ( ) , DTOR_NEEDED ) , ptr) ;
9821010 }
@@ -1037,7 +1065,7 @@ pub fn num_args(r: &Repr, discr: Disr) -> usize {
10371065
10381066/// Access a field, at a point when the value's case is known.
10391067pub fn trans_field_ptr < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > , r : & Repr < ' tcx > ,
1040- val : ValueRef , discr : Disr , ix : usize ) -> ValueRef {
1068+ val : MaybeSizedValue , discr : Disr , ix : usize ) -> ValueRef {
10411069 // Note: if this ever needs to generate conditionals (e.g., if we
10421070 // decide to do some kind of cdr-coding-like non-unique repr
10431071 // someday), it will need to return a possibly-new bcx as well.
@@ -1060,13 +1088,13 @@ pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
10601088 assert_eq ! ( machine:: llsize_of_alloc( bcx. ccx( ) , ty) , 0 ) ;
10611089 // The contents of memory at this pointer can't matter, but use
10621090 // the value that's "reasonable" in case of pointer comparison.
1063- PointerCast ( bcx, val, ty. ptr_to ( ) )
1091+ PointerCast ( bcx, val. value , ty. ptr_to ( ) )
10641092 }
10651093 RawNullablePointer { nndiscr, nnty, .. } => {
10661094 assert_eq ! ( ix, 0 ) ;
10671095 assert_eq ! ( discr, nndiscr) ;
10681096 let ty = type_of:: type_of ( bcx. ccx ( ) , nnty) ;
1069- PointerCast ( bcx, val, ty. ptr_to ( ) )
1097+ PointerCast ( bcx, val. value , ty. ptr_to ( ) )
10701098 }
10711099 StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
10721100 assert_eq ! ( discr, nndiscr) ;
@@ -1075,18 +1103,94 @@ pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
10751103 }
10761104}
10771105
1078- pub fn struct_field_ptr < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > , st : & Struct < ' tcx > , val : ValueRef ,
1106+ pub fn struct_field_ptr < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > , st : & Struct < ' tcx > , val : MaybeSizedValue ,
10791107 ix : usize , needs_cast : bool ) -> ValueRef {
1080- let val = if needs_cast {
1108+ let ptr_val = if needs_cast {
10811109 let ccx = bcx. ccx ( ) ;
1082- let fields = st. fields . iter ( ) . map ( |& ty| type_of:: type_of ( ccx, ty) ) . collect :: < Vec < _ > > ( ) ;
1110+ let fields = st. fields . iter ( ) . map ( |& ty| {
1111+ type_of:: in_memory_type_of ( ccx, ty)
1112+ } ) . collect :: < Vec < _ > > ( ) ;
10831113 let real_ty = Type :: struct_ ( ccx, & fields[ ..] , st. packed ) ;
1084- PointerCast ( bcx, val, real_ty. ptr_to ( ) )
1114+ PointerCast ( bcx, val. value , real_ty. ptr_to ( ) )
10851115 } else {
1086- val
1116+ val. value
10871117 } ;
10881118
1089- StructGEP ( bcx, val, ix)
1119+ let fty = st. fields [ ix] ;
1120+ // Simple case - we can just GEP the field
1121+ // * First field - Always aligned properly
1122+ // * Packed struct - There is no alignment padding
1123+ // * Field is sized - pointer is properly aligned already
1124+ if ix == 0 || st. packed || type_is_sized ( bcx. tcx ( ) , fty) {
1125+ return StructGEP ( bcx, ptr_val, ix) ;
1126+ }
1127+
1128+ // If the type of the last field is [T] or str, then we don't need to do
1129+ // any adjusments
1130+ match fty. sty {
1131+ ty:: TySlice ( ..) | ty:: TyStr => {
1132+ return StructGEP ( bcx, ptr_val, ix) ;
1133+ }
1134+ _ => ( )
1135+ }
1136+
1137+ // There's no metadata available, log the case and just do the GEP.
1138+ if !val. has_meta ( ) {
1139+ debug ! ( "Unsized field `{}`, of `{}` has no metadata for adjustment" ,
1140+ ix,
1141+ bcx. val_to_string( ptr_val) ) ;
1142+ return StructGEP ( bcx, ptr_val, ix) ;
1143+ }
1144+
1145+ let dbloc = DebugLoc :: None ;
1146+
1147+ // We need to get the pointer manually now.
1148+ // We do this by casting to a *i8, then offsetting it by the appropriate amount.
1149+ // We do this instead of, say, simply adjusting the pointer from the result of a GEP
1150+ // because the the field may have an arbitrary alignment in the LLVM representation
1151+ // anyway.
1152+ //
1153+ // To demonstrate:
1154+ // struct Foo<T: ?Sized> {
1155+ // x: u16,
1156+ // y: T
1157+ // }
1158+ //
1159+ // The type Foo<Foo<Trait>> is represented in LLVM as { u16, { u16, u8 }}, meaning that
1160+ // the `y` field has 16-bit alignment.
1161+
1162+ let meta = val. meta ;
1163+
1164+ // st.size is the size of the sized portion of the struct. So the position
1165+ // exactly after it is the offset for unaligned data.
1166+ let unaligned_offset = C_uint ( bcx. ccx ( ) , st. size ) ;
1167+
1168+ // Get the alignment of the field
1169+ let ( _, align) = glue:: size_and_align_of_dst ( bcx, fty, meta) ;
1170+
1171+ // Bump the unaligned offset up to the appropriate alignment using the
1172+ // following expression:
1173+ //
1174+ // (unaligned offset + (align - 1)) & -align
1175+
1176+ // Calculate offset
1177+ let align_sub_1 = Sub ( bcx, align, C_uint ( bcx. ccx ( ) , 1u64 ) , dbloc) ;
1178+ let offset = And ( bcx,
1179+ Add ( bcx, unaligned_offset, align_sub_1, dbloc) ,
1180+ Neg ( bcx, align, dbloc) ,
1181+ dbloc) ;
1182+
1183+ debug ! ( "struct_field_ptr: DST field offset: {}" ,
1184+ bcx. val_to_string( offset) ) ;
1185+
1186+ // Cast and adjust pointer
1187+ let byte_ptr = PointerCast ( bcx, ptr_val, Type :: i8p ( bcx. ccx ( ) ) ) ;
1188+ let byte_ptr = GEP ( bcx, byte_ptr, & [ offset] ) ;
1189+
1190+ // Finally, cast back to the type expected
1191+ let ll_fty = type_of:: in_memory_type_of ( bcx. ccx ( ) , fty) ;
1192+ debug ! ( "struct_field_ptr: Field type is {}" , ll_fty. to_string( ) ) ;
1193+ PointerCast ( bcx, byte_ptr, ll_fty. ptr_to ( ) )
10901194}
10911195
10921196pub fn fold_variants < ' blk , ' tcx , F > ( bcx : Block < ' blk , ' tcx > ,
@@ -1168,7 +1272,8 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
11681272 cleanup:: CustomScope ( custom_cleanup_scope) , ( ) , |_, bcx, _| bcx
11691273 ) ) ;
11701274 bcx = fold_variants ( bcx, r, val, |variant_cx, st, value| {
1171- let ptr = struct_field_ptr ( variant_cx, st, value, ( st. fields . len ( ) - 1 ) , false ) ;
1275+ let ptr = struct_field_ptr ( variant_cx, st, MaybeSizedValue :: sized ( value) ,
1276+ ( st. fields . len ( ) - 1 ) , false ) ;
11721277 datum:: Datum :: new ( ptr, ptr_ty, datum:: Lvalue :: new ( "adt::trans_drop_flag_ptr" ) )
11731278 . store_to ( variant_cx, scratch. val )
11741279 } ) ;
0 commit comments