43
43
44
44
pub use self :: Repr :: * ;
45
45
46
+ use std;
46
47
use std:: rc:: Rc ;
47
48
48
49
use llvm:: { ValueRef , True , IntEQ , IntNE } ;
@@ -60,6 +61,7 @@ use trans::cleanup::CleanupMethods;
60
61
use trans:: common:: * ;
61
62
use trans:: datum;
62
63
use trans:: debuginfo:: DebugLoc ;
64
+ use trans:: glue;
63
65
use trans:: machine;
64
66
use trans:: monomorphize;
65
67
use trans:: type_:: Type ;
@@ -153,6 +155,32 @@ pub struct Struct<'tcx> {
153
155
pub fields : Vec < Ty < ' tcx > > ,
154
156
}
155
157
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
+
156
184
/// Convenience for `represent_type`. There should probably be more or
157
185
/// these, for places in trans where the `Ty` isn't directly
158
186
/// available.
@@ -247,7 +275,11 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
247
275
monomorphize:: field_ty ( cx. tcx ( ) , substs, field)
248
276
} ) . collect :: < Vec < _ > > ( ) ;
249
277
let packed = cx. tcx ( ) . lookup_packed ( def. did ) ;
250
- let dtor = def. dtor_kind ( ) . has_drop_flag ( ) ;
278
+ // FIXME(16758) don't add a drop flag to unsized structs, as it
279
+ // won't actually be in the location we say it is because it'll be after
280
+ // the unsized field. Several other pieces of code assume that the unsized
281
+ // field is definitely the last one.
282
+ let dtor = def. dtor_kind ( ) . has_drop_flag ( ) && type_is_sized ( cx. tcx ( ) , t) ;
251
283
if dtor {
252
284
ftys. push ( cx. tcx ( ) . dtor_type ( ) ) ;
253
285
}
@@ -976,7 +1008,7 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
976
1008
}
977
1009
General ( ity, ref cases, dtor) => {
978
1010
if dtor_active ( dtor) {
979
- let ptr = trans_field_ptr ( bcx, r, val, discr,
1011
+ let ptr = trans_field_ptr ( bcx, r, MaybeSizedValue :: sized ( val) , discr,
980
1012
cases[ discr as usize ] . fields . len ( ) - 2 ) ;
981
1013
Store ( bcx, C_u8 ( bcx. ccx ( ) , DTOR_NEEDED ) , ptr) ;
982
1014
}
@@ -1037,7 +1069,7 @@ pub fn num_args(r: &Repr, discr: Disr) -> usize {
1037
1069
1038
1070
/// Access a field, at a point when the value's case is known.
1039
1071
pub fn trans_field_ptr < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > , r : & Repr < ' tcx > ,
1040
- val : ValueRef , discr : Disr , ix : usize ) -> ValueRef {
1072
+ val : MaybeSizedValue , discr : Disr , ix : usize ) -> ValueRef {
1041
1073
// Note: if this ever needs to generate conditionals (e.g., if we
1042
1074
// decide to do some kind of cdr-coding-like non-unique repr
1043
1075
// someday), it will need to return a possibly-new bcx as well.
@@ -1060,13 +1092,13 @@ pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
1060
1092
assert_eq ! ( machine:: llsize_of_alloc( bcx. ccx( ) , ty) , 0 ) ;
1061
1093
// The contents of memory at this pointer can't matter, but use
1062
1094
// the value that's "reasonable" in case of pointer comparison.
1063
- PointerCast ( bcx, val, ty. ptr_to ( ) )
1095
+ PointerCast ( bcx, val. value , ty. ptr_to ( ) )
1064
1096
}
1065
1097
RawNullablePointer { nndiscr, nnty, .. } => {
1066
1098
assert_eq ! ( ix, 0 ) ;
1067
1099
assert_eq ! ( discr, nndiscr) ;
1068
1100
let ty = type_of:: type_of ( bcx. ccx ( ) , nnty) ;
1069
- PointerCast ( bcx, val, ty. ptr_to ( ) )
1101
+ PointerCast ( bcx, val. value , ty. ptr_to ( ) )
1070
1102
}
1071
1103
StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
1072
1104
assert_eq ! ( discr, nndiscr) ;
@@ -1075,18 +1107,100 @@ pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
1075
1107
}
1076
1108
}
1077
1109
1078
- pub fn struct_field_ptr < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > , st : & Struct < ' tcx > , val : ValueRef ,
1110
+ pub fn struct_field_ptr < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > , st : & Struct < ' tcx > , val : MaybeSizedValue ,
1079
1111
ix : usize , needs_cast : bool ) -> ValueRef {
1080
- let val = if needs_cast {
1081
- let ccx = bcx. ccx ( ) ;
1082
- let fields = st. fields . iter ( ) . map ( |& ty| type_of:: type_of ( ccx, ty) ) . collect :: < Vec < _ > > ( ) ;
1112
+ let ccx = bcx. ccx ( ) ;
1113
+ let ptr_val = if needs_cast {
1114
+ let fields = st. fields . iter ( ) . map ( |& ty| {
1115
+ type_of:: in_memory_type_of ( ccx, ty)
1116
+ } ) . collect :: < Vec < _ > > ( ) ;
1083
1117
let real_ty = Type :: struct_ ( ccx, & fields[ ..] , st. packed ) ;
1084
- PointerCast ( bcx, val, real_ty. ptr_to ( ) )
1118
+ PointerCast ( bcx, val. value , real_ty. ptr_to ( ) )
1085
1119
} else {
1086
- val
1120
+ val. value
1087
1121
} ;
1088
1122
1089
- StructGEP ( bcx, val, ix)
1123
+ let fty = st. fields [ ix] ;
1124
+ // Simple case - we can just GEP the field
1125
+ // * First field - Always aligned properly
1126
+ // * Packed struct - There is no alignment padding
1127
+ // * Field is sized - pointer is properly aligned already
1128
+ if ix == 0 || st. packed || type_is_sized ( bcx. tcx ( ) , fty) {
1129
+ return StructGEP ( bcx, ptr_val, ix) ;
1130
+ }
1131
+
1132
+ // If the type of the last field is [T] or str, then we don't need to do
1133
+ // any adjusments
1134
+ match fty. sty {
1135
+ ty:: TySlice ( ..) | ty:: TyStr => {
1136
+ return StructGEP ( bcx, ptr_val, ix) ;
1137
+ }
1138
+ _ => ( )
1139
+ }
1140
+
1141
+ // There's no metadata available, log the case and just do the GEP.
1142
+ if !val. has_meta ( ) {
1143
+ debug ! ( "Unsized field `{}`, of `{}` has no metadata for adjustment" ,
1144
+ ix,
1145
+ bcx. val_to_string( ptr_val) ) ;
1146
+ return StructGEP ( bcx, ptr_val, ix) ;
1147
+ }
1148
+
1149
+ let dbloc = DebugLoc :: None ;
1150
+
1151
+ // We need to get the pointer manually now.
1152
+ // We do this by casting to a *i8, then offsetting it by the appropriate amount.
1153
+ // We do this instead of, say, simply adjusting the pointer from the result of a GEP
1154
+ // because the field may have an arbitrary alignment in the LLVM representation
1155
+ // anyway.
1156
+ //
1157
+ // To demonstrate:
1158
+ // struct Foo<T: ?Sized> {
1159
+ // x: u16,
1160
+ // y: T
1161
+ // }
1162
+ //
1163
+ // The type Foo<Foo<Trait>> is represented in LLVM as { u16, { u16, u8 }}, meaning that
1164
+ // the `y` field has 16-bit alignment.
1165
+
1166
+ let meta = val. meta ;
1167
+
1168
+ // Calculate the unaligned offset of the the unsized field.
1169
+ let mut offset = 0 ;
1170
+ for & ty in & st. fields [ 0 ..ix] {
1171
+ let llty = type_of:: sizing_type_of ( ccx, ty) ;
1172
+ let type_align = type_of:: align_of ( ccx, ty) ;
1173
+ offset = roundup ( offset, type_align) ;
1174
+ offset += machine:: llsize_of_alloc ( ccx, llty) ;
1175
+ }
1176
+ let unaligned_offset = C_uint ( bcx. ccx ( ) , offset) ;
1177
+
1178
+ // Get the alignment of the field
1179
+ let ( _, align) = glue:: size_and_align_of_dst ( bcx, fty, meta) ;
1180
+
1181
+ // Bump the unaligned offset up to the appropriate alignment using the
1182
+ // following expression:
1183
+ //
1184
+ // (unaligned offset + (align - 1)) & -align
1185
+
1186
+ // Calculate offset
1187
+ let align_sub_1 = Sub ( bcx, align, C_uint ( bcx. ccx ( ) , 1u64 ) , dbloc) ;
1188
+ let offset = And ( bcx,
1189
+ Add ( bcx, unaligned_offset, align_sub_1, dbloc) ,
1190
+ Neg ( bcx, align, dbloc) ,
1191
+ dbloc) ;
1192
+
1193
+ debug ! ( "struct_field_ptr: DST field offset: {}" ,
1194
+ bcx. val_to_string( offset) ) ;
1195
+
1196
+ // Cast and adjust pointer
1197
+ let byte_ptr = PointerCast ( bcx, ptr_val, Type :: i8p ( bcx. ccx ( ) ) ) ;
1198
+ let byte_ptr = GEP ( bcx, byte_ptr, & [ offset] ) ;
1199
+
1200
+ // Finally, cast back to the type expected
1201
+ let ll_fty = type_of:: in_memory_type_of ( bcx. ccx ( ) , fty) ;
1202
+ debug ! ( "struct_field_ptr: Field type is {}" , ll_fty. to_string( ) ) ;
1203
+ PointerCast ( bcx, byte_ptr, ll_fty. ptr_to ( ) )
1090
1204
}
1091
1205
1092
1206
pub fn fold_variants < ' blk , ' tcx , F > ( bcx : Block < ' blk , ' tcx > ,
@@ -1168,7 +1282,8 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
1168
1282
cleanup:: CustomScope ( custom_cleanup_scope) , ( ) , |_, bcx, _| bcx
1169
1283
) ) ;
1170
1284
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 ) ;
1285
+ let ptr = struct_field_ptr ( variant_cx, st, MaybeSizedValue :: sized ( value) ,
1286
+ ( st. fields . len ( ) - 1 ) , false ) ;
1172
1287
datum:: Datum :: new ( ptr, ptr_ty, datum:: Lvalue :: new ( "adt::trans_drop_flag_ptr" ) )
1173
1288
. store_to ( variant_cx, scratch. val )
1174
1289
} ) ;
0 commit comments