Skip to content

Commit a422b42

Browse files
committed
don't allow ZST in ScalarInt
There are several indications that we should not ZST as a ScalarInt: - We had two ways to have ZST valtrees, either an empty `Branch` or a `Leaf` with a ZST in it. `ValTree::zst()` used the former, but the latter could possibly arise as well. - Likewise, the interpreter had `Immediate::Uninit` and `Immediate::Scalar(Scalar::ZST)`. - LLVM codegen already had to special-case ZST ScalarInt. So instead add new ZST variants to those types that did not have other variants which could be used for this purpose.
1 parent c4693bc commit a422b42

File tree

21 files changed

+78
-61
lines changed

21 files changed

+78
-61
lines changed

compiler/rustc_codegen_llvm/src/common.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use rustc_codegen_ssa::traits::*;
1313
use rustc_middle::bug;
1414
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
1515
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
16-
use rustc_middle::ty::ScalarInt;
1716
use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer, Size};
1817

1918
use libc::{c_char, c_uint};
@@ -223,13 +222,13 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
223222
})
224223
}
225224

225+
fn zst_to_backend(&self, _llty: &'ll Type) -> &'ll Value {
226+
self.const_undef(self.type_ix(0))
227+
}
228+
226229
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value {
227230
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
228231
match cv {
229-
Scalar::Int(ScalarInt::ZST) => {
230-
assert_eq!(0, layout.size(self).bytes());
231-
self.const_undef(self.type_ix(0))
232-
}
233232
Scalar::Int(int) => {
234233
let data = int.assert_bits(layout.size(self));
235234
let llval = self.const_uint_big(self.type_ix(bitsize), data);

compiler/rustc_codegen_ssa/src/mir/operand.rs

+4
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
8484
let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout));
8585
OperandValue::Immediate(llval)
8686
}
87+
ConstValue::ZST => {
88+
let llval = bx.zst_to_backend(bx.immediate_backend_type(layout));
89+
OperandValue::Immediate(llval)
90+
}
8791
ConstValue::Slice { data, start, end } => {
8892
let Abi::ScalarPair(a_scalar, _) = layout.abi else {
8993
bug!("from_const: invalid ScalarPair layout: {:#?}", layout);

compiler/rustc_codegen_ssa/src/traits/consts.rs

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
2929
fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value;
3030

3131
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
32+
fn zst_to_backend(&self, llty: Self::Type) -> Self::Value;
3233
fn from_const_alloc(
3334
&self,
3435
layout: TyAndLayout<'tcx>,

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr};
22
use crate::interpret::eval_nullary_intrinsic;
33
use crate::interpret::{
44
intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId,
5-
Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar,
5+
Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
66
ScalarMaybeUninit, StackPopCleanup,
77
};
88

@@ -157,7 +157,7 @@ pub(super) fn op_to_const<'tcx>(
157157
"this MPlaceTy must come from a validated constant, thus we can assume the \
158158
alignment is correct",
159159
);
160-
ConstValue::Scalar(Scalar::ZST)
160+
ConstValue::ZST
161161
}
162162
}
163163
};

compiler/rustc_const_eval/src/const_eval/valtrees.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ pub fn valtree_to_const_value<'tcx>(
272272
match ty.kind() {
273273
ty::FnDef(..) => {
274274
assert!(valtree.unwrap_branch().is_empty());
275-
ConstValue::Scalar(Scalar::ZST)
275+
ConstValue::ZST
276276
}
277277
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => match valtree {
278278
ty::ValTree::Leaf(scalar_int) => ConstValue::Scalar(Scalar::Int(scalar_int)),
@@ -344,11 +344,7 @@ fn valtree_into_mplace<'tcx>(
344344

345345
match ty.kind() {
346346
ty::FnDef(_, _) => {
347-
ecx.write_immediate(
348-
Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::ZST)),
349-
&place.into(),
350-
)
351-
.unwrap();
347+
ecx.write_immediate(Immediate::Uninit, &place.into()).unwrap();
352348
}
353349
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
354350
let scalar_int = valtree.unwrap_leaf();

compiler/rustc_const_eval/src/interpret/operand.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
297297

298298
let Some(alloc) = self.get_place_alloc(mplace)? else {
299299
return Ok(Some(ImmTy {
300-
// zero-sized type
301-
imm: Scalar::ZST.into(),
300+
// zero-sized type can be left uninit
301+
imm: Immediate::Uninit,
302302
layout: mplace.layout,
303303
}));
304304
};
@@ -441,8 +441,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
441441
// This makes several assumptions about what layouts we will encounter; we match what
442442
// codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`).
443443
let field_val: Immediate<_> = match (*base, base.layout.abi) {
444-
// the field contains no information
445-
_ if field_layout.is_zst() => Scalar::ZST.into(),
444+
// the field contains no information, can be left uninit
445+
_ if field_layout.is_zst() => Immediate::Uninit,
446446
// the field covers the entire type
447447
_ if field_layout.size == base.layout.size => {
448448
assert!(match (base.layout.abi, field_layout.abi) {
@@ -553,8 +553,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
553553
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
554554
let layout = self.layout_of_local(frame, local, layout)?;
555555
let op = if layout.is_zst() {
556-
// Do not read from ZST, they might not be initialized
557-
Operand::Immediate(Scalar::ZST.into())
556+
// Bypass `access_local` (helps in ConstProp)
557+
Operand::Immediate(Immediate::Uninit)
558558
} else {
559559
*M::access_local(frame, local)?
560560
};
@@ -709,6 +709,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
709709
Operand::Indirect(MemPlace::from_ptr(ptr.into()))
710710
}
711711
ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()),
712+
ConstValue::ZST => Operand::Immediate(Immediate::Uninit),
712713
ConstValue::Slice { data, start, end } => {
713714
// We rely on mutability being set correctly in `data` to prevent writes
714715
// where none should happen.

compiler/rustc_middle/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#![feature(drain_filter)]
6060
#![feature(intra_doc_pointers)]
6161
#![feature(yeet_expr)]
62+
#![feature(const_option)]
6263
#![recursion_limit = "512"]
6364
#![allow(rustc::potential_query_instability)]
6465

compiler/rustc_middle/src/mir/interpret/value.rs

+6-8
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ pub struct ConstAlloc<'tcx> {
2929
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
3030
#[derive(HashStable)]
3131
pub enum ConstValue<'tcx> {
32-
/// Used only for types with `layout::abi::Scalar` ABI and ZSTs.
32+
/// Used only for types with `layout::abi::Scalar` ABI.
3333
///
3434
/// Not using the enum `Value` to encode that this must not be `Uninit`.
3535
Scalar(Scalar),
3636

37+
/// Only used for ZSTs.
38+
ZST,
39+
3740
/// Used only for `&[u8]` and `&str`
3841
Slice { data: ConstAllocation<'tcx>, start: usize, end: usize },
3942

@@ -55,6 +58,7 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> {
5558
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ConstValue<'tcx>> {
5659
Some(match self {
5760
ConstValue::Scalar(s) => ConstValue::Scalar(s),
61+
ConstValue::ZST => ConstValue::ZST,
5862
ConstValue::Slice { data, start, end } => {
5963
ConstValue::Slice { data: tcx.lift(data)?, start, end }
6064
}
@@ -69,7 +73,7 @@ impl<'tcx> ConstValue<'tcx> {
6973
#[inline]
7074
pub fn try_to_scalar(&self) -> Option<Scalar<AllocId>> {
7175
match *self {
72-
ConstValue::ByRef { .. } | ConstValue::Slice { .. } => None,
76+
ConstValue::ByRef { .. } | ConstValue::Slice { .. } | ConstValue::ZST => None,
7377
ConstValue::Scalar(val) => Some(val),
7478
}
7579
}
@@ -111,10 +115,6 @@ impl<'tcx> ConstValue<'tcx> {
111115
pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self {
112116
ConstValue::Scalar(Scalar::from_machine_usize(i, cx))
113117
}
114-
115-
pub fn zst() -> Self {
116-
Self::Scalar(Scalar::ZST)
117-
}
118118
}
119119

120120
/// A `Scalar` represents an immediate, primitive value existing outside of a
@@ -194,8 +194,6 @@ impl<Tag> From<ScalarInt> for Scalar<Tag> {
194194
}
195195

196196
impl<Tag> Scalar<Tag> {
197-
pub const ZST: Self = Scalar::Int(ScalarInt::ZST);
198-
199197
#[inline(always)]
200198
pub fn from_pointer(ptr: Pointer<Tag>, cx: &impl HasDataLayout) -> Self {
201199
Scalar::Ptr(ptr, u8::try_from(cx.pointer_size().bytes()).unwrap())

compiler/rustc_middle/src/mir/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1711,7 +1711,7 @@ impl<'tcx> Operand<'tcx> {
17111711
Operand::Constant(Box::new(Constant {
17121712
span,
17131713
user_ty: None,
1714-
literal: ConstantKind::Val(ConstValue::zst(), ty),
1714+
literal: ConstantKind::Val(ConstValue::ZST, ty),
17151715
}))
17161716
}
17171717

@@ -2196,7 +2196,7 @@ impl<'tcx> ConstantKind<'tcx> {
21962196

21972197
#[inline]
21982198
pub fn zero_sized(ty: Ty<'tcx>) -> Self {
2199-
let cv = ConstValue::Scalar(Scalar::ZST);
2199+
let cv = ConstValue::ZST;
22002200
Self::Val(cv, ty)
22012201
}
22022202

compiler/rustc_middle/src/mir/pretty.rs

+2
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
449449
}
450450

451451
let fmt_val = |val: &ConstValue<'tcx>| match val {
452+
ConstValue::ZST => format!("ZST"),
452453
ConstValue::Scalar(s) => format!("Scalar({:?})", s),
453454
ConstValue::Slice { .. } => format!("Slice(..)"),
454455
ConstValue::ByRef { .. } => format!("ByRef(..)"),
@@ -679,6 +680,7 @@ pub fn write_allocations<'tcx>(
679680
ConstValue::Scalar(interpret::Scalar::Int { .. }) => {
680681
Either::Left(Either::Right(std::iter::empty()))
681682
}
683+
ConstValue::ZST => Either::Left(Either::Right(std::iter::empty())),
682684
ConstValue::ByRef { alloc, .. } | ConstValue::Slice { data: alloc, .. } => {
683685
Either::Right(alloc_ids_from_alloc(alloc))
684686
}

compiler/rustc_middle/src/thir.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,10 @@ pub enum ExprKind<'tcx> {
419419
lit: ty::ScalarInt,
420420
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
421421
},
422+
/// A literal of a ZST type.
423+
ZstLiteral {
424+
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
425+
},
422426
/// Associated constants and named constants
423427
NamedConst {
424428
def_id: DefId,
@@ -456,7 +460,7 @@ pub enum ExprKind<'tcx> {
456460

457461
impl<'tcx> ExprKind<'tcx> {
458462
pub fn zero_sized_literal(user_ty: Option<Canonical<'tcx, UserType<'tcx>>>) -> Self {
459-
ExprKind::NonHirLiteral { lit: ty::ScalarInt::ZST, user_ty }
463+
ExprKind::ZstLiteral { user_ty }
460464
}
461465
}
462466

compiler/rustc_middle/src/thir/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
129129
Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
130130
Literal { lit: _, neg: _ } => {}
131131
NonHirLiteral { lit: _, user_ty: _ } => {}
132+
ZstLiteral { user_ty: _ } => {}
132133
NamedConst { def_id: _, substs: _, user_ty: _ } => {}
133134
ConstParam { param: _, def_id: _ } => {}
134135
StaticRef { alloc_id: _, ty: _, def_id: _ } => {}

0 commit comments

Comments
 (0)