Auto merge of #116707 - cjgillot:slice-id, r=oli-obk,RalfJung

Create an `AllocId` for `ConstValue::Slice`.

This PR modifies `ConstValue::Slice` to use an `AllocId` instead of directly manipulating the allocation. This was originally proposed by https://github.com/rust-lang/rust/pull/115764 but was a perf regression.

Almost 2 years later, enough code has changed to make this a perf improvement: https://github.com/rust-lang/rust/pull/116707#issuecomment-3067158777
This commit is contained in:
bors 2025-07-24 03:35:47 +00:00
commit 3c30dbbe31
86 changed files with 632 additions and 275 deletions

View file

@ -74,7 +74,7 @@ pub(crate) fn codegen_tls_ref<'tcx>(
pub(crate) fn eval_mir_constant<'tcx>(
fx: &FunctionCx<'_, '_, 'tcx>,
constant: &ConstOperand<'tcx>,
) -> (ConstValue<'tcx>, Ty<'tcx>) {
) -> (ConstValue, Ty<'tcx>) {
let cv = fx.monomorphize(constant.const_);
// This cannot fail because we checked all required_consts in advance.
let val = cv
@ -93,7 +93,7 @@ pub(crate) fn codegen_constant_operand<'tcx>(
pub(crate) fn codegen_const_value<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
const_val: ConstValue<'tcx>,
const_val: ConstValue,
ty: Ty<'tcx>,
) -> CValue<'tcx> {
let layout = fx.layout_of(ty);
@ -210,8 +210,7 @@ pub(crate) fn codegen_const_value<'tcx>(
.offset_i64(fx, i64::try_from(offset.bytes()).unwrap()),
layout,
),
ConstValue::Slice { data, meta } => {
let alloc_id = fx.tcx.reserve_and_set_memory_alloc(data);
ConstValue::Slice { alloc_id, meta } => {
let ptr = pointer_for_allocation(fx, alloc_id).get_addr(fx);
let len = fx.bcx.ins().iconst(fx.pointer_type, meta as i64);
CValue::by_val_pair(ptr, len, layout)

View file

@ -148,7 +148,7 @@ pub(crate) fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
pub fn asm_const_to_str<'tcx>(
tcx: TyCtxt<'tcx>,
sp: Span,
const_value: mir::ConstValue<'tcx>,
const_value: mir::ConstValue,
ty_and_layout: TyAndLayout<'tcx>,
) -> String {
let mir::ConstValue::Scalar(scalar) = const_value else {

View file

@ -20,7 +20,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
OperandRef::from_const(bx, val, ty)
}
pub fn eval_mir_constant(&self, constant: &mir::ConstOperand<'tcx>) -> mir::ConstValue<'tcx> {
pub fn eval_mir_constant(&self, constant: &mir::ConstOperand<'tcx>) -> mir::ConstValue {
// `MirUsedCollector` visited all required_consts before codegen began, so if we got here
// there can be no more constants that fail to evaluate.
self.monomorphize(constant.const_)

View file

@ -140,7 +140,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
pub(crate) fn from_const<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
val: mir::ConstValue<'tcx>,
val: mir::ConstValue,
ty: Ty<'tcx>,
) -> Self {
let layout = bx.layout_of(ty);
@ -154,14 +154,11 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
OperandValue::Immediate(llval)
}
ConstValue::ZeroSized => return OperandRef::zero_sized(layout),
ConstValue::Slice { data, meta } => {
ConstValue::Slice { alloc_id, meta } => {
let BackendRepr::ScalarPair(a_scalar, _) = layout.backend_repr else {
bug!("from_const: invalid ScalarPair layout: {:#?}", layout);
};
let a = Scalar::from_pointer(
Pointer::new(bx.tcx().reserve_and_set_memory_alloc(data).into(), Size::ZERO),
&bx.tcx(),
);
let a = Scalar::from_pointer(Pointer::new(alloc_id.into(), Size::ZERO), &bx.tcx());
let a_llval = bx.scalar_to_backend(
a,
a_scalar,

View file

@ -152,7 +152,7 @@ pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>(
pub fn mk_eval_cx_for_const_val<'tcx>(
tcx: TyCtxtAt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
val: mir::ConstValue<'tcx>,
val: mir::ConstValue,
ty: Ty<'tcx>,
) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> {
let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, typing_env, CanAccessMutGlobal::No);
@ -172,7 +172,7 @@ pub(super) fn op_to_const<'tcx>(
ecx: &CompileTimeInterpCx<'tcx>,
op: &OpTy<'tcx>,
for_diagnostics: bool,
) -> ConstValue<'tcx> {
) -> ConstValue {
// Handle ZST consistently and early.
if op.layout.is_zst() {
return ConstValue::ZeroSized;
@ -241,10 +241,9 @@ pub(super) fn op_to_const<'tcx>(
let (prov, offset) =
ptr.into_pointer_or_addr().expect(msg).prov_and_relative_offset();
let alloc_id = prov.alloc_id();
let data = ecx.tcx.global_alloc(alloc_id).unwrap_memory();
assert!(offset == abi::Size::ZERO, "{}", msg);
let meta = b.to_target_usize(ecx).expect(msg);
ConstValue::Slice { data, meta }
ConstValue::Slice { alloc_id, meta }
}
Immediate::Uninit => bug!("`Uninit` is not a valid value for {}", op.layout.ty),
},
@ -256,7 +255,7 @@ pub(crate) fn turn_into_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
constant: ConstAlloc<'tcx>,
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
) -> ConstValue<'tcx> {
) -> ConstValue {
let cid = key.value;
let def_id = cid.instance.def.def_id();
let is_static = tcx.is_static(def_id);

View file

@ -28,7 +28,7 @@ const VALTREE_MAX_NODES: usize = 100000;
#[instrument(skip(tcx), level = "debug")]
pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
tcx: TyCtxt<'tcx>,
val: mir::ConstValue<'tcx>,
val: mir::ConstValue,
ty: Ty<'tcx>,
) -> Option<mir::DestructuredConstant<'tcx>> {
let typing_env = ty::TypingEnv::fully_monomorphized();

View file

@ -259,7 +259,7 @@ pub fn valtree_to_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
cv: ty::Value<'tcx>,
) -> mir::ConstValue<'tcx> {
) -> mir::ConstValue {
// Basic idea: We directly construct `Scalar` values from trivial `ValTree`s
// (those for constants with type bool, int, uint, float or char).
// For all other types we create an `MPlace` and fill that by walking

View file

@ -582,8 +582,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
span: Span,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| {
let const_val = val.eval(*ecx.tcx, ecx.typing_env, span).map_err(|err| {
let const_val = val.eval(*self.tcx, self.typing_env, span).map_err(|err| {
if M::ALL_CONSTS_ARE_PRECHECKED {
match err {
ErrorHandled::TooGeneric(..) => {},
@ -599,11 +598,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
}
}
err.emit_note(*ecx.tcx);
err.emit_note(*self.tcx);
err
})?;
ecx.const_val_to_op(const_val, val.ty(), layout)
})
self.const_val_to_op(const_val, val.ty(), layout)
}
#[must_use]

View file

@ -6,7 +6,7 @@ use std::assert_matches::assert_matches;
use rustc_abi::{FieldIdx, HasDataLayout, Size};
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_middle::mir::interpret::{read_target_uint, write_target_uint};
use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint};
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{Ty, TyCtxt};
@ -17,17 +17,18 @@ use tracing::trace;
use super::memory::MemoryKind;
use super::util::ensure_monomorphic_enough;
use super::{
Allocation, CheckInAllocMsg, ConstAllocation, ImmTy, InterpCx, InterpResult, Machine, OpTy,
PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_ub_custom, err_unsup_format,
interp_ok, throw_inval, throw_ub_custom, throw_ub_format,
AllocId, CheckInAllocMsg, ImmTy, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Pointer,
PointerArithmetic, Provenance, Scalar, err_ub_custom, err_unsup_format, interp_ok, throw_inval,
throw_ub_custom, throw_ub_format,
};
use crate::fluent_generated as fluent;
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (AllocId, u64) {
let path = crate::util::type_name(tcx, ty);
let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes(), ());
tcx.mk_const_alloc(alloc)
let bytes = path.into_bytes();
let len = bytes.len().try_into().unwrap();
(tcx.allocate_bytes_dedup(bytes, CTFE_ALLOC_SALT), len)
}
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Generates a value of `TypeId` for `ty` in-place.
@ -126,8 +127,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
sym::type_name => {
let tp_ty = instance.args.type_at(0);
ensure_monomorphic_enough(tcx, tp_ty)?;
let alloc = alloc_type_name(tcx, tp_ty);
let val = ConstValue::Slice { data: alloc, meta: alloc.inner().size().bytes() };
let (alloc_id, meta) = alloc_type_name(tcx, tp_ty);
let val = ConstValue::Slice { alloc_id, meta };
let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?;
self.copy_op(&val, dest)?;
}

View file

@ -12,7 +12,6 @@ use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{mir, ty};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use rustc_target::callconv::FnAbi;
@ -587,27 +586,6 @@ pub trait Machine<'tcx>: Sized {
interp_ok(())
}
/// Evaluate the given constant. The `eval` function will do all the required evaluation,
/// but this hook has the chance to do some pre/postprocessing.
#[inline(always)]
fn eval_mir_constant<F>(
ecx: &InterpCx<'tcx, Self>,
val: mir::Const<'tcx>,
span: Span,
layout: Option<TyAndLayout<'tcx>>,
eval: F,
) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>
where
F: Fn(
&InterpCx<'tcx, Self>,
mir::Const<'tcx>,
Span,
Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>,
{
eval(ecx, val, span, layout)
}
/// Returns the salt to be used for a deduplicated global alloation.
/// If the allocation is for a function, the instance is provided as well
/// (this lets Miri ensure unique addresses for some functions).

View file

@ -836,7 +836,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
pub(crate) fn const_val_to_op(
&self,
val_val: mir::ConstValue<'tcx>,
val_val: mir::ConstValue,
ty: Ty<'tcx>,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
@ -860,9 +860,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(),
mir::ConstValue::ZeroSized => Immediate::Uninit,
mir::ConstValue::Slice { data, meta } => {
mir::ConstValue::Slice { alloc_id, meta } => {
// This is const data, no mutation allowed.
let alloc_id = self.tcx.reserve_and_set_memory_alloc(data);
let ptr = Pointer::new(CtfeProvenance::from(alloc_id).as_immutable(), Size::ZERO);
Immediate::new_slice(self.global_root_pointer(ptr)?.into(), meta, self)
}

View file

@ -57,7 +57,7 @@ pub(crate) fn const_caller_location_provider(
file: Symbol,
line: u32,
col: u32,
) -> mir::ConstValue<'_> {
) -> mir::ConstValue {
trace!("const_caller_location: {}:{}:{}", file, line, col);
let mut ecx = mk_eval_cx_to_read_const_val(
tcx,

View file

@ -50,10 +50,10 @@ macro_rules! declare_hooks {
declare_hooks! {
/// Tries to destructure an `mir::Const` ADT or array into its variant index
/// and its field values. This should only be used for pretty printing.
hook try_destructure_mir_constant_for_user_output(val: mir::ConstValue<'tcx>, ty: Ty<'tcx>) -> Option<mir::DestructuredConstant<'tcx>>;
hook try_destructure_mir_constant_for_user_output(val: mir::ConstValue, ty: Ty<'tcx>) -> Option<mir::DestructuredConstant<'tcx>>;
/// Getting a &core::panic::Location referring to a span.
hook const_caller_location(file: rustc_span::Symbol, line: u32, col: u32) -> mir::ConstValue<'tcx>;
hook const_caller_location(file: rustc_span::Symbol, line: u32, col: u32) -> mir::ConstValue;
/// Returns `true` if this def is a function-like thing that is eligible for
/// coverage instrumentation under `-Cinstrument-coverage`.

View file

@ -9,9 +9,7 @@ use rustc_span::{DUMMY_SP, Span, Symbol};
use rustc_type_ir::TypeVisitableExt;
use super::interpret::ReportedErrorInfo;
use crate::mir::interpret::{
AllocId, AllocRange, ConstAllocation, ErrorHandled, GlobalAlloc, Scalar, alloc_range,
};
use crate::mir::interpret::{AllocId, AllocRange, ErrorHandled, GlobalAlloc, Scalar, alloc_range};
use crate::mir::{Promoted, pretty_print_const_value};
use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt};
@ -33,8 +31,8 @@ pub struct ConstAlloc<'tcx> {
/// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for
/// array length computations, enum discriminants and the pattern matching logic.
#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash)]
#[derive(HashStable, Lift)]
pub enum ConstValue<'tcx> {
#[derive(HashStable)]
pub enum ConstValue {
/// Used for types with `layout::abi::Scalar` ABI.
///
/// Not using the enum `Value` to encode that this must not be `Uninit`.
@ -52,7 +50,7 @@ pub enum ConstValue<'tcx> {
Slice {
/// The allocation storing the slice contents.
/// This always points to the beginning of the allocation.
data: ConstAllocation<'tcx>,
alloc_id: AllocId,
/// The metadata field of the reference.
/// This is a "target usize", so we use `u64` as in the interpreter.
meta: u64,
@ -75,9 +73,9 @@ pub enum ConstValue<'tcx> {
}
#[cfg(target_pointer_width = "64")]
rustc_data_structures::static_assert_size!(ConstValue<'_>, 24);
rustc_data_structures::static_assert_size!(ConstValue, 24);
impl<'tcx> ConstValue<'tcx> {
impl ConstValue {
#[inline]
pub fn try_to_scalar(&self) -> Option<Scalar> {
match *self {
@ -98,11 +96,11 @@ impl<'tcx> ConstValue<'tcx> {
self.try_to_scalar_int()?.try_into().ok()
}
pub fn try_to_target_usize(&self, tcx: TyCtxt<'tcx>) -> Option<u64> {
pub fn try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Option<u64> {
Some(self.try_to_scalar_int()?.to_target_usize(tcx))
}
pub fn try_to_bits_for_ty(
pub fn try_to_bits_for_ty<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
@ -132,12 +130,15 @@ impl<'tcx> ConstValue<'tcx> {
}
/// Must only be called on constants of type `&str` or `&[u8]`!
pub fn try_get_slice_bytes_for_diagnostics(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx [u8]> {
let (data, start, end) = match self {
pub fn try_get_slice_bytes_for_diagnostics<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
) -> Option<&'tcx [u8]> {
let (alloc_id, start, len) = match self {
ConstValue::Scalar(_) | ConstValue::ZeroSized => {
bug!("`try_get_slice_bytes` on non-slice constant")
}
&ConstValue::Slice { data, meta } => (data, 0, meta),
&ConstValue::Slice { alloc_id, meta } => (alloc_id, 0, meta),
&ConstValue::Indirect { alloc_id, offset } => {
// The reference itself is stored behind an indirection.
// Load the reference, and then load the actual slice contents.
@ -170,26 +171,29 @@ impl<'tcx> ConstValue<'tcx> {
// Non-empty slice, must have memory. We know this is a relative pointer.
let (inner_prov, offset) =
ptr.into_pointer_or_addr().ok()?.prov_and_relative_offset();
let data = tcx.global_alloc(inner_prov.alloc_id()).unwrap_memory();
(data, offset.bytes(), offset.bytes() + len)
(inner_prov.alloc_id(), offset.bytes(), len)
}
};
let data = tcx.global_alloc(alloc_id).unwrap_memory();
// This is for diagnostics only, so we are okay to use `inspect_with_uninit_and_ptr_outside_interpreter`.
let start = start.try_into().unwrap();
let end = end.try_into().unwrap();
let end = start + usize::try_from(len).unwrap();
Some(data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end))
}
/// Check if a constant may contain provenance information. This is used by MIR opts.
/// Can return `true` even if there is no provenance.
pub fn may_have_provenance(&self, tcx: TyCtxt<'tcx>, size: Size) -> bool {
pub fn may_have_provenance(&self, tcx: TyCtxt<'_>, size: Size) -> bool {
match *self {
ConstValue::ZeroSized | ConstValue::Scalar(Scalar::Int(_)) => return false,
ConstValue::Scalar(Scalar::Ptr(..)) => return true,
// It's hard to find out the part of the allocation we point to;
// just conservatively check everything.
ConstValue::Slice { data, meta: _ } => !data.inner().provenance().ptrs().is_empty(),
ConstValue::Slice { alloc_id, meta: _ } => {
!tcx.global_alloc(alloc_id).unwrap_memory().inner().provenance().ptrs().is_empty()
}
ConstValue::Indirect { alloc_id, offset } => !tcx
.global_alloc(alloc_id)
.unwrap_memory()
@ -200,7 +204,7 @@ impl<'tcx> ConstValue<'tcx> {
}
/// Check if a constant only contains uninitialized bytes.
pub fn all_bytes_uninit(&self, tcx: TyCtxt<'tcx>) -> bool {
pub fn all_bytes_uninit(&self, tcx: TyCtxt<'_>) -> bool {
let ConstValue::Indirect { alloc_id, .. } = self else {
return false;
};
@ -247,7 +251,7 @@ pub enum Const<'tcx> {
/// This constant cannot go back into the type system, as it represents
/// something the type system cannot handle (e.g. pointers).
Val(ConstValue<'tcx>, Ty<'tcx>),
Val(ConstValue, Ty<'tcx>),
}
impl<'tcx> Const<'tcx> {
@ -343,7 +347,7 @@ impl<'tcx> Const<'tcx> {
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
span: Span,
) -> Result<ConstValue<'tcx>, ErrorHandled> {
) -> Result<ConstValue, ErrorHandled> {
match self {
Const::Ty(_, c) => {
if c.has_non_region_param() {
@ -440,7 +444,7 @@ impl<'tcx> Const<'tcx> {
}
#[inline]
pub fn from_value(val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self {
pub fn from_value(val: ConstValue, ty: Ty<'tcx>) -> Self {
Self::Val(val, ty)
}
@ -487,9 +491,8 @@ impl<'tcx> Const<'tcx> {
/// taking into account even pointer identity tests.
pub fn is_deterministic(&self) -> bool {
// Some constants may generate fresh allocations for pointers they contain,
// so using the same constant twice can yield two different results:
// - valtrees purposefully generate new allocations
// - ConstValue::Slice also generate new allocations
// so using the same constant twice can yield two different results.
// Notably, valtrees purposefully generate new allocations.
match self {
Const::Ty(_, c) => match c.kind() {
ty::ConstKind::Param(..) => true,
@ -507,11 +510,11 @@ impl<'tcx> Const<'tcx> {
| ty::ConstKind::Placeholder(..) => bug!(),
},
Const::Unevaluated(..) => false,
// If the same slice appears twice in the MIR, we cannot guarantee that we will
// give the same `AllocId` to the data.
Const::Val(ConstValue::Slice { .. }, _) => false,
Const::Val(
ConstValue::ZeroSized | ConstValue::Scalar(_) | ConstValue::Indirect { .. },
ConstValue::Slice { .. }
| ConstValue::ZeroSized
| ConstValue::Scalar(_)
| ConstValue::Indirect { .. },
_,
) => true,
}
@ -574,7 +577,7 @@ impl<'tcx> Display for Const<'tcx> {
/// Const-related utilities
impl<'tcx> TyCtxt<'tcx> {
pub fn span_as_caller_location(self, span: Span) -> ConstValue<'tcx> {
pub fn span_as_caller_location(self, span: Span) -> ConstValue {
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
let caller = self.sess.source_map().lookup_char_pos(topmost.lo());
self.const_caller_location(

View file

@ -137,7 +137,7 @@ impl<'tcx> ValTreeCreationError<'tcx> {
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>;
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
pub type EvalToConstValueResult<'tcx> = Result<ConstValue, ErrorHandled>;
pub type EvalToValTreeResult<'tcx> = Result<ValTree<'tcx>, ValTreeCreationError<'tcx>>;
#[cfg(target_pointer_width = "64")]

View file

@ -1465,7 +1465,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
self.push(&format!("+ user_ty: {user_ty:?}"));
}
let fmt_val = |val: ConstValue<'tcx>, ty: Ty<'tcx>| {
let fmt_val = |val: ConstValue, ty: Ty<'tcx>| {
let tcx = self.tcx;
rustc_data_structures::make_display(move |fmt| {
pretty_print_const_value_tcx(tcx, val, ty, fmt)
@ -1562,16 +1562,12 @@ pub fn write_allocations<'tcx>(
alloc.inner().provenance().ptrs().values().map(|p| p.alloc_id())
}
fn alloc_id_from_const_val(val: ConstValue<'_>) -> Option<AllocId> {
fn alloc_id_from_const_val(val: ConstValue) -> Option<AllocId> {
match val {
ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => Some(ptr.provenance.alloc_id()),
ConstValue::Scalar(interpret::Scalar::Int { .. }) => None,
ConstValue::ZeroSized => None,
ConstValue::Slice { .. } => {
// `u8`/`str` slices, shouldn't contain pointers that we want to print.
None
}
ConstValue::Indirect { alloc_id, .. } => {
ConstValue::Slice { alloc_id, .. } | ConstValue::Indirect { alloc_id, .. } => {
// FIXME: we don't actually want to print all of these, since some are printed nicely directly as values inline in MIR.
// Really we'd want `pretty_print_const_value` to decide which allocations to print, instead of having a separate visitor.
Some(alloc_id)
@ -1885,7 +1881,7 @@ fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Resul
fn comma_sep<'tcx>(
tcx: TyCtxt<'tcx>,
fmt: &mut Formatter<'_>,
elems: Vec<(ConstValue<'tcx>, Ty<'tcx>)>,
elems: Vec<(ConstValue, Ty<'tcx>)>,
) -> fmt::Result {
let mut first = true;
for (ct, ty) in elems {
@ -1900,7 +1896,7 @@ fn comma_sep<'tcx>(
fn pretty_print_const_value_tcx<'tcx>(
tcx: TyCtxt<'tcx>,
ct: ConstValue<'tcx>,
ct: ConstValue,
ty: Ty<'tcx>,
fmt: &mut Formatter<'_>,
) -> fmt::Result {
@ -1947,7 +1943,7 @@ fn pretty_print_const_value_tcx<'tcx>(
let ct = tcx.lift(ct).unwrap();
let ty = tcx.lift(ty).unwrap();
if let Some(contents) = tcx.try_destructure_mir_constant_for_user_output(ct, ty) {
let fields: Vec<(ConstValue<'_>, Ty<'_>)> = contents.fields.to_vec();
let fields: Vec<(ConstValue, Ty<'_>)> = contents.fields.to_vec();
match *ty.kind() {
ty::Array(..) => {
fmt.write_str("[")?;
@ -2028,7 +2024,7 @@ fn pretty_print_const_value_tcx<'tcx>(
}
pub(crate) fn pretty_print_const_value<'tcx>(
ct: ConstValue<'tcx>,
ct: ConstValue,
ty: Ty<'tcx>,
fmt: &mut Formatter<'_>,
) -> fmt::Result {

View file

@ -173,5 +173,5 @@ pub enum AnnotationSource {
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredConstant<'tcx> {
pub variant: Option<VariantIdx>,
pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)],
pub fields: &'tcx [(ConstValue, Ty<'tcx>)],
}

View file

@ -153,8 +153,8 @@ impl EraseType for Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled> {
type Result = [u8; size_of::<Result<mir::ConstAlloc<'static>, mir::interpret::ErrorHandled>>()];
}
impl EraseType for Result<mir::ConstValue<'_>, mir::interpret::ErrorHandled> {
type Result = [u8; size_of::<Result<mir::ConstValue<'static>, mir::interpret::ErrorHandled>>()];
impl EraseType for Result<mir::ConstValue, mir::interpret::ErrorHandled> {
type Result = [u8; size_of::<Result<mir::ConstValue, mir::interpret::ErrorHandled>>()];
}
impl EraseType for EvalToValTreeResult<'_> {
@ -301,6 +301,7 @@ trivial! {
rustc_middle::middle::resolve_bound_vars::ResolvedArg,
rustc_middle::middle::stability::DeprecationEntry,
rustc_middle::mir::ConstQualifs,
rustc_middle::mir::ConstValue,
rustc_middle::mir::interpret::AllocId,
rustc_middle::mir::interpret::CtfeProvenance,
rustc_middle::mir::interpret::ErrorHandled,
@ -362,7 +363,6 @@ tcx_lifetime! {
rustc_middle::mir::Const,
rustc_middle::mir::DestructuredConstant,
rustc_middle::mir::ConstAlloc,
rustc_middle::mir::ConstValue,
rustc_middle::mir::interpret::GlobalId,
rustc_middle::mir::interpret::LitToConstInput,
rustc_middle::mir::interpret::EvalStaticInitializerRawResult,

View file

@ -1363,7 +1363,7 @@ rustc_queries! {
}
/// Converts a type-level constant value into a MIR constant value.
query valtree_to_const_val(key: ty::Value<'tcx>) -> mir::ConstValue<'tcx> {
query valtree_to_const_val(key: ty::Value<'tcx>) -> mir::ConstValue {
desc { "converting type-level constant value to MIR constant value"}
}

View file

@ -5,7 +5,7 @@
pub mod tls;
use std::assert_matches::debug_assert_matches;
use std::borrow::Borrow;
use std::borrow::{Borrow, Cow};
use std::cmp::Ordering;
use std::env::VarError;
use std::ffi::OsStr;
@ -1625,7 +1625,11 @@ impl<'tcx> TyCtxt<'tcx> {
/// Allocates a read-only byte or string literal for `mir::interpret` with alignment 1.
/// Returns the same `AllocId` if called again with the same bytes.
pub fn allocate_bytes_dedup(self, bytes: &[u8], salt: usize) -> interpret::AllocId {
pub fn allocate_bytes_dedup<'a>(
self,
bytes: impl Into<Cow<'a, [u8]>>,
salt: usize,
) -> interpret::AllocId {
// Create an allocation that just contains these bytes.
let alloc = interpret::Allocation::from_bytes_byte_aligned_immutable(bytes, ());
let alloc = self.mk_const_alloc(alloc);

View file

@ -4,6 +4,7 @@
//! to help with the tedium.
use std::fmt::{self, Debug};
use std::marker::PhantomData;
use rustc_abi::TyAndLayout;
use rustc_hir::def::Namespace;
@ -234,6 +235,7 @@ TrivialLiftImpls! {
rustc_abi::ExternAbi,
rustc_abi::Size,
rustc_hir::Safety,
rustc_middle::mir::ConstValue,
rustc_type_ir::BoundConstness,
rustc_type_ir::PredicatePolarity,
// tidy-alphabetical-end
@ -250,7 +252,7 @@ TrivialTypeTraversalImpls! {
crate::mir::BlockTailInfo,
crate::mir::BorrowKind,
crate::mir::CastKind,
crate::mir::ConstValue<'tcx>,
crate::mir::ConstValue,
crate::mir::CoroutineSavedLocal,
crate::mir::FakeReadCause,
crate::mir::Local,
@ -311,6 +313,13 @@ TrivialTypeTraversalAndLiftImpls! {
///////////////////////////////////////////////////////////////////////////
// Lift implementations
impl<'tcx> Lift<TyCtxt<'tcx>> for PhantomData<&()> {
type Lifted = PhantomData<&'tcx ()>;
fn lift_to_interner(self, _: TyCtxt<'tcx>) -> Option<Self::Lifted> {
Some(PhantomData)
}
}
impl<'tcx, T: Lift<TyCtxt<'tcx>>> Lift<TyCtxt<'tcx>> for Option<T> {
type Lifted = Option<T::Lifted>;
fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {

View file

@ -3,7 +3,7 @@
use rustc_abi::Size;
use rustc_ast as ast;
use rustc_hir::LangItem;
use rustc_middle::mir::interpret::{Allocation, CTFE_ALLOC_SALT, LitToConstInput, Scalar};
use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, LitToConstInput, Scalar};
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::{
@ -120,17 +120,18 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>
let value = match (lit, lit_ty.kind()) {
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
let s = s.as_str();
let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes(), ());
let allocation = tcx.mk_const_alloc(allocation);
ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() }
let s = s.as_str().as_bytes();
let len = s.len();
let allocation = tcx.allocate_bytes_dedup(s, CTFE_ALLOC_SALT);
ConstValue::Slice { alloc_id: allocation, meta: len.try_into().unwrap() }
}
(ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _))
(ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _))
if matches!(inner_ty.kind(), ty::Slice(_)) =>
{
let allocation = Allocation::from_bytes_byte_aligned_immutable(data.as_byte_str(), ());
let allocation = tcx.mk_const_alloc(allocation);
ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() }
let data = byte_sym.as_byte_str();
let len = data.len();
let allocation = tcx.allocate_bytes_dedup(data, CTFE_ALLOC_SALT);
ConstValue::Slice { alloc_id: allocation, meta: len.try_into().unwrap() }
}
(ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
let id = tcx.allocate_bytes_dedup(byte_sym.as_byte_str(), CTFE_ALLOC_SALT);
@ -138,10 +139,10 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>
}
(ast::LitKind::CStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) =>
{
let allocation =
Allocation::from_bytes_byte_aligned_immutable(byte_sym.as_byte_str(), ());
let allocation = tcx.mk_const_alloc(allocation);
ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() }
let data = byte_sym.as_byte_str();
let len = data.len();
let allocation = tcx.allocate_bytes_dedup(data, CTFE_ALLOC_SALT);
ConstValue::Slice { alloc_id: allocation, meta: len.try_into().unwrap() }
}
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
ConstValue::Scalar(Scalar::from_uint(n, Size::from_bytes(1)))

View file

@ -1045,11 +1045,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
fn parse_float_into_constval<'tcx>(
num: Symbol,
float_ty: ty::FloatTy,
neg: bool,
) -> Option<ConstValue<'tcx>> {
fn parse_float_into_constval(num: Symbol, float_ty: ty::FloatTy, neg: bool) -> Option<ConstValue> {
parse_float_into_scalar(num, float_ty, neg).map(|s| ConstValue::Scalar(s.into()))
}

View file

@ -1542,7 +1542,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
fn op_to_prop_const<'tcx>(
ecx: &mut InterpCx<'tcx, DummyMachine>,
op: &OpTy<'tcx>,
) -> Option<ConstValue<'tcx>> {
) -> Option<ConstValue> {
// Do not attempt to propagate unsized locals.
if op.layout.is_unsized() {
return None;

View file

@ -659,10 +659,7 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
}
/// Evaluates a *not yet monomorphized* constant.
fn eval_constant(
&mut self,
constant: &mir::ConstOperand<'tcx>,
) -> Option<mir::ConstValue<'tcx>> {
fn eval_constant(&mut self, constant: &mir::ConstOperand<'tcx>) -> Option<mir::ConstValue> {
let const_ = self.monomorphize(constant.const_);
// Evaluate the constant. This makes const eval failure a collection-time error (rather than
// a codegen-time error). rustc stops after collection if there was an error, so this
@ -1355,19 +1352,15 @@ fn visit_mentioned_item<'tcx>(
#[instrument(skip(tcx, output), level = "debug")]
fn collect_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
value: mir::ConstValue<'tcx>,
value: mir::ConstValue,
output: &mut MonoItems<'tcx>,
) {
match value {
mir::ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => {
collect_alloc(tcx, ptr.provenance.alloc_id(), output)
}
mir::ConstValue::Indirect { alloc_id, .. } => collect_alloc(tcx, alloc_id, output),
mir::ConstValue::Slice { data, meta: _ } => {
for &prov in data.inner().provenance().ptrs().values() {
collect_alloc(tcx, prov.alloc_id(), output);
}
}
mir::ConstValue::Indirect { alloc_id, .. }
| mir::ConstValue::Slice { alloc_id, meta: _ } => collect_alloc(tcx, alloc_id, output),
_ => {}
}
}

View file

@ -33,7 +33,7 @@ fn new_empty_allocation(align: Align) -> Allocation {
#[allow(rustc::usage_of_qualified_ty)]
pub(crate) fn new_allocation<'tcx>(
ty: rustc_middle::ty::Ty<'tcx>,
const_value: ConstValue<'tcx>,
const_value: ConstValue,
tables: &mut Tables<'tcx, BridgeTys>,
cx: &CompilerCtxt<'tcx, BridgeTys>,
) -> Allocation {
@ -44,7 +44,7 @@ pub(crate) fn new_allocation<'tcx>(
#[allow(rustc::usage_of_qualified_ty)]
pub(crate) fn try_new_allocation<'tcx>(
ty: rustc_middle::ty::Ty<'tcx>,
const_value: ConstValue<'tcx>,
const_value: ConstValue,
tables: &mut Tables<'tcx, BridgeTys>,
cx: &CompilerCtxt<'tcx, BridgeTys>,
) -> Result<Allocation, Error> {
@ -54,8 +54,8 @@ pub(crate) fn try_new_allocation<'tcx>(
alloc::try_new_scalar(layout, scalar, cx).map(|alloc| alloc.stable(tables, cx))
}
ConstValue::ZeroSized => Ok(new_empty_allocation(layout.align.abi)),
ConstValue::Slice { data, meta } => {
alloc::try_new_slice(layout, data, meta, cx).map(|alloc| alloc.stable(tables, cx))
ConstValue::Slice { alloc_id, meta } => {
alloc::try_new_slice(layout, alloc_id, meta, cx).map(|alloc| alloc.stable(tables, cx))
}
ConstValue::Indirect { alloc_id, offset } => {
let alloc = alloc::try_new_indirect(alloc_id, cx);

View file

@ -38,11 +38,10 @@ pub fn try_new_scalar<'tcx, B: Bridge>(
pub fn try_new_slice<'tcx, B: Bridge>(
layout: TyAndLayout<'tcx, Ty<'tcx>>,
data: ConstAllocation<'tcx>,
alloc_id: AllocId,
meta: u64,
cx: &CompilerCtxt<'tcx, B>,
) -> Result<Allocation, B::Error> {
let alloc_id = cx.tcx.reserve_and_set_memory_alloc(data);
let ptr = Pointer::new(alloc_id.into(), Size::ZERO);
let scalar_ptr = Scalar::from_pointer(ptr, &cx.tcx);
let scalar_meta: Scalar = Scalar::from_target_usize(meta, &cx.tcx);

View file

@ -63,7 +63,7 @@ impl<'tcx, B: Bridge> CompilerCtxt<'tcx, B> {
self.tcx.coroutine_movability(def_id)
}
pub fn valtree_to_const_val(&self, key: ty::Value<'tcx>) -> ConstValue<'tcx> {
pub fn valtree_to_const_val(&self, key: ty::Value<'tcx>) -> ConstValue {
self.tcx.valtree_to_const_val(key)
}
@ -675,10 +675,7 @@ impl<'tcx, B: Bridge> CompilerCtxt<'tcx, B> {
}
/// Try to evaluate an instance into a constant.
pub fn eval_instance(
&self,
instance: ty::Instance<'tcx>,
) -> Result<ConstValue<'tcx>, ErrorHandled> {
pub fn eval_instance(&self, instance: ty::Instance<'tcx>) -> Result<ConstValue, ErrorHandled> {
self.tcx.const_eval_instance(
self.fully_monomorphized(),
instance,

View file

@ -338,7 +338,7 @@ impl<'tcx> NonCopyConst<'tcx> {
tcx: TyCtxt<'tcx>,
typing_env: TypingEnv<'tcx>,
ty: Ty<'tcx>,
val: ConstValue<'tcx>,
val: ConstValue,
) -> Result<bool, ()> {
let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
match self.is_ty_freeze(tcx, typing_env, ty) {
@ -477,7 +477,7 @@ impl<'tcx> NonCopyConst<'tcx> {
typing_env: TypingEnv<'tcx>,
typeck: &'tcx TypeckResults<'tcx>,
mut src_expr: &'tcx Expr<'tcx>,
mut val: ConstValue<'tcx>,
mut val: ConstValue,
) -> Result<Option<BorrowSource<'tcx>>, ()> {
let mut parents = tcx.hir_parent_iter(src_expr.hir_id);
let mut ty = typeck.expr_ty(src_expr);

View file

@ -4,7 +4,6 @@
use std::any::Any;
use std::borrow::Cow;
use std::cell::{Cell, RefCell};
use std::collections::hash_map::Entry;
use std::path::Path;
use std::rc::Rc;
use std::{fmt, process};
@ -70,12 +69,6 @@ pub struct FrameExtra<'tcx> {
/// This is used by `MiriMachine::current_span` and `MiriMachine::caller_span`
pub is_user_relevant: bool,
/// We have a cache for the mapping from [`mir::Const`] to resulting [`AllocId`].
/// However, we don't want all frames to always get the same result, so we insert
/// an additional bit of "salt" into the cache key. This salt is fixed per-frame
/// so that within a call, a const will have a stable address.
salt: usize,
/// Data race detector per-frame data.
pub data_race: Option<data_race::FrameState>,
}
@ -88,14 +81,12 @@ impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> {
catch_unwind,
timing: _,
is_user_relevant,
salt,
data_race,
} = self;
f.debug_struct("FrameData")
.field("borrow_tracker", borrow_tracker)
.field("catch_unwind", catch_unwind)
.field("is_user_relevant", is_user_relevant)
.field("salt", salt)
.field("data_race", data_race)
.finish()
}
@ -108,7 +99,6 @@ impl VisitProvenance for FrameExtra<'_> {
borrow_tracker,
timing: _,
is_user_relevant: _,
salt: _,
data_race: _,
} = self;
@ -578,11 +568,6 @@ pub struct MiriMachine<'tcx> {
/// diagnostics.
pub(crate) allocation_spans: RefCell<FxHashMap<AllocId, (Span, Option<Span>)>>,
/// Maps MIR consts to their evaluated result. We combine the const with a "salt" (`usize`)
/// that is fixed per stack frame; this lets us have sometimes different results for the
/// same const while ensuring consistent results within a single call.
const_cache: RefCell<FxHashMap<(mir::Const<'tcx>, usize), OpTy<'tcx>>>,
/// For each allocation, an offset inside that allocation that was deemed aligned even for
/// symbolic alignment checks. This cannot be stored in `AllocExtra` since it needs to be
/// tracked for vtables and function allocations as well as regular allocations.
@ -764,7 +749,6 @@ impl<'tcx> MiriMachine<'tcx> {
stack_size,
collect_leak_backtraces: config.collect_leak_backtraces,
allocation_spans: RefCell::new(FxHashMap::default()),
const_cache: RefCell::new(FxHashMap::default()),
symbolic_alignment: RefCell::new(FxHashMap::default()),
union_data_ranges: FxHashMap::default(),
pthread_mutex_sanity: Cell::new(false),
@ -941,7 +925,6 @@ impl VisitProvenance for MiriMachine<'_> {
stack_size: _,
collect_leak_backtraces: _,
allocation_spans: _,
const_cache: _,
symbolic_alignment: _,
union_data_ranges: _,
pthread_mutex_sanity: _,
@ -1578,7 +1561,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
catch_unwind: None,
timing,
is_user_relevant: ecx.machine.is_user_relevant(&frame),
salt: ecx.machine.rng.borrow_mut().random_range(0..ADDRS_PER_ANON_GLOBAL),
data_race: ecx
.machine
.data_race
@ -1737,33 +1719,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
interp_ok(())
}
fn eval_mir_constant<F>(
ecx: &InterpCx<'tcx, Self>,
val: mir::Const<'tcx>,
span: Span,
layout: Option<TyAndLayout<'tcx>>,
eval: F,
) -> InterpResult<'tcx, OpTy<'tcx>>
where
F: Fn(
&InterpCx<'tcx, Self>,
mir::Const<'tcx>,
Span,
Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx>>,
{
let frame = ecx.active_thread_stack().last().unwrap();
let mut cache = ecx.machine.const_cache.borrow_mut();
match cache.entry((val, frame.extra.salt)) {
Entry::Vacant(ve) => {
let op = eval(ecx, val, span, layout)?;
ve.insert(op.clone());
interp_ok(op)
}
Entry::Occupied(oe) => interp_ok(oe.get().clone()),
}
}
fn get_global_alloc_salt(
ecx: &InterpCx<'tcx, Self>,
instance: Option<ty::Instance<'tcx>>,

View file

@ -1,14 +1,10 @@
// The const fn interpreter creates a new AllocId every time it evaluates any const.
// If we do that in Miri, repeatedly evaluating a const causes unbounded memory use
// we need to keep track of the base address for that AllocId, and the allocation is never
// deallocated.
// In Miri we explicitly store previously-assigned AllocIds for each const and ensure
// that we only hand out a finite number of AllocIds per const.
// MIR inlining will put every evaluation of the const we're repeatedly evaluating into the same
// stack frame, breaking this test.
// The interpreter used to create a new AllocId every time it evaluates any const.
// This caused unbounded memory use in Miri.
// This test verifies that we only create a bounded amount of addresses for any given const.
// In practice, the interpreter always returns the same address, but we *do not guarantee* that.
//@compile-flags: -Zinline-mir=no
const EVALS: usize = 256;
const EVALS: usize = 64;
use std::collections::HashSet;
fn main() {
@ -16,10 +12,8 @@ fn main() {
for _ in 0..EVALS {
addrs.insert(const_addr());
}
// Check that the const allocation has multiple base addresses
assert!(addrs.len() > 1);
// But also that we get a limited number of unique base addresses
assert!(addrs.len() < EVALS);
// Check that we always return the same base address for the const allocation.
assert_eq!(addrs.len(), 1);
// Check that within a call we always produce the same address
let mut prev = 0;

View file

@ -71,3 +71,7 @@ fn main() -> () {
resume;
}
}
ALLOC0 (size: 14, align: 1) {
65 78 70 6c 69 63 69 74 20 70 61 6e 69 63 explicit panic
}

View file

@ -198,3 +198,7 @@ static XXX: &Foo = {
return;
}
}
ALLOC0 (size: 2, align: 1) {
68 69 hi
}

View file

@ -78,3 +78,9 @@ fn let_else() -> () {
resume;
}
}
ALLOC0 (size: 40, align: 1) {
0x00 69 6e 74 65 72 6e 61 6c 20 65 72 72 6f 72 3a 20 internal error:
0x10 65 6e 74 65 72 65 64 20 75 6e 72 65 61 63 68 61 entered unreacha
0x20 62 6c 65 20 63 6f 64 65 ble code
}

View file

@ -60,3 +60,9 @@ fn let_else_bindless() -> () {
resume;
}
}
ALLOC0 (size: 40, align: 1) {
0x00 69 6e 74 65 72 6e 61 6c 20 65 72 72 6f 72 3a 20 internal error:
0x10 65 6e 74 65 72 65 64 20 75 6e 72 65 61 63 68 61 entered unreacha
0x20 62 6c 65 20 63 6f 64 65 ble code
}

View file

@ -123,3 +123,5 @@
ALLOC1 (size: 4, align: 2) { .. }
ALLOC2 (size: 13, align: 1) { .. }

View file

@ -24,3 +24,7 @@
}
}
ALLOC0 (size: 14, align: 1) {
65 78 70 6c 69 63 69 74 20 70 61 6e 69 63 │ explicit panic
}

View file

@ -24,3 +24,7 @@
}
}
ALLOC0 (size: 14, align: 1) {
65 78 70 6c 69 63 69 74 20 70 61 6e 69 63 │ explicit panic
}

View file

@ -17,3 +17,11 @@
}
}
ALLOC0 (size: 5, align: 1) {
57 6f 72 6c 64 │ World
}
ALLOC1 (size: 5, align: 1) {
48 65 6c 6c 6f │ Hello
}

View file

@ -16,23 +16,31 @@
bb0: {
_7 = (const "a",);
_1 = copy (_7.0: &str) as u128 (Transmute);
_5 = identity::<&str>(copy (_7.0: &str)) -> [return: bb1, unwind unreachable];
- _1 = copy (_7.0: &str) as u128 (Transmute);
- _5 = identity::<&str>(copy (_7.0: &str)) -> [return: bb1, unwind unreachable];
+ _1 = const "a" as u128 (Transmute);
+ _5 = identity::<&str>(const "a") -> [return: bb1, unwind unreachable];
}
bb1: {
_3 = copy _5 as u128 (Transmute);
_8 = const "a";
_2 = copy _8 as u128 (Transmute);
_6 = identity::<&str>(copy _8) -> [return: bb2, unwind unreachable];
- _2 = copy _8 as u128 (Transmute);
- _6 = identity::<&str>(copy _8) -> [return: bb2, unwind unreachable];
+ _2 = copy _1;
+ _6 = identity::<&str>(const "a") -> [return: bb2, unwind unreachable];
}
bb2: {
_4 = copy _6 as u128 (Transmute);
_9 = Eq(copy _1, copy _2);
- _9 = Eq(copy _1, copy _2);
+ _9 = const true;
_10 = Eq(copy _3, copy _4);
_0 = (copy _9, copy _10);
- _0 = (copy _9, copy _10);
+ _0 = (const true, copy _10);
return;
}
}
ALLOC0 (size: 1, align: 1) { .. }

View file

@ -16,23 +16,31 @@
bb0: {
_7 = (const "a",);
_1 = copy (_7.0: &str) as u128 (Transmute);
_5 = identity::<&str>(copy (_7.0: &str)) -> [return: bb1, unwind continue];
- _1 = copy (_7.0: &str) as u128 (Transmute);
- _5 = identity::<&str>(copy (_7.0: &str)) -> [return: bb1, unwind continue];
+ _1 = const "a" as u128 (Transmute);
+ _5 = identity::<&str>(const "a") -> [return: bb1, unwind continue];
}
bb1: {
_3 = copy _5 as u128 (Transmute);
_8 = const "a";
_2 = copy _8 as u128 (Transmute);
_6 = identity::<&str>(copy _8) -> [return: bb2, unwind continue];
- _2 = copy _8 as u128 (Transmute);
- _6 = identity::<&str>(copy _8) -> [return: bb2, unwind continue];
+ _2 = copy _1;
+ _6 = identity::<&str>(const "a") -> [return: bb2, unwind continue];
}
bb2: {
_4 = copy _6 as u128 (Transmute);
_9 = Eq(copy _1, copy _2);
- _9 = Eq(copy _1, copy _2);
+ _9 = const true;
_10 = Eq(copy _3, copy _4);
_0 = (copy _9, copy _10);
- _0 = (copy _9, copy _10);
+ _0 = (const true, copy _10);
return;
}
}
ALLOC0 (size: 1, align: 1) { .. }

View file

@ -8,10 +8,10 @@
let mut _3: fn(u8) -> u8;
let _5: ();
let mut _6: fn(u8) -> u8;
let mut _9: {closure@$DIR/gvn.rs:620:19: 620:21};
let mut _9: {closure@$DIR/gvn.rs:617:19: 617:21};
let _10: ();
let mut _11: fn();
let mut _13: {closure@$DIR/gvn.rs:620:19: 620:21};
let mut _13: {closure@$DIR/gvn.rs:617:19: 617:21};
let _14: ();
let mut _15: fn();
scope 1 {
@ -19,7 +19,7 @@
let _4: fn(u8) -> u8;
scope 2 {
debug g => _4;
let _7: {closure@$DIR/gvn.rs:620:19: 620:21};
let _7: {closure@$DIR/gvn.rs:617:19: 617:21};
scope 3 {
debug closure => _7;
let _8: fn();
@ -62,16 +62,16 @@
StorageDead(_6);
StorageDead(_5);
- StorageLive(_7);
- _7 = {closure@$DIR/gvn.rs:620:19: 620:21};
- _7 = {closure@$DIR/gvn.rs:617:19: 617:21};
- StorageLive(_8);
+ nop;
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21};
+ nop;
StorageLive(_9);
- _9 = copy _7;
- _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21};
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
StorageDead(_9);
StorageLive(_10);
StorageLive(_11);
@ -88,8 +88,8 @@
StorageLive(_13);
- _13 = copy _7;
- _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21};
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
StorageDead(_13);
StorageLive(_14);
StorageLive(_15);

View file

@ -8,10 +8,10 @@
let mut _3: fn(u8) -> u8;
let _5: ();
let mut _6: fn(u8) -> u8;
let mut _9: {closure@$DIR/gvn.rs:620:19: 620:21};
let mut _9: {closure@$DIR/gvn.rs:617:19: 617:21};
let _10: ();
let mut _11: fn();
let mut _13: {closure@$DIR/gvn.rs:620:19: 620:21};
let mut _13: {closure@$DIR/gvn.rs:617:19: 617:21};
let _14: ();
let mut _15: fn();
scope 1 {
@ -19,7 +19,7 @@
let _4: fn(u8) -> u8;
scope 2 {
debug g => _4;
let _7: {closure@$DIR/gvn.rs:620:19: 620:21};
let _7: {closure@$DIR/gvn.rs:617:19: 617:21};
scope 3 {
debug closure => _7;
let _8: fn();
@ -62,16 +62,16 @@
StorageDead(_6);
StorageDead(_5);
- StorageLive(_7);
- _7 = {closure@$DIR/gvn.rs:620:19: 620:21};
- _7 = {closure@$DIR/gvn.rs:617:19: 617:21};
- StorageLive(_8);
+ nop;
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21};
+ nop;
StorageLive(_9);
- _9 = copy _7;
- _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21};
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
StorageDead(_9);
StorageLive(_10);
StorageLive(_11);
@ -88,8 +88,8 @@
StorageLive(_13);
- _13 = copy _7;
- _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21};
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:617:19: 617:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
StorageDead(_13);
StorageLive(_14);
StorageLive(_15);

View file

@ -533,10 +533,10 @@ fn dereferences(t: &mut u32, u: &impl Copy, s: &S<u32>) {
fn slices() {
// CHECK-LABEL: fn slices(
// CHECK: {{_.*}} = const "
// CHECK-NOT: {{_.*}} = const "
let s = "my favourite slice"; // This is a `Const::Slice` in MIR.
// CHECK: {{_.*}} = const "
let s = "my favourite slice";
opaque(s);
let t = s; // This should be the same pointer, so cannot be a `Const::Slice`.
let t = s; // This should be the same pointer.
opaque(t);
assert_eq!(s.as_ptr(), t.as_ptr());
let u = unsafe { transmute::<&str, &[u8]>(s) };
@ -556,12 +556,12 @@ fn duplicate_slice() -> (bool, bool) {
let d: &str;
{
// CHECK: [[a:_.*]] = (const "a",);
// CHECK: [[au:_.*]] = copy ([[a]].0: &str) as u128 (Transmute);
// CHECK: [[au:_.*]] = const "a" as u128 (Transmute);
let a = ("a",);
Call(au = transmute::<_, u128>(a.0), ReturnTo(bb1), UnwindContinue())
}
bb1 = {
// CHECK: [[c:_.*]] = identity::<&str>(copy ([[a]].0: &str))
// CHECK: [[c:_.*]] = identity::<&str>(const "a")
Call(c = identity(a.0), ReturnTo(bb2), UnwindContinue())
}
bb2 = {
@ -569,15 +569,13 @@ fn duplicate_slice() -> (bool, bool) {
Call(cu = transmute::<_, u128>(c), ReturnTo(bb3), UnwindContinue())
}
bb3 = {
// This slice is different from `a.0`. Hence `bu` is not `au`.
// CHECK: [[b:_.*]] = const "a";
// CHECK: [[bu:_.*]] = copy [[b]] as u128 (Transmute);
// CHECK: [[bu:_.*]] = copy [[au]];
let b = "a";
Call(bu = transmute::<_, u128>(b), ReturnTo(bb4), UnwindContinue())
}
bb4 = {
// This returns a copy of `b`, which is not `a`.
// CHECK: [[d:_.*]] = identity::<&str>(copy [[b]])
// CHECK: [[d:_.*]] = identity::<&str>(const "a")
Call(d = identity(b), ReturnTo(bb5), UnwindContinue())
}
bb5 = {
@ -585,8 +583,7 @@ fn duplicate_slice() -> (bool, bool) {
Call(du = transmute::<_, u128>(d), ReturnTo(bb6), UnwindContinue())
}
bb6 = {
// `direct` must not fold to `true`, as `indirect` will not.
// CHECK: = Eq(copy [[au]], copy [[bu]]);
// CHECK: = const true;
// CHECK: = Eq(copy [[cu]], copy [[du]]);
let direct = au == bu;
let indirect = cu == du;

View file

@ -87,22 +87,24 @@
_1 = const "my favourite slice";
StorageLive(_2);
StorageLive(_3);
_3 = copy _1;
- _3 = copy _1;
- _2 = opaque::<&str>(move _3) -> [return: bb1, unwind unreachable];
+ _2 = opaque::<&str>(copy _1) -> [return: bb1, unwind unreachable];
+ _3 = const "my favourite slice";
+ _2 = opaque::<&str>(const "my favourite slice") -> [return: bb1, unwind unreachable];
}
bb1: {
StorageDead(_3);
StorageDead(_2);
StorageLive(_4);
_4 = copy _1;
- _4 = copy _1;
+ _4 = const "my favourite slice";
StorageLive(_5);
StorageLive(_6);
- _6 = copy _4;
- _5 = opaque::<&str>(move _6) -> [return: bb2, unwind unreachable];
+ _6 = copy _1;
+ _5 = opaque::<&str>(copy _1) -> [return: bb2, unwind unreachable];
+ _6 = const "my favourite slice";
+ _5 = opaque::<&str>(const "my favourite slice") -> [return: bb2, unwind unreachable];
}
bb2: {
@ -315,3 +317,5 @@
}
}
ALLOC0 (size: 18, align: 1) { .. }

View file

@ -87,22 +87,24 @@
_1 = const "my favourite slice";
StorageLive(_2);
StorageLive(_3);
_3 = copy _1;
- _3 = copy _1;
- _2 = opaque::<&str>(move _3) -> [return: bb1, unwind continue];
+ _2 = opaque::<&str>(copy _1) -> [return: bb1, unwind continue];
+ _3 = const "my favourite slice";
+ _2 = opaque::<&str>(const "my favourite slice") -> [return: bb1, unwind continue];
}
bb1: {
StorageDead(_3);
StorageDead(_2);
StorageLive(_4);
_4 = copy _1;
- _4 = copy _1;
+ _4 = const "my favourite slice";
StorageLive(_5);
StorageLive(_6);
- _6 = copy _4;
- _5 = opaque::<&str>(move _6) -> [return: bb2, unwind continue];
+ _6 = copy _1;
+ _5 = opaque::<&str>(copy _1) -> [return: bb2, unwind continue];
+ _6 = const "my favourite slice";
+ _5 = opaque::<&str>(const "my favourite slice") -> [return: bb2, unwind continue];
}
bb2: {
@ -315,3 +317,5 @@
}
}
ALLOC0 (size: 18, align: 1) { .. }

View file

@ -47,3 +47,5 @@
}
}
ALLOC0 (size: 14, align: 1) { .. }

View file

@ -47,3 +47,5 @@
}
}
ALLOC0 (size: 14, align: 1) { .. }

View file

@ -38,5 +38,9 @@
+ StorageLive(_7);
+ _7 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable;
}
+ }
+
+ ALLOC0 (size: 14, align: 1) {
+ 65 78 70 6c 69 63 69 74 20 70 61 6e 69 63 │ explicit panic
}

View file

@ -38,5 +38,9 @@
+ StorageLive(_7);
+ _7 = begin_panic::<&str>(const "explicit panic") -> unwind continue;
}
+ }
+
+ ALLOC0 (size: 14, align: 1) {
+ 65 78 70 6c 69 63 69 74 20 70 61 6e 69 63 │ explicit panic
}

View file

@ -251,7 +251,7 @@
+ StorageLive(_50);
+ _50 = discriminant(_43);
+ switchInt(move _50) -> [0: bb11, 1: bb12, otherwise: bb5];
+ }
}
+
+ bb5: {
+ unreachable;
@ -329,6 +329,11 @@
+ StorageDead(_19);
+ _25 = discriminant(_18);
+ switchInt(move _25) -> [0: bb7, 1: bb6, otherwise: bb5];
}
+ }
+ }
+
+ ALLOC0 (size: 31, align: 1) {
+ 0x00 │ 60 52 65 61 64 79 60 20 70 6f 6c 6c 65 64 20 61 │ `Ready` polled a
+ 0x10 │ 66 74 65 72 20 63 6f 6d 70 6c 65 74 69 6f 6e │ fter completion
}

View file

@ -274,7 +274,7 @@
- resume;
+ bb7: {
+ unreachable;
+ }
}
+
+ bb8: {
+ _17 = const ();
@ -370,6 +370,11 @@
+ StorageDead(_19);
+ _25 = discriminant(_18);
+ switchInt(move _25) -> [0: bb9, 1: bb8, otherwise: bb7];
}
+ }
+ }
+
+ ALLOC0 (size: 31, align: 1) {
+ 0x00 │ 60 52 65 61 64 79 60 20 70 6f 6c 6c 65 64 20 61 │ `Ready` polled a
+ 0x10 │ 66 74 65 72 20 63 6f 6d 70 6c 65 74 69 6f 6e │ fter completion
}

View file

@ -11,3 +11,7 @@
}
}
ALLOC0 (size: 1, align: 1) {
61 │ a
}

View file

@ -51,3 +51,9 @@
}
}
ALLOC0 (size: 40, align: 1) {
0x00 │ 69 6e 74 65 72 6e 61 6c 20 65 72 72 6f 72 3a 20 │ internal error:
0x10 │ 65 6e 74 65 72 65 64 20 75 6e 72 65 61 63 68 61 │ entered unreacha
0x20 │ 62 6c 65 20 63 6f 64 65 │ ble code
}

View file

@ -51,3 +51,9 @@
}
}
ALLOC0 (size: 40, align: 1) {
0x00 │ 69 6e 74 65 72 6e 61 6c 20 65 72 72 6f 72 3a 20 │ internal error:
0x10 │ 65 6e 74 65 72 65 64 20 75 6e 72 65 61 63 68 61 │ entered unreacha
0x20 │ 62 6c 65 20 63 6f 64 65 │ ble code
}

View file

@ -36,3 +36,7 @@ fn unwrap(_1: Option<T>) -> T {
return;
}
}
ALLOC0 (size: 14, align: 1) {
65 78 70 6c 69 63 69 74 20 70 61 6e 69 63 explicit panic
}

View file

@ -41,3 +41,7 @@ fn unwrap(_1: Option<T>) -> T {
resume;
}
}
ALLOC0 (size: 14, align: 1) {
65 78 70 6c 69 63 69 74 20 70 61 6e 69 63 explicit panic
}

View file

@ -38,3 +38,5 @@ fn main() -> () {
resume;
}
}
ALLOC0 (size: 0, align: 1) {}

View file

@ -38,3 +38,5 @@ fn main() -> () {
resume;
}
}
ALLOC0 (size: 0, align: 1) {}

View file

@ -110,9 +110,16 @@
+ nop;
return;
}
+ }
+
+ ALLOC0 (size: 8, align: 4) {
+ 00 00 00 00 __ __ __ __ │ ....░░░░
}
- ALLOC0 (size: 43, align: 1) {
+ ALLOC0 (size: 8, align: 4) {
+ 00 00 00 00 __ __ __ __ │ ....░░░░
+ }
+
+ ALLOC1 (size: 43, align: 1) {
0x00 │ 63 61 6c 6c 65 64 20 60 52 65 73 75 6c 74 3a 3a │ called `Result::
0x10 │ 75 6e 77 72 61 70 28 29 60 20 6f 6e 20 61 6e 20 │ unwrap()` on an
0x20 │ 60 45 72 72 60 20 76 61 6c 75 65 │ `Err` value
}

View file

@ -110,9 +110,16 @@
+ nop;
return;
}
+ }
+
+ ALLOC0 (size: 16, align: 8) {
+ 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░
}
- ALLOC0 (size: 43, align: 1) {
+ ALLOC0 (size: 16, align: 8) {
+ 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░
+ }
+
+ ALLOC1 (size: 43, align: 1) {
0x00 │ 63 61 6c 6c 65 64 20 60 52 65 73 75 6c 74 3a 3a │ called `Result::
0x10 │ 75 6e 77 72 61 70 28 29 60 20 6f 6e 20 61 6e 20 │ unwrap()` on an
0x20 │ 60 45 72 72 60 20 76 61 6c 75 65 │ `Err` value
}

View file

@ -34,3 +34,15 @@
}
}
ALLOC0 (size: 5, align: 1) {
77 6f 72 6c 64 │ world
}
ALLOC1 (size: 5, align: 1) {
74 6f 77 65 6c │ towel
}
ALLOC2 (size: 5, align: 1) {
68 65 6c 6c 6f │ hello
}

View file

@ -34,3 +34,15 @@
}
}
ALLOC0 (size: 5, align: 1) {
77 6f 72 6c 64 │ world
}
ALLOC1 (size: 5, align: 1) {
74 6f 77 65 6c │ towel
}
ALLOC2 (size: 5, align: 1) {
68 65 6c 6c 6f │ hello
}

View file

@ -45,3 +45,15 @@
}
}
ALLOC0 (size: 5, align: 1) {
77 6f 72 6c 64 │ world
}
ALLOC1 (size: 5, align: 1) {
74 6f 77 65 6c │ towel
}
ALLOC2 (size: 5, align: 1) {
68 65 6c 6c 6f │ hello
}

View file

@ -45,3 +45,15 @@
}
}
ALLOC0 (size: 5, align: 1) {
77 6f 72 6c 64 │ world
}
ALLOC1 (size: 5, align: 1) {
74 6f 77 65 6c │ towel
}
ALLOC2 (size: 5, align: 1) {
68 65 6c 6c 6f │ hello
}

View file

@ -75,3 +75,7 @@
}
}
ALLOC0 (size: 1, align: 1) {
61 │ a
}

View file

@ -113,3 +113,19 @@
}
}
ALLOC0 (size: 1, align: 1) {
44 │ D
}
ALLOC1 (size: 1, align: 1) {
43 │ C
}
ALLOC2 (size: 8, align: 1) {
42 28 45 6d 70 74 79 29 │ B(Empty)
}
ALLOC3 (size: 8, align: 1) {
41 28 45 6d 70 74 79 29 │ A(Empty)
}

View file

@ -113,3 +113,19 @@
}
}
ALLOC0 (size: 1, align: 1) {
44 │ D
}
ALLOC1 (size: 1, align: 1) {
43 │ C
}
ALLOC2 (size: 8, align: 1) {
42 28 45 6d 70 74 79 29 │ B(Empty)
}
ALLOC3 (size: 8, align: 1) {
41 28 45 6d 70 74 79 29 │ A(Empty)
}

View file

@ -41,3 +41,11 @@
}
}
ALLOC0 (size: 1, align: 1) {
45 │ E
}
ALLOC1 (size: 1, align: 1) {
44 │ D
}

View file

@ -41,3 +41,11 @@
}
}
ALLOC0 (size: 1, align: 1) {
45 │ E
}
ALLOC1 (size: 1, align: 1) {
44 │ D
}

View file

@ -51,3 +51,15 @@
}
}
ALLOC0 (size: 1, align: 1) {
43 │ C
}
ALLOC1 (size: 8, align: 1) {
42 28 45 6d 70 74 79 29 │ B(Empty)
}
ALLOC2 (size: 8, align: 1) {
41 28 45 6d 70 74 79 29 │ A(Empty)
}

View file

@ -51,3 +51,15 @@
}
}
ALLOC0 (size: 1, align: 1) {
43 │ C
}
ALLOC1 (size: 8, align: 1) {
42 28 45 6d 70 74 79 29 │ B(Empty)
}
ALLOC2 (size: 8, align: 1) {
41 28 45 6d 70 74 79 29 │ A(Empty)
}

View file

@ -42,3 +42,11 @@
}
}
ALLOC0 (size: 1, align: 1) {
45 │ E
}
ALLOC1 (size: 1, align: 1) {
44 │ D
}

View file

@ -42,3 +42,11 @@
}
}
ALLOC0 (size: 1, align: 1) {
45 │ E
}
ALLOC1 (size: 1, align: 1) {
44 │ D
}

View file

@ -51,3 +51,15 @@
}
}
ALLOC0 (size: 1, align: 1) {
43 │ C
}
ALLOC1 (size: 8, align: 1) {
42 28 45 6d 70 74 79 29 │ B(Empty)
}
ALLOC2 (size: 8, align: 1) {
41 28 45 6d 70 74 79 29 │ A(Empty)
}

View file

@ -51,3 +51,15 @@
}
}
ALLOC0 (size: 1, align: 1) {
43 │ C
}
ALLOC1 (size: 8, align: 1) {
42 28 45 6d 70 74 79 29 │ B(Empty)
}
ALLOC2 (size: 8, align: 1) {
41 28 45 6d 70 74 79 29 │ A(Empty)
}

View file

@ -46,3 +46,15 @@
}
}
ALLOC0 (size: 2, align: 1) {
43 44 │ CD
}
ALLOC1 (size: 6, align: 1) {
42 28 69 33 32 29 │ B(i32)
}
ALLOC2 (size: 6, align: 1) {
41 28 69 33 32 29 │ A(i32)
}

View file

@ -46,3 +46,15 @@
}
}
ALLOC0 (size: 2, align: 1) {
43 44 │ CD
}
ALLOC1 (size: 6, align: 1) {
42 28 69 33 32 29 │ B(i32)
}
ALLOC2 (size: 6, align: 1) {
41 28 69 33 32 29 │ A(i32)
}

View file

@ -60,3 +60,19 @@
}
}
ALLOC0 (size: 6, align: 1) {
42 28 69 33 32 29 │ B(i32)
}
ALLOC1 (size: 6, align: 1) {
41 28 69 33 32 29 │ A(i32)
}
ALLOC2 (size: 1, align: 1) {
44 │ D
}
ALLOC3 (size: 1, align: 1) {
43 │ C
}

View file

@ -60,3 +60,19 @@
}
}
ALLOC0 (size: 6, align: 1) {
42 28 69 33 32 29 │ B(i32)
}
ALLOC1 (size: 6, align: 1) {
41 28 69 33 32 29 │ A(i32)
}
ALLOC2 (size: 1, align: 1) {
44 │ D
}
ALLOC3 (size: 1, align: 1) {
43 │ C
}

View file

@ -73,3 +73,23 @@
}
}
ALLOC0 (size: 9, align: 1) {
41 28 6f 74 68 65 72 29 44 │ A(other)D
}
ALLOC1 (size: 4, align: 1) {
41 28 32 29 │ A(2)
}
ALLOC2 (size: 4, align: 1) {
41 28 31 29 │ A(1)
}
ALLOC3 (size: 6, align: 1) {
42 28 69 33 32 29 │ B(i32)
}
ALLOC4 (size: 1, align: 1) {
43 │ C
}

View file

@ -73,3 +73,23 @@
}
}
ALLOC0 (size: 9, align: 1) {
41 28 6f 74 68 65 72 29 44 │ A(other)D
}
ALLOC1 (size: 4, align: 1) {
41 28 32 29 │ A(2)
}
ALLOC2 (size: 4, align: 1) {
41 28 31 29 │ A(1)
}
ALLOC3 (size: 6, align: 1) {
42 28 69 33 32 29 │ B(i32)
}
ALLOC4 (size: 1, align: 1) {
43 │ C
}

View file

@ -64,3 +64,19 @@
}
}
ALLOC0 (size: 4, align: 1) {
42 28 54 29 │ B(T)
}
ALLOC1 (size: 4, align: 1) {
41 28 54 29 │ A(T)
}
ALLOC2 (size: 1, align: 1) {
44 │ D
}
ALLOC3 (size: 1, align: 1) {
43 │ C
}

View file

@ -68,3 +68,19 @@
}
}
ALLOC0 (size: 4, align: 1) {
42 28 54 29 │ B(T)
}
ALLOC1 (size: 4, align: 1) {
41 28 54 29 │ A(T)
}
ALLOC2 (size: 1, align: 1) {
44 │ D
}
ALLOC3 (size: 1, align: 1) {
43 │ C
}

View file

@ -51,3 +51,15 @@
}
}
ALLOC0 (size: 1, align: 1) {
43 │ C
}
ALLOC1 (size: 8, align: 1) {
42 28 45 6d 70 74 79 29 │ B(Empty)
}
ALLOC2 (size: 8, align: 1) {
41 28 45 6d 70 74 79 29 │ A(Empty)
}

View file

@ -51,3 +51,15 @@
}
}
ALLOC0 (size: 1, align: 1) {
43 │ C
}
ALLOC1 (size: 8, align: 1) {
42 28 45 6d 70 74 79 29 │ B(Empty)
}
ALLOC2 (size: 8, align: 1) {
41 28 45 6d 70 74 79 29 │ A(Empty)
}