@@ -12,7 +12,10 @@ use value::{PrimVal, Value};
12
12
pub enum Lvalue < ' tcx > {
13
13
/// An lvalue referring to a value allocated in the `Memory` system.
14
14
Ptr {
15
- ptr : Pointer ,
15
+ /// An lvalue may have an invalid (integral or undef) pointer,
16
+ /// since it might be turned back into a reference
17
+ /// before ever being dereferenced.
18
+ ptr : PrimVal ,
16
19
extra : LvalueExtra ,
17
20
} ,
18
21
@@ -61,22 +64,35 @@ pub struct Global<'tcx> {
61
64
}
62
65
63
66
impl < ' tcx > Lvalue < ' tcx > {
64
- pub fn from_ptr ( ptr : Pointer ) -> Self {
67
+ /// Produces an Lvalue that will error if attempted to be read from
68
+ pub fn undef ( ) -> Self {
69
+ Self :: from_primval_ptr ( PrimVal :: Undef )
70
+ }
71
+
72
+ fn from_primval_ptr ( ptr : PrimVal ) -> Self {
65
73
Lvalue :: Ptr { ptr, extra : LvalueExtra :: None }
66
74
}
67
75
68
- pub ( super ) fn to_ptr_and_extra ( self ) -> ( Pointer , LvalueExtra ) {
76
+ pub fn zst ( ) -> Self {
77
+ Self :: from_ptr ( Pointer :: zst_ptr ( ) )
78
+ }
79
+
80
+ pub fn from_ptr ( ptr : Pointer ) -> Self {
81
+ Self :: from_primval_ptr ( PrimVal :: Ptr ( ptr) )
82
+ }
83
+
84
+ pub ( super ) fn to_ptr_and_extra ( self ) -> ( PrimVal , LvalueExtra ) {
69
85
match self {
70
86
Lvalue :: Ptr { ptr, extra } => ( ptr, extra) ,
71
87
_ => bug ! ( "to_ptr_and_extra: expected Lvalue::Ptr, got {:?}" , self ) ,
72
88
73
89
}
74
90
}
75
91
76
- pub ( super ) fn to_ptr ( self ) -> Pointer {
92
+ pub ( super ) fn to_ptr ( self ) -> EvalResult < ' tcx , Pointer > {
77
93
let ( ptr, extra) = self . to_ptr_and_extra ( ) ;
78
94
assert_eq ! ( extra, LvalueExtra :: None ) ;
79
- ptr
95
+ ptr. to_ptr ( )
80
96
}
81
97
82
98
pub ( super ) fn elem_ty_and_len ( self , ty : Ty < ' tcx > ) -> ( Ty < ' tcx > , u64 ) {
@@ -127,7 +143,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
127
143
match lvalue {
128
144
Lvalue :: Ptr { ptr, extra } => {
129
145
assert_eq ! ( extra, LvalueExtra :: None ) ;
130
- Ok ( Value :: ByRef ( ptr) )
146
+ Ok ( Value :: ByRef ( ptr. to_ptr ( ) ? ) )
131
147
}
132
148
Lvalue :: Local { frame, local, field } => {
133
149
self . stack [ frame] . get_local ( local, field. map ( |( i, _) | i) )
@@ -167,7 +183,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
167
183
field_ty : Ty < ' tcx > ,
168
184
) -> EvalResult < ' tcx , Lvalue < ' tcx > > {
169
185
let base_layout = self . type_layout ( base_ty) ?;
170
-
171
186
use rustc:: ty:: layout:: Layout :: * ;
172
187
let ( offset, packed) = match * base_layout {
173
188
Univariant { ref variant, .. } => {
@@ -229,19 +244,24 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
229
244
Lvalue :: Local { frame, local, field } => match self . stack [ frame] . get_local ( local, field. map ( |( i, _) | i) ) ? {
230
245
Value :: ByRef ( ptr) => {
231
246
assert ! ( field. is_none( ) , "local can't be ByRef and have a field offset" ) ;
232
- ( ptr, LvalueExtra :: None )
247
+ ( PrimVal :: Ptr ( ptr) , LvalueExtra :: None )
233
248
} ,
234
249
Value :: ByVal ( PrimVal :: Undef ) => {
235
250
// FIXME: allocate in fewer cases
236
251
if self . ty_to_primval_kind ( base_ty) . is_ok ( ) {
237
252
return Ok ( base) ;
238
253
} else {
239
- ( self . force_allocation ( base) ?. to_ptr ( ) , LvalueExtra :: None )
254
+ ( PrimVal :: Ptr ( self . force_allocation ( base) ?. to_ptr ( ) ? ) , LvalueExtra :: None )
240
255
}
241
256
} ,
242
257
Value :: ByVal ( _) => {
243
- assert_eq ! ( field_index, 0 , "ByVal can only have 1 non zst field with offset 0" ) ;
244
- return Ok ( base) ;
258
+ if self . get_field_count ( base_ty) ? == 1 {
259
+ assert_eq ! ( field_index, 0 , "ByVal can only have 1 non zst field with offset 0" ) ;
260
+ return Ok ( base) ;
261
+ }
262
+ // this branch is taken when a union creates a large ByVal which is then
263
+ // accessed as a struct with multiple small fields
264
+ ( PrimVal :: Ptr ( self . force_allocation ( base) ?. to_ptr ( ) ?) , LvalueExtra :: None )
245
265
} ,
246
266
Value :: ByValPair ( _, _) => {
247
267
let field_count = self . get_field_count ( base_ty) ?;
@@ -264,7 +284,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
264
284
265
285
let offset = match base_extra {
266
286
LvalueExtra :: Vtable ( tab) => {
267
- let ( _, align) = self . size_and_align_of_dst ( base_ty, Value :: ByValPair ( PrimVal :: Ptr ( base_ptr) , PrimVal :: Ptr ( tab) ) ) ?;
287
+ let ( _, align) = self . size_and_align_of_dst ( base_ty, Value :: ByValPair ( base_ptr, PrimVal :: Ptr ( tab) ) ) ?;
268
288
offset. abi_align ( Align :: from_bytes ( align, align) . unwrap ( ) ) . bytes ( )
269
289
}
270
290
_ => offset. bytes ( ) ,
@@ -276,7 +296,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
276
296
277
297
if packed {
278
298
let size = self . type_size ( field_ty) ?. expect ( "packed struct must be sized" ) ;
279
- self . memory . mark_packed ( ptr, size) ;
299
+ self . memory . mark_packed ( ptr. to_ptr ( ) ? , size) ;
280
300
}
281
301
282
302
let extra = if self . type_is_sized ( field_ty) {
0 commit comments