@@ -45,6 +45,14 @@ pub enum OperandValue<V> {
45
45
/// as returned by [`LayoutTypeMethods::scalar_pair_element_backend_type`]
46
46
/// with `immediate: true`.
47
47
Pair ( V , V ) ,
48
+ /// A value taking no bytes, and which therefore needs no LLVM value at all.
49
+ ///
50
+ /// If you ever need a `V` to pass to something, get a fresh poison value
51
+ /// from [`ConstMethods::const_poison`].
52
+ ///
53
+ /// An `OperandValue` *must* be this variant for any type for which
54
+ /// `is_zst` on its `Layout` returns `true`.
55
+ ZeroSized ,
48
56
}
49
57
50
58
/// An `OperandRef` is an "SSA" reference to a Rust value, along with
@@ -71,15 +79,9 @@ impl<V: CodegenObject> fmt::Debug for OperandRef<'_, V> {
71
79
}
72
80
73
81
impl < ' a , ' tcx , V : CodegenObject > OperandRef < ' tcx , V > {
74
- pub fn new_zst < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
75
- bx : & mut Bx ,
76
- layout : TyAndLayout < ' tcx > ,
77
- ) -> OperandRef < ' tcx , V > {
82
+ pub fn zero_sized ( layout : TyAndLayout < ' tcx > ) -> OperandRef < ' tcx , V > {
78
83
assert ! ( layout. is_zst( ) ) ;
79
- OperandRef {
80
- val : OperandValue :: Immediate ( bx. const_poison ( bx. immediate_backend_type ( layout) ) ) ,
81
- layout,
82
- }
84
+ OperandRef { val : OperandValue :: ZeroSized , layout }
83
85
}
84
86
85
87
pub fn from_const < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
@@ -97,7 +99,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
97
99
let llval = bx. scalar_to_backend ( x, scalar, bx. immediate_backend_type ( layout) ) ;
98
100
OperandValue :: Immediate ( llval)
99
101
}
100
- ConstValue :: ZeroSized => return OperandRef :: new_zst ( bx , layout) ,
102
+ ConstValue :: ZeroSized => return OperandRef :: zero_sized ( layout) ,
101
103
ConstValue :: Slice { data, start, end } => {
102
104
let Abi :: ScalarPair ( a_scalar, _) = layout. abi else {
103
105
bug ! ( "from_const: invalid ScalarPair layout: {:#?}" , layout) ;
@@ -147,6 +149,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
147
149
OperandValue :: Immediate ( llptr) => ( llptr, None ) ,
148
150
OperandValue :: Pair ( llptr, llextra) => ( llptr, Some ( llextra) ) ,
149
151
OperandValue :: Ref ( ..) => bug ! ( "Deref of by-Ref operand {:?}" , self ) ,
152
+ OperandValue :: ZeroSized => bug ! ( "Deref of ZST operand {:?}" , self ) ,
150
153
} ;
151
154
let layout = cx. layout_of ( projected_ty) ;
152
155
PlaceRef { llval : llptr, llextra, layout, align : layout. align . abi }
@@ -204,9 +207,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
204
207
205
208
let mut val = match ( self . val , self . layout . abi ) {
206
209
// If the field is ZST, it has no data.
207
- _ if field. is_zst ( ) => {
208
- return OperandRef :: new_zst ( bx, field) ;
209
- }
210
+ _ if field. is_zst ( ) => OperandValue :: ZeroSized ,
210
211
211
212
// Newtype of a scalar, scalar pair or vector.
212
213
( OperandValue :: Immediate ( _) | OperandValue :: Pair ( ..) , _)
@@ -237,6 +238,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
237
238
} ;
238
239
239
240
match ( & mut val, field. abi ) {
241
+ ( OperandValue :: ZeroSized , _) => { }
240
242
(
241
243
OperandValue :: Immediate ( llval) ,
242
244
Abi :: Scalar ( _) | Abi :: ScalarPair ( ..) | Abi :: Vector { .. } ,
@@ -290,16 +292,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
290
292
impl < ' a , ' tcx , V : CodegenObject > OperandValue < V > {
291
293
/// Returns an `OperandValue` that's generally UB to use in any way.
292
294
///
293
- /// Depending on the `layout`, returns an `Immediate` or `Pair` containing
294
- /// poison value(s), or a `Ref` containing a poison pointer.
295
+ /// Depending on the `layout`, returns `ZeroSized` for ZSTs, an `Immediate` or
296
+ /// `Pair` containing poison value(s), or a `Ref` containing a poison pointer.
295
297
///
296
298
/// Supports sized types only.
297
299
pub fn poison < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
298
300
bx : & mut Bx ,
299
301
layout : TyAndLayout < ' tcx > ,
300
302
) -> OperandValue < V > {
301
303
assert ! ( layout. is_sized( ) ) ;
302
- if bx. cx ( ) . is_backend_immediate ( layout) {
304
+ if layout. is_zst ( ) {
305
+ OperandValue :: ZeroSized
306
+ } else if bx. cx ( ) . is_backend_immediate ( layout) {
303
307
let ibty = bx. cx ( ) . immediate_backend_type ( layout) ;
304
308
OperandValue :: Immediate ( bx. const_poison ( ibty) )
305
309
} else if bx. cx ( ) . is_backend_scalar_pair ( layout) {
@@ -352,12 +356,11 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
352
356
flags : MemFlags ,
353
357
) {
354
358
debug ! ( "OperandRef::store: operand={:?}, dest={:?}" , self , dest) ;
355
- // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
356
- // value is through `undef`, and store itself is useless.
357
- if dest. layout . is_zst ( ) {
358
- return ;
359
- }
360
359
match self {
360
+ OperandValue :: ZeroSized => {
361
+ // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
362
+ // value is through `undef`/`poison`, and the store itself is useless.
363
+ }
361
364
OperandValue :: Ref ( r, None , source_align) => {
362
365
if flags. contains ( MemFlags :: NONTEMPORAL ) {
363
366
// HACK(nox): This is inefficient but there is no nontemporal memcpy.
@@ -458,7 +461,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
458
461
// checks in `codegen_consume` and `extract_field`.
459
462
let elem = o. layout . field ( bx. cx ( ) , 0 ) ;
460
463
if elem. is_zst ( ) {
461
- o = OperandRef :: new_zst ( bx , elem) ;
464
+ o = OperandRef :: zero_sized ( elem) ;
462
465
} else {
463
466
return None ;
464
467
}
@@ -492,7 +495,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
492
495
493
496
// ZSTs don't require any actual memory access.
494
497
if layout. is_zst ( ) {
495
- return OperandRef :: new_zst ( bx , layout) ;
498
+ return OperandRef :: zero_sized ( layout) ;
496
499
}
497
500
498
501
if let Some ( o) = self . maybe_codegen_consume_direct ( bx, place_ref) {
0 commit comments