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.
@@ -976,7 +1004,7 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
976
1004
}
977
1005
General ( ity, ref cases, dtor) => {
978
1006
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,
980
1008
cases[ discr as usize ] . fields . len ( ) - 2 ) ;
981
1009
Store ( bcx, C_u8 ( bcx. ccx ( ) , DTOR_NEEDED ) , ptr) ;
982
1010
}
@@ -1037,7 +1065,7 @@ pub fn num_args(r: &Repr, discr: Disr) -> usize {
1037
1065
1038
1066
/// Access a field, at a point when the value's case is known.
1039
1067
pub 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 {
1041
1069
// Note: if this ever needs to generate conditionals (e.g., if we
1042
1070
// decide to do some kind of cdr-coding-like non-unique repr
1043
1071
// 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>,
1060
1088
assert_eq ! ( machine:: llsize_of_alloc( bcx. ccx( ) , ty) , 0 ) ;
1061
1089
// The contents of memory at this pointer can't matter, but use
1062
1090
// 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 ( ) )
1064
1092
}
1065
1093
RawNullablePointer { nndiscr, nnty, .. } => {
1066
1094
assert_eq ! ( ix, 0 ) ;
1067
1095
assert_eq ! ( discr, nndiscr) ;
1068
1096
let ty = type_of:: type_of ( bcx. ccx ( ) , nnty) ;
1069
- PointerCast ( bcx, val, ty. ptr_to ( ) )
1097
+ PointerCast ( bcx, val. value , ty. ptr_to ( ) )
1070
1098
}
1071
1099
StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
1072
1100
assert_eq ! ( discr, nndiscr) ;
@@ -1075,18 +1103,94 @@ pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
1075
1103
}
1076
1104
}
1077
1105
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 ,
1079
1107
ix : usize , needs_cast : bool ) -> ValueRef {
1080
- let val = if needs_cast {
1108
+ let ptr_val = if needs_cast {
1081
1109
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 < _ > > ( ) ;
1083
1113
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 ( ) )
1085
1115
} else {
1086
- val
1116
+ val. value
1087
1117
} ;
1088
1118
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 ( ) )
1090
1194
}
1091
1195
1092
1196
pub 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>,
1168
1272
cleanup:: CustomScope ( custom_cleanup_scope) , ( ) , |_, bcx, _| bcx
1169
1273
) ) ;
1170
1274
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 ) ;
1172
1277
datum:: Datum :: new ( ptr, ptr_ty, datum:: Lvalue :: new ( "adt::trans_drop_flag_ptr" ) )
1173
1278
. store_to ( variant_cx, scratch. val )
1174
1279
} ) ;
0 commit comments