Skip to content

Commit f893495

Browse files
committed
Auto merge of #98957 - RalfJung:zst-are-different, r=lcnr,oli-obk
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 I propose we stop using ScalarInt to represent ZST (which are clearly not integers). Instead, we can add new ZST variants to those types that did not have other variants which could be used for this purpose. Based on #98831. Only the commits starting from "don't allow ZST in ScalarInt" are new. r? `@oli-obk`
2 parents 6c20ab7 + 4e7aaf1 commit f893495

File tree

139 files changed

+312
-291
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

139 files changed

+312
-291
lines changed

Diff for: compiler/rustc_codegen_cranelift/src/constant.rs

+1
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ pub(crate) fn codegen_const_value<'tcx>(
167167
}
168168

169169
match const_val {
170+
ConstValue::ZeroSized => unreachable!(), // we already handles ZST above
170171
ConstValue::Scalar(x) => match x {
171172
Scalar::Int(int) => {
172173
if fx.clif_type(layout.ty).is_some() {

Diff for: compiler/rustc_codegen_gcc/src/common.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use rustc_codegen_ssa::traits::{
99
StaticMethods,
1010
};
1111
use rustc_middle::mir::Mutability;
12-
use rustc_middle::ty::ScalarInt;
1312
use rustc_middle::ty::layout::{TyAndLayout, LayoutOf};
1413
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
1514
use rustc_target::abi::{self, HasDataLayout, Pointer, Size};
@@ -159,13 +158,13 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
159158
None
160159
}
161160

161+
fn zst_to_backend(&self, _ty: Type<'gcc>) -> RValue<'gcc> {
162+
self.const_undef(self.type_ix(0))
163+
}
164+
162165
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> {
163166
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
164167
match cv {
165-
Scalar::Int(ScalarInt::ZST) => {
166-
assert_eq!(0, layout.size(self).bytes());
167-
self.const_undef(self.type_ix(0))
168-
}
169168
Scalar::Int(int) => {
170169
let data = int.assert_bits(layout.size(self));
171170

Diff for: 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);

Diff for: 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::ZeroSized => {
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);

Diff for: 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>,

Diff for: 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::ZeroSized
161161
}
162162
}
163163
};

Diff for: 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::ZeroSized
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();

Diff for: 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::ZeroSized => 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.

Diff for: 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

Diff for: 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+
ZeroSized,
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::ZeroSized => ConstValue::ZeroSized,
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::ZeroSized => 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())

Diff for: compiler/rustc_middle/src/mir/mod.rs

+9-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::ZeroSized, 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::ZeroSized;
22002200
Self::Val(cv, ty)
22012201
}
22022202

@@ -2772,6 +2772,13 @@ fn pretty_print_const_value<'tcx>(
27722772
fmt.write_str(&cx.into_buffer())?;
27732773
return Ok(());
27742774
}
2775+
(ConstValue::ZeroSized, ty::FnDef(d, s)) => {
2776+
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
2777+
cx.print_alloc_ids = true;
2778+
let cx = cx.print_value_path(*d, s)?;
2779+
fmt.write_str(&cx.into_buffer())?;
2780+
return Ok(());
2781+
}
27752782
// FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
27762783
// their fields instead of just dumping the memory.
27772784
_ => {}

Diff for: compiler/rustc_middle/src/mir/pretty.rs

+3
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
448448
self.push(&format!("+ user_ty: {:?}", user_ty));
449449
}
450450

451+
// FIXME: this is a poor version of `pretty_print_const_value`.
451452
let fmt_val = |val: &ConstValue<'tcx>| match val {
453+
ConstValue::ZeroSized => format!("<ZST>"),
452454
ConstValue::Scalar(s) => format!("Scalar({:?})", s),
453455
ConstValue::Slice { .. } => format!("Slice(..)"),
454456
ConstValue::ByRef { .. } => format!("ByRef(..)"),
@@ -679,6 +681,7 @@ pub fn write_allocations<'tcx>(
679681
ConstValue::Scalar(interpret::Scalar::Int { .. }) => {
680682
Either::Left(Either::Right(std::iter::empty()))
681683
}
684+
ConstValue::ZeroSized => Either::Left(Either::Right(std::iter::empty())),
682685
ConstValue::ByRef { alloc, .. } | ConstValue::Slice { data: alloc, .. } => {
683686
Either::Right(alloc_ids_from_alloc(alloc))
684687
}

Diff for: compiler/rustc_middle/src/thir.rs

+4-6
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,
@@ -454,12 +458,6 @@ pub enum ExprKind<'tcx> {
454458
},
455459
}
456460

457-
impl<'tcx> ExprKind<'tcx> {
458-
pub fn zero_sized_literal(user_ty: Option<Canonical<'tcx, UserType<'tcx>>>) -> Self {
459-
ExprKind::NonHirLiteral { lit: ty::ScalarInt::ZST, user_ty }
460-
}
461-
}
462-
463461
/// Represents the association of a field identifier and an expression.
464462
///
465463
/// This is used in struct constructors.

Diff for: 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)