Skip to content

Commit 2906e0f

Browse files
authored
Rollup merge of rust-lang#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 rust-lang#98831. Only the commits starting from "don't allow ZST in ScalarInt" are new. r? `@oli-obk`
2 parents e12a4a5 + 19e0a41 commit 2906e0f

File tree

138 files changed

+311
-290
lines changed

Some content is hidden

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

138 files changed

+311
-290
lines changed

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() {

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_span::Symbol;
@@ -157,13 +156,13 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
157156
None
158157
}
159158

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

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_span::symbol::Symbol;
1817
use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer, Size};
1918

@@ -219,13 +218,13 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
219218
})
220219
}
221220

221+
fn zst_to_backend(&self, _llty: &'ll Type) -> &'ll Value {
222+
self.const_undef(self.type_ix(0))
223+
}
224+
222225
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value {
223226
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
224227
match cv {
225-
Scalar::Int(ScalarInt::ZST) => {
226-
assert_eq!(0, layout.size(self).bytes());
227-
self.const_undef(self.type_ix(0))
228-
}
229228
Scalar::Int(int) => {
230229
let data = int.assert_bits(layout.size(self));
231230
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::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);

compiler/rustc_codegen_ssa/src/traits/consts.rs

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

3232
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
33+
fn zst_to_backend(&self, llty: Self::Type) -> Self::Value;
3334
fn from_const_alloc(
3435
&self,
3536
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::ZeroSized
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::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();

compiler/rustc_const_eval/src/interpret/operand.rs

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

294294
let Some(alloc) = self.get_place_alloc(mplace)? else {
295295
return Ok(Some(ImmTy {
296-
// zero-sized type
297-
imm: Scalar::ZST.into(),
296+
// zero-sized type can be left uninit
297+
imm: Immediate::Uninit,
298298
layout: mplace.layout,
299299
}));
300300
};
@@ -437,8 +437,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
437437
// This makes several assumptions about what layouts we will encounter; we match what
438438
// codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`).
439439
let field_val: Immediate<_> = match (*base, base.layout.abi) {
440-
// the field contains no information
441-
_ if field_layout.is_zst() => Scalar::ZST.into(),
440+
// the field contains no information, can be left uninit
441+
_ if field_layout.is_zst() => Immediate::Uninit,
442442
// the field covers the entire type
443443
_ if field_layout.size == base.layout.size => {
444444
assert!(match (base.layout.abi, field_layout.abi) {
@@ -549,8 +549,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
549549
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
550550
let layout = self.layout_of_local(frame, local, layout)?;
551551
let op = if layout.is_zst() {
552-
// Do not read from ZST, they might not be initialized
553-
Operand::Immediate(Scalar::ZST.into())
552+
// Bypass `access_local` (helps in ConstProp)
553+
Operand::Immediate(Immediate::Uninit)
554554
} else {
555555
*M::access_local(frame, local)?
556556
};
@@ -705,6 +705,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
705705
Operand::Indirect(MemPlace::from_ptr(ptr.into()))
706706
}
707707
ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()),
708+
ConstValue::ZeroSized => Operand::Immediate(Immediate::Uninit),
708709
ConstValue::Slice { data, start, end } => {
709710
// We rely on mutability being set correctly in `data` to prevent writes
710711
// 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+
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())

compiler/rustc_middle/src/mir/mod.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1708,7 +1708,7 @@ impl<'tcx> Operand<'tcx> {
17081708
Operand::Constant(Box::new(Constant {
17091709
span,
17101710
user_ty: None,
1711-
literal: ConstantKind::Val(ConstValue::zst(), ty),
1711+
literal: ConstantKind::Val(ConstValue::ZeroSized, ty),
17121712
}))
17131713
}
17141714

@@ -2193,7 +2193,7 @@ impl<'tcx> ConstantKind<'tcx> {
21932193

21942194
#[inline]
21952195
pub fn zero_sized(ty: Ty<'tcx>) -> Self {
2196-
let cv = ConstValue::Scalar(Scalar::ZST);
2196+
let cv = ConstValue::ZeroSized;
21972197
Self::Val(cv, ty)
21982198
}
21992199

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

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
}

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.

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)