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 https://github.com/rust-lang/rust/pull/98831. Only the commits starting from "don't allow ZST in ScalarInt" are new. r? `@oli-obk`
This commit is contained in:
commit
f893495e3d
139 changed files with 312 additions and 291 deletions
|
@ -167,6 +167,7 @@ pub(crate) fn codegen_const_value<'tcx>(
|
|||
}
|
||||
|
||||
match const_val {
|
||||
ConstValue::ZeroSized => unreachable!(), // we already handles ZST above
|
||||
ConstValue::Scalar(x) => match x {
|
||||
Scalar::Int(int) => {
|
||||
if fx.clif_type(layout.ty).is_some() {
|
||||
|
|
|
@ -9,7 +9,6 @@ use rustc_codegen_ssa::traits::{
|
|||
StaticMethods,
|
||||
};
|
||||
use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::ty::ScalarInt;
|
||||
use rustc_middle::ty::layout::{TyAndLayout, LayoutOf};
|
||||
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
|
||||
use rustc_target::abi::{self, HasDataLayout, Pointer, Size};
|
||||
|
@ -159,13 +158,13 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
None
|
||||
}
|
||||
|
||||
fn zst_to_backend(&self, _ty: Type<'gcc>) -> RValue<'gcc> {
|
||||
self.const_undef(self.type_ix(0))
|
||||
}
|
||||
|
||||
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> {
|
||||
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
|
||||
match cv {
|
||||
Scalar::Int(ScalarInt::ZST) => {
|
||||
assert_eq!(0, layout.size(self).bytes());
|
||||
self.const_undef(self.type_ix(0))
|
||||
}
|
||||
Scalar::Int(int) => {
|
||||
let data = int.assert_bits(layout.size(self));
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ use rustc_codegen_ssa::traits::*;
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
|
||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::ScalarInt;
|
||||
use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer, Size};
|
||||
|
||||
use libc::{c_char, c_uint};
|
||||
|
@ -223,13 +222,13 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
fn zst_to_backend(&self, _llty: &'ll Type) -> &'ll Value {
|
||||
self.const_undef(self.type_ix(0))
|
||||
}
|
||||
|
||||
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value {
|
||||
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
|
||||
match cv {
|
||||
Scalar::Int(ScalarInt::ZST) => {
|
||||
assert_eq!(0, layout.size(self).bytes());
|
||||
self.const_undef(self.type_ix(0))
|
||||
}
|
||||
Scalar::Int(int) => {
|
||||
let data = int.assert_bits(layout.size(self));
|
||||
let llval = self.const_uint_big(self.type_ix(bitsize), data);
|
||||
|
|
|
@ -84,6 +84,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
|
|||
let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout));
|
||||
OperandValue::Immediate(llval)
|
||||
}
|
||||
ConstValue::ZeroSized => {
|
||||
let llval = bx.zst_to_backend(bx.immediate_backend_type(layout));
|
||||
OperandValue::Immediate(llval)
|
||||
}
|
||||
ConstValue::Slice { data, start, end } => {
|
||||
let Abi::ScalarPair(a_scalar, _) = layout.abi else {
|
||||
bug!("from_const: invalid ScalarPair layout: {:#?}", layout);
|
||||
|
|
|
@ -29,6 +29,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
|
|||
fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value;
|
||||
|
||||
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
|
||||
fn zst_to_backend(&self, llty: Self::Type) -> Self::Value;
|
||||
fn from_const_alloc(
|
||||
&self,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
|
|
|
@ -2,7 +2,7 @@ use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr};
|
|||
use crate::interpret::eval_nullary_intrinsic;
|
||||
use crate::interpret::{
|
||||
intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId,
|
||||
Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar,
|
||||
Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
|
||||
ScalarMaybeUninit, StackPopCleanup,
|
||||
};
|
||||
|
||||
|
@ -157,7 +157,7 @@ pub(super) fn op_to_const<'tcx>(
|
|||
"this MPlaceTy must come from a validated constant, thus we can assume the \
|
||||
alignment is correct",
|
||||
);
|
||||
ConstValue::Scalar(Scalar::ZST)
|
||||
ConstValue::ZeroSized
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -272,7 +272,7 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
match ty.kind() {
|
||||
ty::FnDef(..) => {
|
||||
assert!(valtree.unwrap_branch().is_empty());
|
||||
ConstValue::Scalar(Scalar::ZST)
|
||||
ConstValue::ZeroSized
|
||||
}
|
||||
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => match valtree {
|
||||
ty::ValTree::Leaf(scalar_int) => ConstValue::Scalar(Scalar::Int(scalar_int)),
|
||||
|
@ -344,11 +344,7 @@ fn valtree_into_mplace<'tcx>(
|
|||
|
||||
match ty.kind() {
|
||||
ty::FnDef(_, _) => {
|
||||
ecx.write_immediate(
|
||||
Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::ZST)),
|
||||
&place.into(),
|
||||
)
|
||||
.unwrap();
|
||||
ecx.write_immediate(Immediate::Uninit, &place.into()).unwrap();
|
||||
}
|
||||
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
|
||||
let scalar_int = valtree.unwrap_leaf();
|
||||
|
|
|
@ -297,8 +297,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
|
||||
let Some(alloc) = self.get_place_alloc(mplace)? else {
|
||||
return Ok(Some(ImmTy {
|
||||
// zero-sized type
|
||||
imm: Scalar::ZST.into(),
|
||||
// zero-sized type can be left uninit
|
||||
imm: Immediate::Uninit,
|
||||
layout: mplace.layout,
|
||||
}));
|
||||
};
|
||||
|
@ -441,8 +441,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// This makes several assumptions about what layouts we will encounter; we match what
|
||||
// codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`).
|
||||
let field_val: Immediate<_> = match (*base, base.layout.abi) {
|
||||
// the field contains no information
|
||||
_ if field_layout.is_zst() => Scalar::ZST.into(),
|
||||
// the field contains no information, can be left uninit
|
||||
_ if field_layout.is_zst() => Immediate::Uninit,
|
||||
// the field covers the entire type
|
||||
_ if field_layout.size == base.layout.size => {
|
||||
assert!(match (base.layout.abi, field_layout.abi) {
|
||||
|
@ -553,8 +553,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
let layout = self.layout_of_local(frame, local, layout)?;
|
||||
let op = if layout.is_zst() {
|
||||
// Do not read from ZST, they might not be initialized
|
||||
Operand::Immediate(Scalar::ZST.into())
|
||||
// Bypass `access_local` (helps in ConstProp)
|
||||
Operand::Immediate(Immediate::Uninit)
|
||||
} else {
|
||||
*M::access_local(frame, local)?
|
||||
};
|
||||
|
@ -709,6 +709,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
Operand::Indirect(MemPlace::from_ptr(ptr.into()))
|
||||
}
|
||||
ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()),
|
||||
ConstValue::ZeroSized => Operand::Immediate(Immediate::Uninit),
|
||||
ConstValue::Slice { data, start, end } => {
|
||||
// We rely on mutability being set correctly in `data` to prevent writes
|
||||
// where none should happen.
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#![feature(drain_filter)]
|
||||
#![feature(intra_doc_pointers)]
|
||||
#![feature(yeet_expr)]
|
||||
#![feature(const_option)]
|
||||
#![recursion_limit = "512"]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
|
||||
|
|
|
@ -29,11 +29,14 @@ pub struct ConstAlloc<'tcx> {
|
|||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
|
||||
#[derive(HashStable)]
|
||||
pub enum ConstValue<'tcx> {
|
||||
/// Used only for types with `layout::abi::Scalar` ABI and ZSTs.
|
||||
/// Used only for types with `layout::abi::Scalar` ABI.
|
||||
///
|
||||
/// Not using the enum `Value` to encode that this must not be `Uninit`.
|
||||
Scalar(Scalar),
|
||||
|
||||
/// Only used for ZSTs.
|
||||
ZeroSized,
|
||||
|
||||
/// Used only for `&[u8]` and `&str`
|
||||
Slice { data: ConstAllocation<'tcx>, start: usize, end: usize },
|
||||
|
||||
|
@ -55,6 +58,7 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> {
|
|||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ConstValue<'tcx>> {
|
||||
Some(match self {
|
||||
ConstValue::Scalar(s) => ConstValue::Scalar(s),
|
||||
ConstValue::ZeroSized => ConstValue::ZeroSized,
|
||||
ConstValue::Slice { data, start, end } => {
|
||||
ConstValue::Slice { data: tcx.lift(data)?, start, end }
|
||||
}
|
||||
|
@ -69,7 +73,7 @@ impl<'tcx> ConstValue<'tcx> {
|
|||
#[inline]
|
||||
pub fn try_to_scalar(&self) -> Option<Scalar<AllocId>> {
|
||||
match *self {
|
||||
ConstValue::ByRef { .. } | ConstValue::Slice { .. } => None,
|
||||
ConstValue::ByRef { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None,
|
||||
ConstValue::Scalar(val) => Some(val),
|
||||
}
|
||||
}
|
||||
|
@ -111,10 +115,6 @@ impl<'tcx> ConstValue<'tcx> {
|
|||
pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self {
|
||||
ConstValue::Scalar(Scalar::from_machine_usize(i, cx))
|
||||
}
|
||||
|
||||
pub fn zst() -> Self {
|
||||
Self::Scalar(Scalar::ZST)
|
||||
}
|
||||
}
|
||||
|
||||
/// A `Scalar` represents an immediate, primitive value existing outside of a
|
||||
|
@ -194,8 +194,6 @@ impl<Tag> From<ScalarInt> for Scalar<Tag> {
|
|||
}
|
||||
|
||||
impl<Tag> Scalar<Tag> {
|
||||
pub const ZST: Self = Scalar::Int(ScalarInt::ZST);
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_pointer(ptr: Pointer<Tag>, cx: &impl HasDataLayout) -> Self {
|
||||
Scalar::Ptr(ptr, u8::try_from(cx.pointer_size().bytes()).unwrap())
|
||||
|
|
|
@ -1711,7 +1711,7 @@ impl<'tcx> Operand<'tcx> {
|
|||
Operand::Constant(Box::new(Constant {
|
||||
span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::Val(ConstValue::zst(), ty),
|
||||
literal: ConstantKind::Val(ConstValue::ZeroSized, ty),
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -2196,7 +2196,7 @@ impl<'tcx> ConstantKind<'tcx> {
|
|||
|
||||
#[inline]
|
||||
pub fn zero_sized(ty: Ty<'tcx>) -> Self {
|
||||
let cv = ConstValue::Scalar(Scalar::ZST);
|
||||
let cv = ConstValue::ZeroSized;
|
||||
Self::Val(cv, ty)
|
||||
}
|
||||
|
||||
|
@ -2772,6 +2772,13 @@ fn pretty_print_const_value<'tcx>(
|
|||
fmt.write_str(&cx.into_buffer())?;
|
||||
return Ok(());
|
||||
}
|
||||
(ConstValue::ZeroSized, ty::FnDef(d, s)) => {
|
||||
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
|
||||
cx.print_alloc_ids = true;
|
||||
let cx = cx.print_value_path(*d, s)?;
|
||||
fmt.write_str(&cx.into_buffer())?;
|
||||
return Ok(());
|
||||
}
|
||||
// FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
|
||||
// their fields instead of just dumping the memory.
|
||||
_ => {}
|
||||
|
|
|
@ -448,7 +448,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
|||
self.push(&format!("+ user_ty: {:?}", user_ty));
|
||||
}
|
||||
|
||||
// FIXME: this is a poor version of `pretty_print_const_value`.
|
||||
let fmt_val = |val: &ConstValue<'tcx>| match val {
|
||||
ConstValue::ZeroSized => format!("<ZST>"),
|
||||
ConstValue::Scalar(s) => format!("Scalar({:?})", s),
|
||||
ConstValue::Slice { .. } => format!("Slice(..)"),
|
||||
ConstValue::ByRef { .. } => format!("ByRef(..)"),
|
||||
|
@ -679,6 +681,7 @@ pub fn write_allocations<'tcx>(
|
|||
ConstValue::Scalar(interpret::Scalar::Int { .. }) => {
|
||||
Either::Left(Either::Right(std::iter::empty()))
|
||||
}
|
||||
ConstValue::ZeroSized => Either::Left(Either::Right(std::iter::empty())),
|
||||
ConstValue::ByRef { alloc, .. } | ConstValue::Slice { data: alloc, .. } => {
|
||||
Either::Right(alloc_ids_from_alloc(alloc))
|
||||
}
|
||||
|
|
|
@ -419,6 +419,10 @@ pub enum ExprKind<'tcx> {
|
|||
lit: ty::ScalarInt,
|
||||
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
|
||||
},
|
||||
/// A literal of a ZST type.
|
||||
ZstLiteral {
|
||||
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
|
||||
},
|
||||
/// Associated constants and named constants
|
||||
NamedConst {
|
||||
def_id: DefId,
|
||||
|
@ -454,12 +458,6 @@ pub enum ExprKind<'tcx> {
|
|||
},
|
||||
}
|
||||
|
||||
impl<'tcx> ExprKind<'tcx> {
|
||||
pub fn zero_sized_literal(user_ty: Option<Canonical<'tcx, UserType<'tcx>>>) -> Self {
|
||||
ExprKind::NonHirLiteral { lit: ty::ScalarInt::ZST, user_ty }
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the association of a field identifier and an expression.
|
||||
///
|
||||
/// This is used in struct constructors.
|
||||
|
|
|
@ -129,6 +129,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
|
|||
Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
|
||||
Literal { lit: _, neg: _ } => {}
|
||||
NonHirLiteral { lit: _, user_ty: _ } => {}
|
||||
ZstLiteral { user_ty: _ } => {}
|
||||
NamedConst { def_id: _, substs: _, user_ty: _ } => {}
|
||||
ConstParam { param: _, def_id: _ } => {}
|
||||
StaticRef { alloc_id: _, ty: _, def_id: _ } => {}
|
||||
|
|
|
@ -4,6 +4,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
|||
use rustc_target::abi::Size;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::fmt;
|
||||
use std::num::NonZeroU8;
|
||||
|
||||
use crate::ty::TyCtxt;
|
||||
|
||||
|
@ -123,7 +124,7 @@ pub struct ScalarInt {
|
|||
/// The first `size` bytes of `data` are the value.
|
||||
/// Do not try to read less or more bytes than that. The remaining bytes must be 0.
|
||||
data: u128,
|
||||
size: u8,
|
||||
size: NonZeroU8,
|
||||
}
|
||||
|
||||
// Cannot derive these, as the derives take references to the fields, and we
|
||||
|
@ -135,33 +136,31 @@ impl<CTX> crate::ty::HashStable<CTX> for ScalarInt {
|
|||
// Since `Self` is a packed struct, that would create a possibly unaligned reference,
|
||||
// which is UB.
|
||||
{ self.data }.hash_stable(hcx, hasher);
|
||||
self.size.hash_stable(hcx, hasher);
|
||||
self.size.get().hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Encoder> Encodable<S> for ScalarInt {
|
||||
fn encode(&self, s: &mut S) {
|
||||
s.emit_u128(self.data);
|
||||
s.emit_u8(self.size);
|
||||
s.emit_u8(self.size.get());
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Decoder> Decodable<D> for ScalarInt {
|
||||
fn decode(d: &mut D) -> ScalarInt {
|
||||
ScalarInt { data: d.read_u128(), size: d.read_u8() }
|
||||
ScalarInt { data: d.read_u128(), size: NonZeroU8::new(d.read_u8()).unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
impl ScalarInt {
|
||||
pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: 1 };
|
||||
pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZeroU8::new(1).unwrap() };
|
||||
|
||||
pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: 1 };
|
||||
|
||||
pub const ZST: ScalarInt = ScalarInt { data: 0_u128, size: 0 };
|
||||
pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZeroU8::new(1).unwrap() };
|
||||
|
||||
#[inline]
|
||||
pub fn size(self) -> Size {
|
||||
Size::from_bytes(self.size)
|
||||
Size::from_bytes(self.size.get())
|
||||
}
|
||||
|
||||
/// Make sure the `data` fits in `size`.
|
||||
|
@ -185,7 +184,7 @@ impl ScalarInt {
|
|||
|
||||
#[inline]
|
||||
pub fn null(size: Size) -> Self {
|
||||
Self { data: 0, size: size.bytes() as u8 }
|
||||
Self { data: 0, size: NonZeroU8::new(size.bytes() as u8).unwrap() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -197,7 +196,7 @@ impl ScalarInt {
|
|||
pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
|
||||
let data = i.into();
|
||||
if size.truncate(data) == data {
|
||||
Some(Self { data, size: size.bytes() as u8 })
|
||||
Some(Self { data, size: NonZeroU8::new(size.bytes() as u8).unwrap() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -209,7 +208,7 @@ impl ScalarInt {
|
|||
// `into` performed sign extension, we have to truncate
|
||||
let truncated = size.truncate(i as u128);
|
||||
if size.sign_extend(truncated) as i128 == i {
|
||||
Some(Self { data: truncated, size: size.bytes() as u8 })
|
||||
Some(Self { data: truncated, size: NonZeroU8::new(size.bytes() as u8).unwrap() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -225,7 +224,7 @@ impl ScalarInt {
|
|||
#[inline]
|
||||
pub fn to_bits(self, target_size: Size) -> Result<u128, Size> {
|
||||
assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
|
||||
if target_size.bytes() == u64::from(self.size) {
|
||||
if target_size.bytes() == u64::from(self.size.get()) {
|
||||
self.check_data();
|
||||
Ok(self.data)
|
||||
} else {
|
||||
|
@ -339,7 +338,7 @@ macro_rules! from {
|
|||
fn from(u: $ty) -> Self {
|
||||
Self {
|
||||
data: u128::from(u),
|
||||
size: std::mem::size_of::<$ty>() as u8,
|
||||
size: NonZeroU8::new(std::mem::size_of::<$ty>() as u8).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -382,7 +381,7 @@ impl TryFrom<ScalarInt> for bool {
|
|||
impl From<char> for ScalarInt {
|
||||
#[inline]
|
||||
fn from(c: char) -> Self {
|
||||
Self { data: c as u128, size: std::mem::size_of::<char>() as u8 }
|
||||
Self { data: c as u128, size: NonZeroU8::new(std::mem::size_of::<char>() as u8).unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -409,7 +408,7 @@ impl From<Single> for ScalarInt {
|
|||
#[inline]
|
||||
fn from(f: Single) -> Self {
|
||||
// We trust apfloat to give us properly truncated data.
|
||||
Self { data: f.to_bits(), size: 4 }
|
||||
Self { data: f.to_bits(), size: NonZeroU8::new((Single::BITS / 8) as u8).unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -425,7 +424,7 @@ impl From<Double> for ScalarInt {
|
|||
#[inline]
|
||||
fn from(f: Double) -> Self {
|
||||
// We trust apfloat to give us properly truncated data.
|
||||
Self { data: f.to_bits(), size: 8 }
|
||||
Self { data: f.to_bits(), size: NonZeroU8::new((Double::BITS / 8) as u8).unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,13 +438,8 @@ impl TryFrom<ScalarInt> for Double {
|
|||
|
||||
impl fmt::Debug for ScalarInt {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.size == 0 {
|
||||
self.check_data();
|
||||
write!(f, "<ZST>")
|
||||
} else {
|
||||
// Dispatch to LowerHex below.
|
||||
write!(f, "0x{:x}", self)
|
||||
}
|
||||
// Dispatch to LowerHex below.
|
||||
write!(f, "0x{:x}", self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,7 +457,7 @@ impl fmt::LowerHex for ScalarInt {
|
|||
// would thus borrow `self.data`. Since `Self`
|
||||
// is a packed struct, that would create a possibly unaligned reference, which
|
||||
// is UB.
|
||||
write!(f, "{:01$x}", { self.data }, self.size as usize * 2)
|
||||
write!(f, "{:01$x}", { self.data }, self.size.get() as usize * 2)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -477,7 +471,7 @@ impl fmt::UpperHex for ScalarInt {
|
|||
// would thus borrow `self.data`. Since `Self`
|
||||
// is a packed struct, that would create a possibly unaligned reference, which
|
||||
// is UB.
|
||||
write!(f, "{:01$X}", { self.data }, self.size as usize * 2)
|
||||
write!(f, "{:01$X}", { self.data }, self.size.get() as usize * 2)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1355,10 +1355,6 @@ pub trait PrettyPrinter<'tcx>:
|
|||
" as ",
|
||||
)?;
|
||||
}
|
||||
// For function type zsts just printing the path is enough
|
||||
ty::FnDef(d, s) if int == ScalarInt::ZST => {
|
||||
p!(print_value_path(*d, s))
|
||||
}
|
||||
// Nontrivial types with scalar bit representation
|
||||
_ => {
|
||||
let print = |mut this: Self| {
|
||||
|
|
|
@ -49,11 +49,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
inferred_ty: ty,
|
||||
})
|
||||
});
|
||||
|
||||
let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
|
||||
|
||||
Constant { span, user_ty: user_ty, literal }
|
||||
}
|
||||
ExprKind::ZstLiteral { user_ty } => {
|
||||
let user_ty = user_ty.map(|user_ty| {
|
||||
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
|
||||
span,
|
||||
user_ty,
|
||||
inferred_ty: ty,
|
||||
})
|
||||
});
|
||||
let literal = ConstantKind::Val(ConstValue::ZeroSized, ty);
|
||||
|
||||
Constant { span, user_ty: user_ty, literal }
|
||||
}
|
||||
ExprKind::NamedConst { def_id, substs, user_ty } => {
|
||||
let user_ty = user_ty.map(|user_ty| {
|
||||
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
|
||||
|
|
|
@ -603,6 +603,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
| ExprKind::Literal { .. }
|
||||
| ExprKind::NamedConst { .. }
|
||||
| ExprKind::NonHirLiteral { .. }
|
||||
| ExprKind::ZstLiteral { .. }
|
||||
| ExprKind::ConstParam { .. }
|
||||
| ExprKind::ConstBlock { .. }
|
||||
| ExprKind::StaticRef { .. }
|
||||
|
|
|
@ -415,6 +415,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
ExprKind::Literal { .. }
|
||||
| ExprKind::NamedConst { .. }
|
||||
| ExprKind::NonHirLiteral { .. }
|
||||
| ExprKind::ZstLiteral { .. }
|
||||
| ExprKind::ConstParam { .. }
|
||||
| ExprKind::ConstBlock { .. }
|
||||
| ExprKind::StaticRef { .. } => {
|
||||
|
|
|
@ -72,6 +72,7 @@ impl Category {
|
|||
ExprKind::ConstBlock { .. }
|
||||
| ExprKind::Literal { .. }
|
||||
| ExprKind::NonHirLiteral { .. }
|
||||
| ExprKind::ZstLiteral { .. }
|
||||
| ExprKind::ConstParam { .. }
|
||||
| ExprKind::StaticRef { .. }
|
||||
| ExprKind::NamedConst { .. } => Some(Category::Constant),
|
||||
|
|
|
@ -559,6 +559,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
| ExprKind::Literal { .. }
|
||||
| ExprKind::NamedConst { .. }
|
||||
| ExprKind::NonHirLiteral { .. }
|
||||
| ExprKind::ZstLiteral { .. }
|
||||
| ExprKind::ConstParam { .. }
|
||||
| ExprKind::ThreadLocalRef(_)
|
||||
| ExprKind::StaticRef { .. } => {
|
||||
|
|
|
@ -307,6 +307,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
| ExprKind::Literal { .. }
|
||||
| ExprKind::NamedConst { .. }
|
||||
| ExprKind::NonHirLiteral { .. }
|
||||
| ExprKind::ZstLiteral { .. }
|
||||
| ExprKind::ConstParam { .. }
|
||||
| ExprKind::ConstBlock { .. }
|
||||
| ExprKind::Deref { .. }
|
||||
|
|
|
@ -799,7 +799,7 @@ impl<'tcx> Cx<'tcx> {
|
|||
}
|
||||
};
|
||||
let ty = self.tcx().mk_fn_def(def_id, substs);
|
||||
Expr { temp_lifetime, ty, span, kind: ExprKind::zero_sized_literal(user_ty) }
|
||||
Expr { temp_lifetime, ty, span, kind: ExprKind::ZstLiteral { user_ty } }
|
||||
}
|
||||
|
||||
fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId {
|
||||
|
@ -828,7 +828,7 @@ impl<'tcx> Cx<'tcx> {
|
|||
| Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
|
||||
| Res::SelfCtor(_) => {
|
||||
let user_ty = self.user_substs_applied_to_res(expr.hir_id, res);
|
||||
ExprKind::zero_sized_literal(user_ty)
|
||||
ExprKind::ZstLiteral { user_ty }
|
||||
}
|
||||
|
||||
Res::Def(DefKind::ConstParam, def_id) => {
|
||||
|
|
|
@ -451,6 +451,10 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
|||
let val = ty::ValTree::from_scalar_int(lit);
|
||||
self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty)))
|
||||
}
|
||||
&ExprKind::ZstLiteral { user_ty: _ } => {
|
||||
let val = ty::ValTree::zst();
|
||||
self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty)))
|
||||
}
|
||||
&ExprKind::NamedConst { def_id, substs, user_ty: _ } => {
|
||||
let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue