summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/const_eval
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_const_eval/src/const_eval')
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs159
-rw-r--r--compiler/rustc_const_eval/src/const_eval/fn_queries.rs9
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs80
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs22
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs51
5 files changed, 166 insertions, 155 deletions
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 3d758cd01..13937a941 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -1,21 +1,22 @@
-use crate::const_eval::CheckAlignment;
-use crate::errors::ConstEvalError;
+use std::mem;
use either::{Left, Right};
use rustc_hir::def::DefKind;
-use rustc_middle::mir::interpret::{ErrorHandled, InterpErrorInfo};
+use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo};
use rustc_middle::mir::pretty::write_allocation_bytes;
use rustc_middle::mir::{self, ConstAlloc, ConstValue};
use rustc_middle::traits::Reveal;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use rustc_target::abi::{self, Abi};
use super::{CanAccessStatics, CompileTimeEvalContext, CompileTimeInterpreter};
+use crate::const_eval::CheckAlignment;
use crate::errors;
+use crate::errors::ConstEvalError;
use crate::interpret::eval_nullary_intrinsic;
use crate::interpret::{
intern_const_alloc_recursive, CtfeValidationMode, GlobalId, Immediate, InternKind, InterpCx,
@@ -74,9 +75,9 @@ fn eval_body_using_ecx<'mir, 'tcx>(
None => InternKind::Constant,
}
};
- ecx.machine.check_alignment = CheckAlignment::No; // interning doesn't need to respect alignment
+ let check_alignment = mem::replace(&mut ecx.machine.check_alignment, CheckAlignment::No); // interning doesn't need to respect alignment
intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
- // we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway
+ ecx.machine.check_alignment = check_alignment;
debug!("eval_body_using_ecx done: {:?}", ret);
Ok(ret)
@@ -89,7 +90,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
/// that inform us about the generic bounds of the constant. E.g., using an associated constant
/// of a function's generic parameter will require knowledge about the bounds on the generic
/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument.
-pub(super) fn mk_eval_cx<'mir, 'tcx>(
+pub(crate) fn mk_eval_cx<'mir, 'tcx>(
tcx: TyCtxt<'tcx>,
root_span: Span,
param_env: ty::ParamEnv<'tcx>,
@@ -105,10 +106,16 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
}
/// This function converts an interpreter value into a MIR constant.
+///
+/// The `for_diagnostics` flag turns the usual rules for returning `ConstValue::Scalar` into a
+/// best-effort attempt. This is not okay for use in const-eval sine it breaks invariants rustc
+/// relies on, but it is okay for diagnostics which will just give up gracefully when they
+/// encounter an `Indirect` they cannot handle.
#[instrument(skip(ecx), level = "debug")]
pub(super) fn op_to_const<'tcx>(
ecx: &CompileTimeEvalContext<'_, 'tcx>,
op: &OpTy<'tcx>,
+ for_diagnostics: bool,
) -> ConstValue<'tcx> {
// Handle ZST consistently and early.
if op.layout.is_zst() {
@@ -132,7 +139,13 @@ pub(super) fn op_to_const<'tcx>(
_ => false,
};
let immediate = if force_as_immediate {
- Right(ecx.read_immediate(op).expect("normalization works on validated constants"))
+ match ecx.read_immediate(op) {
+ Ok(imm) => Right(imm),
+ Err(err) if !for_diagnostics => {
+ panic!("normalization works on validated constants: {err:?}")
+ }
+ _ => op.as_mplace_or_imm(),
+ }
} else {
op.as_mplace_or_imm()
};
@@ -204,7 +217,7 @@ pub(crate) fn turn_into_const_value<'tcx>(
);
// Turn this into a proper constant.
- op_to_const(&ecx, &mplace.into())
+ op_to_const(&ecx, &mplace.into(), /* for diagnostics */ false)
}
#[instrument(skip(tcx), level = "debug")]
@@ -284,22 +297,22 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
let def = cid.instance.def.def_id();
let is_static = tcx.is_static(def);
- let mut ecx = InterpCx::new(
+ let ecx = InterpCx::new(
tcx,
tcx.def_span(def),
key.param_env,
// Statics (and promoteds inside statics) may access other statics, because unlike consts
// they do not have to behave "as if" they were evaluated at runtime.
- CompileTimeInterpreter::new(
- CanAccessStatics::from(is_static),
- if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
- CheckAlignment::Error
- } else {
- CheckAlignment::FutureIncompat
- },
- ),
+ CompileTimeInterpreter::new(CanAccessStatics::from(is_static), CheckAlignment::Error),
);
+ eval_in_interpreter(ecx, cid, is_static)
+}
+pub fn eval_in_interpreter<'mir, 'tcx>(
+ mut ecx: InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
+ cid: GlobalId<'tcx>,
+ is_static: bool,
+) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
let res = ecx.load_mir(cid.instance.def, cid.promoted);
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
Err(error) => {
@@ -312,7 +325,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
// If the current item has generics, we'd like to enrich the message with the
// 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;
+ let instance = &cid.instance;
if !instance.args.is_empty() {
let instance = with_no_trimmed_paths!(instance.to_string());
("const_with_path", instance)
@@ -337,56 +350,14 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
Ok(mplace) => {
// 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.clone());
- let mut inner = false;
- while let Some((mplace, path)) = ref_tracking.todo.pop() {
- let mode = match tcx.static_mutability(cid.instance.def_id()) {
- Some(_) if cid.promoted.is_some() => {
- // Promoteds in statics are allowed to point to statics.
- CtfeValidationMode::Const { inner, allow_static_ptrs: true }
- }
- Some(_) => CtfeValidationMode::Regular, // a `static`
- None => CtfeValidationMode::Const { inner, allow_static_ptrs: false },
- };
- ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
- inner = true;
- }
- };
+ let validation =
+ const_validate_mplace(&ecx, &mplace, is_static, cid.promoted.is_some());
+
let alloc_id = mplace.ptr().provenance.unwrap();
// Validation failed, report an error.
if let Err(error) = validation {
- let (error, backtrace) = error.into_parts();
- backtrace.print_backtrace();
-
- let ub_note = matches!(error, InterpError::UndefinedBehavior(_)).then(|| {});
-
- let alloc = ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
- let mut bytes = String::new();
- if alloc.size() != abi::Size::ZERO {
- bytes = "\n".into();
- // FIXME(translation) there might be pieces that are translatable.
- write_allocation_bytes(*ecx.tcx, alloc, &mut bytes, " ").unwrap();
- }
- let raw_bytes = errors::RawBytesNote {
- size: alloc.size().bytes(),
- align: alloc.align.bytes(),
- bytes,
- };
-
- Err(super::report(
- *ecx.tcx,
- error,
- None,
- || super::get_span_and_frames(&ecx),
- move |span, frames| errors::UndefinedBehavior {
- span,
- ub_note,
- frames,
- raw_bytes,
- },
- ))
+ Err(const_report_error(&ecx, error, alloc_id))
} else {
// Convert to raw constant
Ok(ConstAlloc { alloc_id, ty: mplace.layout.ty })
@@ -394,3 +365,61 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
}
}
}
+
+#[inline(always)]
+pub fn const_validate_mplace<'mir, 'tcx>(
+ ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
+ mplace: &MPlaceTy<'tcx>,
+ is_static: bool,
+ is_promoted: bool,
+) -> InterpResult<'tcx> {
+ let mut ref_tracking = RefTracking::new(mplace.clone());
+ let mut inner = false;
+ while let Some((mplace, path)) = ref_tracking.todo.pop() {
+ let mode = if is_static {
+ if is_promoted {
+ // Promoteds in statics are allowed to point to statics.
+ CtfeValidationMode::Const { inner, allow_static_ptrs: true }
+ } else {
+ // a `static`
+ CtfeValidationMode::Regular
+ }
+ } else {
+ CtfeValidationMode::Const { inner, allow_static_ptrs: false }
+ };
+ ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
+ inner = true;
+ }
+
+ Ok(())
+}
+
+#[inline(always)]
+pub fn const_report_error<'mir, 'tcx>(
+ ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
+ error: InterpErrorInfo<'tcx>,
+ alloc_id: AllocId,
+) -> ErrorHandled {
+ let (error, backtrace) = error.into_parts();
+ backtrace.print_backtrace();
+
+ let ub_note = matches!(error, InterpError::UndefinedBehavior(_)).then(|| {});
+
+ let alloc = ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
+ let mut bytes = String::new();
+ if alloc.size() != abi::Size::ZERO {
+ bytes = "\n".into();
+ // FIXME(translation) there might be pieces that are translatable.
+ write_allocation_bytes(*ecx.tcx, alloc, &mut bytes, " ").unwrap();
+ }
+ let raw_bytes =
+ errors::RawBytesNote { size: alloc.size().bytes(), align: alloc.align.bytes(), bytes };
+
+ crate::const_eval::report(
+ *ecx.tcx,
+ error,
+ None,
+ || crate::const_eval::get_span_and_frames(ecx),
+ move |span, frames| errors::UndefinedBehavior { span, ub_note, frames, raw_bytes },
+ )
+}
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 4ee4ebbb9..9e992637f 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -39,8 +39,13 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::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::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 14b9894aa..4b447229c 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -1,10 +1,10 @@
use rustc_hir::def::DefKind;
-use rustc_hir::{LangItem, CRATE_HIR_ID};
+use rustc_hir::LangItem;
use rustc_middle::mir;
use rustc_middle::mir::interpret::PointerArithmetic;
use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
use rustc_middle::ty::{self, TyCtxt};
-use rustc_session::lint::builtin::INVALID_ALIGNMENT;
+use rustc_span::Span;
use std::borrow::Borrow;
use std::hash::Hash;
use std::ops::ControlFlow;
@@ -21,11 +21,11 @@ use rustc_target::abi::{Align, Size};
use rustc_target::spec::abi::Abi as CallAbi;
use crate::errors::{LongRunning, LongRunningWarn};
+use crate::fluent_generated as fluent;
use crate::interpret::{
self, compile_time_machine, AllocId, ConstAllocation, FnArg, FnVal, Frame, ImmTy, InterpCx,
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
};
-use crate::{errors, fluent_generated as fluent};
use super::error::*;
@@ -65,22 +65,11 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
#[derive(Copy, Clone)]
pub enum CheckAlignment {
- /// Ignore alignment when following relocations.
+ /// Ignore all alignment requirements.
/// This is mainly used in interning.
No,
/// Hard error when dereferencing a misaligned pointer.
Error,
- /// Emit a future incompat lint when dereferencing a misaligned pointer.
- FutureIncompat,
-}
-
-impl CheckAlignment {
- pub fn should_check(&self) -> bool {
- match self {
- CheckAlignment::No => false,
- CheckAlignment::Error | CheckAlignment::FutureIncompat => true,
- }
- }
}
#[derive(Copy, Clone, PartialEq)]
@@ -193,6 +182,24 @@ impl interpret::MayLeak for ! {
}
impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
+ fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
+ let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
+ let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
+
+ use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
+ (
+ Symbol::intern(
+ &caller
+ .file
+ .name
+ .for_scope(&self.tcx.sess, RemapPathScopeComponents::DIAGNOSTICS)
+ .to_string_lossy(),
+ ),
+ u32::try_from(caller.line).unwrap(),
+ u32::try_from(caller.col_display).unwrap().checked_add(1).unwrap(),
+ )
+ }
+
/// "Intercept" a function call, because we have something special to do for it.
/// All `#[rustc_do_not_const_check]` functions should be hooked here.
/// If this returns `Some` function, which may be `instance` or a different function with
@@ -207,7 +214,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
let def_id = instance.def_id();
- if Some(def_id) == self.tcx.lang_items().panic_display()
+ if self.tcx.has_attr(def_id, sym::rustc_const_panic_str)
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
{
let args = self.copy_fn_args(args)?;
@@ -358,8 +365,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
#[inline(always)]
- fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
- ecx.machine.check_alignment
+ fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+ matches!(ecx.machine.check_alignment, CheckAlignment::Error)
}
#[inline(always)]
@@ -367,39 +374,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited()
}
- fn alignment_check_failed(
- ecx: &InterpCx<'mir, 'tcx, Self>,
- has: Align,
- required: Align,
- check: CheckAlignment,
- ) -> InterpResult<'tcx, ()> {
- let err = err_ub!(AlignmentCheckFailed { has, required }).into();
- match check {
- CheckAlignment::Error => Err(err),
- CheckAlignment::No => span_bug!(
- ecx.cur_span(),
- "`alignment_check_failed` called when no alignment check requested"
- ),
- CheckAlignment::FutureIncompat => {
- let (_, backtrace) = err.into_parts();
- backtrace.print_backtrace();
- let (span, frames) = super::get_span_and_frames(&ecx);
-
- ecx.tcx.emit_spanned_lint(
- INVALID_ALIGNMENT,
- ecx.stack().iter().find_map(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
- span,
- errors::AlignmentCheckFailed {
- has: has.bytes(),
- required: required.bytes(),
- frames,
- },
- );
- Ok(())
- }
- }
- }
-
fn load_mir(
ecx: &InterpCx<'mir, 'tcx, Self>,
instance: ty::InstanceDef<'tcx>,
@@ -579,8 +553,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
OverflowNeg(op) => OverflowNeg(eval_to_int(op)?),
DivisionByZero(op) => DivisionByZero(eval_to_int(op)?),
RemainderByZero(op) => RemainderByZero(eval_to_int(op)?),
- ResumedAfterReturn(generator_kind) => ResumedAfterReturn(*generator_kind),
- ResumedAfterPanic(generator_kind) => ResumedAfterPanic(*generator_kind),
+ ResumedAfterReturn(coroutine_kind) => ResumedAfterReturn(*coroutine_kind),
+ ResumedAfterPanic(coroutine_kind) => ResumedAfterPanic(*coroutine_kind),
MisalignedPointerDereference { ref required, ref found } => {
MisalignedPointerDereference {
required: eval_to_int(required)?,
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index bcbe996be..f6942366c 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -1,12 +1,12 @@
// Not in interpret to make sure we do not use private implementation details
use crate::errors::MaxNumNodesInConstErr;
-use crate::interpret::{intern_const_alloc_recursive, InternKind, InterpCx, Scalar};
+use crate::interpret::InterpCx;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
+use rustc_span::DUMMY_SP;
mod error;
mod eval_queries;
@@ -20,20 +20,6 @@ pub use fn_queries::*;
pub use machine::*;
pub(crate) use valtrees::{const_to_valtree_inner, valtree_to_const_value};
-pub(crate) fn const_caller_location(
- tcx: TyCtxt<'_>,
- (file, line, col): (Symbol, u32, u32),
-) -> mir::ConstValue<'_> {
- trace!("const_caller_location: {}:{}:{}", file, line, col);
- let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), CanAccessStatics::No);
-
- let loc_place = ecx.alloc_caller_location(file, line, col);
- if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
- bug!("intern_const_alloc_recursive should not error in this case")
- }
- mir::ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr(), &tcx))
-}
-
// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
const VALTREE_MAX_NODES: usize = 100000;
@@ -86,7 +72,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
}
#[instrument(skip(tcx), level = "debug")]
-pub(crate) fn try_destructure_mir_constant_for_diagnostics<'tcx>(
+pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
tcx: TyCtxtAt<'tcx>,
val: mir::ConstValue<'tcx>,
ty: Ty<'tcx>,
@@ -113,7 +99,7 @@ pub(crate) fn try_destructure_mir_constant_for_diagnostics<'tcx>(
let fields_iter = (0..field_count)
.map(|i| {
let field_op = ecx.project_field(&down, i).ok()?;
- let val = op_to_const(&ecx, &field_op);
+ let val = op_to_const(&ecx, &field_op, /* for diagnostics */ true);
Some((val, field_op.layout.ty))
})
.collect::<Option<Vec<_>>>()?;
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 7436ea6ae..ed2d81727 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -10,7 +10,7 @@ use crate::interpret::{
use rustc_middle::mir;
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
-use rustc_span::source_map::DUMMY_SP;
+use rustc_span::DUMMY_SP;
use rustc_target::abi::VariantIdx;
#[instrument(skip(ecx), level = "debug")]
@@ -97,11 +97,27 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
Ok(ty::ValTree::Leaf(val.assert_int()))
}
- // Raw pointers are not allowed in type level constants, as we cannot properly test them for
- // equality at compile-time (see `ptr_guaranteed_cmp`).
+ ty::RawPtr(_) => {
+ // Not all raw pointers are allowed, as we cannot properly test them for
+ // equality at compile-time (see `ptr_guaranteed_cmp`).
+ // However we allow those that are just integers in disguise.
+ // (We could allow wide raw pointers where both sides are integers in the future,
+ // but for now we reject them.)
+ let Ok(val) = ecx.read_scalar(place) else {
+ return Err(ValTreeCreationError::Other);
+ };
+ // We are in the CTFE machine, so ptr-to-int casts will fail.
+ // This can only be `Ok` if `val` already is an integer.
+ let Ok(val) = val.try_to_int() else {
+ return Err(ValTreeCreationError::Other);
+ };
+ // It's just a ScalarInt!
+ Ok(ty::ValTree::Leaf(val))
+ }
+
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
// agree with runtime equality tests.
- ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
+ ty::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType),
ty::Ref(_, _, _) => {
let Ok(derefd_place)= ecx.deref_pointer(place) else {
@@ -151,8 +167,8 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
| ty::Infer(_)
// FIXME(oli-obk): we can probably encode closures just like structs
| ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..) => Err(ValTreeCreationError::NonSupportedType),
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType),
}
}
@@ -222,17 +238,19 @@ pub fn valtree_to_const_value<'tcx>(
assert!(valtree.unwrap_branch().is_empty());
mir::ConstValue::ZeroSized
}
- ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => match valtree {
- ty::ValTree::Leaf(scalar_int) => mir::ConstValue::Scalar(Scalar::Int(scalar_int)),
- ty::ValTree::Branch(_) => bug!(
- "ValTrees for Bool, Int, Uint, Float or Char should have the form ValTree::Leaf"
- ),
- },
+ ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char | ty::RawPtr(_) => {
+ match valtree {
+ ty::ValTree::Leaf(scalar_int) => mir::ConstValue::Scalar(Scalar::Int(scalar_int)),
+ ty::ValTree::Branch(_) => bug!(
+ "ValTrees for Bool, Int, Uint, Float, Char or RawPtr should have the form ValTree::Leaf"
+ ),
+ }
+ }
ty::Ref(_, inner_ty, _) => {
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
let imm = valtree_to_ref(&mut ecx, valtree, *inner_ty);
let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap());
- op_to_const(&ecx, &imm.into())
+ op_to_const(&ecx, &imm.into(), /* for diagnostics */ false)
}
ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
let layout = tcx.layout_of(param_env_ty).unwrap();
@@ -265,7 +283,7 @@ pub fn valtree_to_const_value<'tcx>(
dump_place(&ecx, &place);
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
- op_to_const(&ecx, &place.into())
+ op_to_const(&ecx, &place.into(), /* for diagnostics */ false)
}
ty::Never
| ty::Error(_)
@@ -278,10 +296,9 @@ pub fn valtree_to_const_value<'tcx>(
| ty::Placeholder(..)
| ty::Infer(_)
| ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::FnPtr(_)
- | ty::RawPtr(_)
| ty::Str
| ty::Slice(_)
| ty::Dynamic(..) => bug!("no ValTree should have been created for type {:?}", ty.kind()),