summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/const_eval
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_const_eval/src/const_eval
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_const_eval/src/const_eval')
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs9
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs18
-rw-r--r--compiler/rustc_const_eval/src/const_eval/fn_queries.rs15
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs71
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs10
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs202
6 files changed, 119 insertions, 206 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 7890d878d..d39a7e8a1 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -138,7 +138,10 @@ where
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
ErrorHandled::TooGeneric
}
- err_inval!(AlreadyReported(error_reported)) => ErrorHandled::Reported(error_reported),
+ err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar),
+ err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
+ ErrorHandled::Reported(guar.into())
+ }
err_inval!(Layout(layout_error @ LayoutError::SizeOverflow(_))) => {
// We must *always* hard error on these, even if the caller wants just a lint.
// The `message` makes little sense here, this is a more serious error than the
@@ -150,8 +153,8 @@ where
tcx.sess.create_err(Spanned { span, node: layout_error.into_diagnostic() });
err.code(rustc_errors::error_code!(E0080));
let Some((mut err, handler)) = err.into_diagnostic() else {
- panic!("did not emit diag");
- };
+ panic!("did not emit diag");
+ };
for frame in frames {
err.eager_subdiagnostic(handler, frame);
}
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 417ab78fd..4c7e91944 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -45,20 +45,20 @@ fn eval_body_using_ecx<'mir, 'tcx>(
"Unexpected DefKind: {:?}",
ecx.tcx.def_kind(cid.instance.def_id())
);
- let layout = ecx.layout_of(body.bound_return_ty().subst(tcx, cid.instance.substs))?;
+ let layout = ecx.layout_of(body.bound_return_ty().instantiate(tcx, cid.instance.args))?;
assert!(layout.is_sized());
let ret = ecx.allocate(layout, MemoryKind::Stack)?;
trace!(
"eval_body_using_ecx: pushing stack frame for global: {}{}",
with_no_trimmed_paths!(ecx.tcx.def_path_str(cid.instance.def_id())),
- cid.promoted.map_or_else(String::new, |p| format!("::promoted[{:?}]", p))
+ cid.promoted.map_or_else(String::new, |p| format!("::promoted[{p:?}]"))
);
ecx.push_stack_frame(
cid.instance,
body,
- &ret.into(),
+ &ret.clone().into(),
StackPopCleanup::Root { cleanup: false },
)?;
@@ -228,7 +228,6 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
- assert!(key.param_env.is_const());
// see comment in eval_to_allocation_raw_provider for what we're doing here
if key.param_env.reveal() == Reveal::All {
let mut key = key;
@@ -245,10 +244,10 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def {
let ty = key.value.instance.ty(tcx, key.param_env);
- let ty::FnDef(_, substs) = ty.kind() else {
+ let ty::FnDef(_, args) = ty.kind() else {
bug!("intrinsic with type {:?}", ty);
};
- return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| {
+ return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).map_err(|error| {
let span = tcx.def_span(def_id);
super::report(
@@ -269,7 +268,6 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
- assert!(key.param_env.is_const());
// Because the constant is computed twice (once per value of `Reveal`), we are at risk of
// reporting the same error twice here. To resolve this, we check whether we can evaluate the
// constant in the more restrictive `Reveal::UserFacing`, which most likely already was
@@ -328,10 +326,10 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
("static", String::new())
} else {
// If the current item has generics, we'd like to enrich the message with the
- // instance and its substs: to show the actual compile-time values, in addition to
+ // instance and its args: to show the actual compile-time values, in addition to
// the expression, leading to the const eval error.
let instance = &key.value.instance;
- if !instance.substs.is_empty() {
+ if !instance.args.is_empty() {
let instance = with_no_trimmed_paths!(instance.to_string());
("const_with_path", instance)
} else {
@@ -356,7 +354,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
// Since evaluation had no errors, validate the resulting constant.
// This is a separate `try` block to provide more targeted error reporting.
let validation: Result<_, InterpErrorInfo<'_>> = try {
- let mut ref_tracking = RefTracking::new(mplace);
+ let mut ref_tracking = RefTracking::new(mplace.clone());
let mut inner = false;
while let Some((mplace, path)) = ref_tracking.todo.pop() {
let mode = match tcx.static_mutability(cid.instance.def_id()) {
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index fa8253d5e..4ee4ebbb9 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -28,16 +28,19 @@ pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
&& tcx.constness(parent_id) == hir::Constness::Const
}
-/// Checks whether an item is considered to be `const`. If it is a constructor, it is const. If
-/// it is a trait impl/function, return if it has a `const` modifier. If it is an intrinsic,
-/// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return
-/// `Constness::NotConst`.
+/// Checks whether an item is considered to be `const`. If it is a constructor, anonymous const,
+/// const block, const item or associated const, it is const. If it is a trait impl/function,
+/// return if it has a `const` modifier. If it is an intrinsic, report whether said intrinsic
+/// has a `rustc_const_{un,}stable` attribute. Otherwise, return `Constness::NotConst`.
fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
let node = tcx.hir().get_by_def_id(def_id);
match node {
- hir::Node::Ctor(_) => hir::Constness::Const,
- hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness,
+ hir::Node::Ctor(_)
+ | hir::Node::AnonConst(_)
+ | hir::Node::ConstBlock(_)
+ | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => hir::Constness::Const,
+ hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx.generics_of(def_id).host_effect_index.map_or(hir::Constness::NotConst, |_| hir::Constness::Const),
hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
// foreign items cannot be evaluated at compile-time.
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index f9f645af4..b740b79d1 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -22,7 +22,7 @@ use rustc_target::spec::abi::Abi as CallAbi;
use crate::errors::{LongRunning, LongRunningWarn};
use crate::interpret::{
- self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx,
+ self, compile_time_machine, AllocId, ConstAllocation, FnArg, FnVal, Frame, ImmTy, InterpCx,
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
};
use crate::{errors, fluent_generated as fluent};
@@ -201,7 +201,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
fn hook_special_const_fn(
&mut self,
instance: ty::Instance<'tcx>,
- args: &[OpTy<'tcx>],
+ args: &[FnArg<'tcx>],
dest: &PlaceTy<'tcx>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
@@ -210,12 +210,13 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
if Some(def_id) == self.tcx.lang_items().panic_display()
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
{
+ let args = self.copy_fn_args(args)?;
// &str or &&str
assert!(args.len() == 1);
- let mut msg_place = self.deref_operand(&args[0])?;
+ let mut msg_place = self.deref_pointer(&args[0])?;
while msg_place.layout.ty.is_ref() {
- msg_place = self.deref_operand(&msg_place.into())?;
+ msg_place = self.deref_pointer(&msg_place)?;
}
let msg = Symbol::intern(self.read_str(&msg_place)?);
@@ -229,15 +230,16 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
*self.tcx,
ty::ParamEnv::reveal_all(),
const_def_id,
- instance.substs,
+ instance.args,
)
.unwrap()
.unwrap();
return Ok(Some(new_instance));
} else if Some(def_id) == self.tcx.lang_items().align_offset_fn() {
+ let args = self.copy_fn_args(args)?;
// For align_offset, we replace the function call if the pointer has no address.
- match self.align_offset(instance, args, dest, ret)? {
+ match self.align_offset(instance, &args, dest, ret)? {
ControlFlow::Continue(()) => return Ok(Some(instance)),
ControlFlow::Break(()) => return Ok(None),
}
@@ -293,7 +295,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
self.eval_fn_call(
FnVal::Instance(instance),
(CallAbi::Rust, fn_abi),
- &[addr, align],
+ &[FnArg::Copy(addr), FnArg::Copy(align)],
/* with_caller_location = */ false,
dest,
ret,
@@ -425,52 +427,41 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
fn find_mir_or_eval_fn(
ecx: &mut InterpCx<'mir, 'tcx, Self>,
- instance: ty::Instance<'tcx>,
+ orig_instance: ty::Instance<'tcx>,
_abi: CallAbi,
- args: &[OpTy<'tcx>],
+ args: &[FnArg<'tcx>],
dest: &PlaceTy<'tcx>,
ret: Option<mir::BasicBlock>,
_unwind: mir::UnwindAction, // unwinding is not supported in consts
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
- debug!("find_mir_or_eval_fn: {:?}", instance);
+ debug!("find_mir_or_eval_fn: {:?}", orig_instance);
+
+ // Replace some functions.
+ let Some(instance) = ecx.hook_special_const_fn(orig_instance, args, dest, ret)? else {
+ // Call has already been handled.
+ return Ok(None);
+ };
// Only check non-glue functions
if let ty::InstanceDef::Item(def) = instance.def {
// Execution might have wandered off into other crates, so we cannot do a stability-
- // sensitive check here. But we can at least rule out functions that are not const
- // at all.
- if !ecx.tcx.is_const_fn_raw(def) {
- // allow calling functions inside a trait marked with #[const_trait].
- if !ecx.tcx.is_const_default_method(def) {
- // We certainly do *not* want to actually call the fn
- // though, so be sure we return here.
- throw_unsup_format!("calling non-const function `{}`", instance)
- }
- }
-
- let Some(new_instance) = ecx.hook_special_const_fn(instance, args, dest, ret)? else {
- return Ok(None);
- };
-
- if new_instance != instance {
- // We call another const fn instead.
- // However, we return the *original* instance to make backtraces work out
- // (and we hope this does not confuse the FnAbi checks too much).
- return Ok(Self::find_mir_or_eval_fn(
- ecx,
- new_instance,
- _abi,
- args,
- dest,
- ret,
- _unwind,
- )?
- .map(|(body, _instance)| (body, instance)));
+ // sensitive check here. But we can at least rule out functions that are not const at
+ // all. That said, we have to allow calling functions inside a trait marked with
+ // #[const_trait]. These *are* const-checked!
+ // FIXME: why does `is_const_fn_raw` not classify them as const?
+ if (!ecx.tcx.is_const_fn_raw(def) && !ecx.tcx.is_const_default_method(def))
+ || ecx.tcx.has_attr(def, sym::rustc_do_not_const_check)
+ {
+ // We certainly do *not* want to actually call the fn
+ // though, so be sure we return here.
+ throw_unsup_format!("calling non-const function `{}`", instance)
}
}
// This is a const fn. Call it.
- Ok(Some((ecx.load_mir(instance.def, None)?, instance)))
+ // In case of replacement, we return the *original* instance to make backtraces work out
+ // (and we hope this does not confuse the FnAbi checks too much).
+ Ok(Some((ecx.load_mir(instance.def, None)?, orig_instance)))
}
fn call_intrinsic(
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index a3064b53d..854104622 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -85,7 +85,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
}
#[instrument(skip(tcx), level = "debug")]
-pub(crate) fn try_destructure_mir_constant_for_diagnostics<'tcx>(
+pub fn try_destructure_mir_constant_for_diagnostics<'tcx>(
tcx: TyCtxt<'tcx>,
val: ConstValue<'tcx>,
ty: Ty<'tcx>,
@@ -101,17 +101,17 @@ pub(crate) fn try_destructure_mir_constant_for_diagnostics<'tcx>(
return None;
}
ty::Adt(def, _) => {
- let variant = ecx.read_discriminant(&op).ok()?.1;
- let down = ecx.operand_downcast(&op, variant).ok()?;
+ let variant = ecx.read_discriminant(&op).ok()?;
+ let down = ecx.project_downcast(&op, variant).ok()?;
(def.variants()[variant].fields.len(), Some(variant), down)
}
- ty::Tuple(substs) => (substs.len(), None, op),
+ ty::Tuple(args) => (args.len(), None, op),
_ => bug!("cannot destructure mir constant {:?}", val),
};
let fields_iter = (0..field_count)
.map(|i| {
- let field_op = ecx.operand_field(&down, i).ok()?;
+ let field_op = ecx.project_field(&down, i).ok()?;
let val = op_to_const(&ecx, &field_op);
Some((val, field_op.layout.ty))
})
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index e574df276..b15a65d67 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -2,14 +2,15 @@ use super::eval_queries::{mk_eval_cx, op_to_const};
use super::machine::CompileTimeEvalContext;
use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
use crate::const_eval::CanAccessStatics;
+use crate::interpret::MPlaceTy;
use crate::interpret::{
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
- MemoryKind, PlaceTy, Scalar,
+ MemoryKind, Place, Projectable, Scalar,
};
-use crate::interpret::{MPlaceTy, Value};
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
use rustc_span::source_map::DUMMY_SP;
-use rustc_target::abi::{Align, FieldIdx, VariantIdx, FIRST_VARIANT};
+use rustc_target::abi::VariantIdx;
#[instrument(skip(ecx), level = "debug")]
fn branches<'tcx>(
@@ -20,15 +21,15 @@ fn branches<'tcx>(
num_nodes: &mut usize,
) -> ValTreeCreationResult<'tcx> {
let place = match variant {
- Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(),
- None => *place,
+ Some(variant) => ecx.project_downcast(place, variant).unwrap(),
+ None => place.clone(),
};
let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
debug!(?place, ?variant);
let mut fields = Vec::with_capacity(n);
for i in 0..n {
- let field = ecx.mplace_field(&place, i).unwrap();
+ let field = ecx.project_field(&place, i).unwrap();
let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?;
fields.push(Some(valtree));
}
@@ -55,13 +56,11 @@ fn slice_branches<'tcx>(
place: &MPlaceTy<'tcx>,
num_nodes: &mut usize,
) -> ValTreeCreationResult<'tcx> {
- let n = place
- .len(&ecx.tcx.tcx)
- .unwrap_or_else(|_| panic!("expected to use len of place {:?}", place));
+ let n = place.len(ecx).unwrap_or_else(|_| panic!("expected to use len of place {place:?}"));
let mut elems = Vec::with_capacity(n as usize);
for i in 0..n {
- let place_elem = ecx.mplace_index(place, i).unwrap();
+ let place_elem = ecx.project_index(place, i).unwrap();
let valtree = const_to_valtree_inner(ecx, &place_elem, num_nodes)?;
elems.push(valtree);
}
@@ -88,7 +87,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
Ok(ty::ValTree::zst())
}
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
- let Ok(val) = ecx.read_immediate(&place.into()) else {
+ let Ok(val) = ecx.read_immediate(place) else {
return Err(ValTreeCreationError::Other);
};
let val = val.to_scalar();
@@ -104,7 +103,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
ty::Ref(_, _, _) => {
- let Ok(derefd_place)= ecx.deref_operand(&place.into()) else {
+ let Ok(derefd_place)= ecx.deref_pointer(place) else {
return Err(ValTreeCreationError::Other);
};
debug!(?derefd_place);
@@ -132,7 +131,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
bug!("uninhabited types should have errored and never gotten converted to valtree")
}
- let Ok((_, variant)) = ecx.read_discriminant(&place.into()) else {
+ let Ok(variant) = ecx.read_discriminant(place) else {
return Err(ValTreeCreationError::Other);
};
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
@@ -156,52 +155,37 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
}
}
-#[instrument(skip(ecx), level = "debug")]
-fn create_mplace_from_layout<'tcx>(
- ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
- ty: Ty<'tcx>,
-) -> MPlaceTy<'tcx> {
- let tcx = ecx.tcx;
- let param_env = ecx.param_env;
- let layout = tcx.layout_of(param_env.and(ty)).unwrap();
- debug!(?layout);
-
- ecx.allocate(layout, MemoryKind::Stack).unwrap()
-}
-
-// Walks custom DSTs and gets the type of the unsized field and the number of elements
-// in the unsized field.
-fn get_info_on_unsized_field<'tcx>(
- ty: Ty<'tcx>,
+/// Valtrees don't store the `MemPlaceMeta` that all dynamically sized values have in the interpreter.
+/// This function reconstructs it.
+fn reconstruct_place_meta<'tcx>(
+ layout: TyAndLayout<'tcx>,
valtree: ty::ValTree<'tcx>,
tcx: TyCtxt<'tcx>,
-) -> (Ty<'tcx>, usize) {
+) -> MemPlaceMeta {
+ if layout.is_sized() {
+ return MemPlaceMeta::None;
+ }
+
let mut last_valtree = valtree;
+ // Traverse the type, and update `last_valtree` as we go.
let tail = tcx.struct_tail_with_normalize(
- ty,
+ layout.ty,
|ty| ty,
|| {
let branches = last_valtree.unwrap_branch();
- last_valtree = branches[branches.len() - 1];
+ last_valtree = *branches.last().unwrap();
debug!(?branches, ?last_valtree);
},
);
- let unsized_inner_ty = match tail.kind() {
- ty::Slice(t) => *t,
- ty::Str => tail,
- _ => bug!("expected Slice or Str"),
- };
-
- // Have to adjust type for ty::Str
- let unsized_inner_ty = match unsized_inner_ty.kind() {
- ty::Str => tcx.types.u8,
- _ => unsized_inner_ty,
+ // Sanity-check that we got a tail we support.
+ match tail.kind() {
+ ty::Slice(..) | ty::Str => {}
+ _ => bug!("unsized tail of a valtree must be Slice or Str"),
};
- // Get the number of elements in the unsized field
+ // Get the number of elements in the unsized field.
let num_elems = last_valtree.unwrap_branch().len();
-
- (unsized_inner_ty, num_elems)
+ MemPlaceMeta::Meta(Scalar::from_target_usize(num_elems as u64, &tcx))
}
#[instrument(skip(ecx), level = "debug", ret)]
@@ -210,41 +194,9 @@ fn create_pointee_place<'tcx>(
ty: Ty<'tcx>,
valtree: ty::ValTree<'tcx>,
) -> MPlaceTy<'tcx> {
- let tcx = ecx.tcx.tcx;
-
- if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty()) {
- // We need to create `Allocation`s for custom DSTs
-
- let (unsized_inner_ty, num_elems) = get_info_on_unsized_field(ty, valtree, tcx);
- let unsized_inner_ty = match unsized_inner_ty.kind() {
- ty::Str => tcx.types.u8,
- _ => unsized_inner_ty,
- };
- let unsized_inner_ty_size =
- tcx.layout_of(ty::ParamEnv::empty().and(unsized_inner_ty)).unwrap().layout.size();
- debug!(?unsized_inner_ty, ?unsized_inner_ty_size, ?num_elems);
-
- // for custom DSTs only the last field/element is unsized, but we need to also allocate
- // space for the other fields/elements
- let layout = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap();
- let size_of_sized_part = layout.layout.size();
-
- // Get the size of the memory behind the DST
- let dst_size = unsized_inner_ty_size.checked_mul(num_elems as u64, &tcx).unwrap();
-
- let size = size_of_sized_part.checked_add(dst_size, &tcx).unwrap();
- let align = Align::from_bytes(size.bytes().next_power_of_two()).unwrap();
- let ptr = ecx.allocate_ptr(size, align, MemoryKind::Stack).unwrap();
- debug!(?ptr);
-
- MPlaceTy::from_aligned_ptr_with_meta(
- ptr.into(),
- layout,
- MemPlaceMeta::Meta(Scalar::from_target_usize(num_elems as u64, &tcx)),
- )
- } else {
- create_mplace_from_layout(ecx, ty)
- }
+ let layout = ecx.layout_of(ty).unwrap();
+ let meta = reconstruct_place_meta(layout, valtree, ecx.tcx.tcx);
+ ecx.allocate_dyn(layout, MemoryKind::Stack, meta).unwrap()
}
/// Converts a `ValTree` to a `ConstValue`, which is needed after mir
@@ -282,17 +234,20 @@ pub fn valtree_to_const_value<'tcx>(
),
},
ty::Ref(_, _, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
- let mut place = match ty.kind() {
+ let place = match ty.kind() {
ty::Ref(_, inner_ty, _) => {
- // Need to create a place for the pointee to fill for Refs
+ // Need to create a place for the pointee (the reference itself will be an immediate)
create_pointee_place(&mut ecx, *inner_ty, valtree)
}
- _ => create_mplace_from_layout(&mut ecx, ty),
+ _ => {
+ // Need to create a place for this valtree.
+ create_pointee_place(&mut ecx, ty, valtree)
+ }
};
debug!(?place);
- valtree_into_mplace(&mut ecx, &mut place, valtree);
- dump_place(&ecx, place.into());
+ valtree_into_mplace(&mut ecx, &place, valtree);
+ dump_place(&ecx, &place);
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
match ty.kind() {
@@ -331,7 +286,7 @@ pub fn valtree_to_const_value<'tcx>(
#[instrument(skip(ecx), level = "debug")]
fn valtree_into_mplace<'tcx>(
ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
- place: &mut MPlaceTy<'tcx>,
+ place: &MPlaceTy<'tcx>,
valtree: ty::ValTree<'tcx>,
) {
// This will match on valtree and write the value(s) corresponding to the ValTree
@@ -347,14 +302,14 @@ fn valtree_into_mplace<'tcx>(
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
let scalar_int = valtree.unwrap_leaf();
debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place);
- ecx.write_immediate(Immediate::Scalar(scalar_int.into()), &place.into()).unwrap();
+ ecx.write_immediate(Immediate::Scalar(scalar_int.into()), place).unwrap();
}
ty::Ref(_, inner_ty, _) => {
- let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
+ let pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
debug!(?pointee_place);
- valtree_into_mplace(ecx, &mut pointee_place, valtree);
- dump_place(ecx, pointee_place.into());
+ valtree_into_mplace(ecx, &pointee_place, valtree);
+ dump_place(ecx, &pointee_place);
intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap();
let imm = match inner_ty.kind() {
@@ -371,7 +326,7 @@ fn valtree_into_mplace<'tcx>(
};
debug!(?imm);
- ecx.write_immediate(imm, &place.into()).unwrap();
+ ecx.write_immediate(imm, place).unwrap();
}
ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => {
let branches = valtree.unwrap_branch();
@@ -386,12 +341,12 @@ fn valtree_into_mplace<'tcx>(
debug!(?variant);
(
- place.project_downcast(ecx, variant_idx).unwrap(),
+ ecx.project_downcast(place, variant_idx).unwrap(),
&branches[1..],
Some(variant_idx),
)
}
- _ => (*place, branches, None),
+ _ => (place.clone(), branches, None),
};
debug!(?place_adjusted, ?branches);
@@ -400,70 +355,33 @@ fn valtree_into_mplace<'tcx>(
for (i, inner_valtree) in branches.iter().enumerate() {
debug!(?i, ?inner_valtree);
- let mut place_inner = match ty.kind() {
- ty::Str | ty::Slice(_) => ecx.mplace_index(&place, i as u64).unwrap(),
- _ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty())
- && i == branches.len() - 1 =>
- {
- // Note: For custom DSTs we need to manually process the last unsized field.
- // We created a `Pointer` for the `Allocation` of the complete sized version of
- // the Adt in `create_pointee_place` and now we fill that `Allocation` with the
- // values in the ValTree. For the unsized field we have to additionally add the meta
- // data.
-
- let (unsized_inner_ty, num_elems) =
- get_info_on_unsized_field(ty, valtree, tcx);
- debug!(?unsized_inner_ty);
-
- let inner_ty = match ty.kind() {
- ty::Adt(def, substs) => {
- let i = FieldIdx::from_usize(i);
- def.variant(FIRST_VARIANT).fields[i].ty(tcx, substs)
- }
- ty::Tuple(inner_tys) => inner_tys[i],
- _ => bug!("unexpected unsized type {:?}", ty),
- };
-
- let inner_layout =
- tcx.layout_of(ty::ParamEnv::empty().and(inner_ty)).unwrap();
- debug!(?inner_layout);
-
- let offset = place_adjusted.layout.fields.offset(i);
- place
- .offset_with_meta(
- offset,
- MemPlaceMeta::Meta(Scalar::from_target_usize(
- num_elems as u64,
- &tcx,
- )),
- inner_layout,
- &tcx,
- )
- .unwrap()
+ let place_inner = match ty.kind() {
+ ty::Str | ty::Slice(_) | ty::Array(..) => {
+ ecx.project_index(place, i as u64).unwrap()
}
- _ => ecx.mplace_field(&place_adjusted, i).unwrap(),
+ _ => ecx.project_field(&place_adjusted, i).unwrap(),
};
debug!(?place_inner);
- valtree_into_mplace(ecx, &mut place_inner, *inner_valtree);
- dump_place(&ecx, place_inner.into());
+ valtree_into_mplace(ecx, &place_inner, *inner_valtree);
+ dump_place(&ecx, &place_inner);
}
debug!("dump of place_adjusted:");
- dump_place(ecx, place_adjusted.into());
+ dump_place(ecx, &place_adjusted);
if let Some(variant_idx) = variant_idx {
// don't forget filling the place with the discriminant of the enum
- ecx.write_discriminant(variant_idx, &place.into()).unwrap();
+ ecx.write_discriminant(variant_idx, place).unwrap();
}
debug!("dump of place after writing discriminant:");
- dump_place(ecx, place.into());
+ dump_place(ecx, place);
}
_ => bug!("shouldn't have created a ValTree for {:?}", ty),
}
}
-fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: PlaceTy<'tcx>) {
- trace!("{:?}", ecx.dump_place(*place));
+fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>) {
+ trace!("{:?}", ecx.dump_place(Place::Ptr(**place)));
}