1 // Not in interpret to make sure we do not use private implementation details
3 use std
::convert
::TryFrom
;
5 use rustc_hir
::Mutability
;
7 use rustc_middle
::ty
::{self, TyCtxt}
;
8 use rustc_span
::{source_map::DUMMY_SP, symbol::Symbol}
;
10 use crate::interpret
::{
11 intern_const_alloc_recursive
, ConstValue
, InternKind
, InterpCx
, InterpResult
, MemPlaceMeta
,
22 pub use eval_queries
::*;
23 pub use fn_queries
::*;
25 pub(crate) use valtrees
::{const_to_valtree, valtree_to_const_value}
;
27 pub(crate) fn const_caller_location(
29 (file
, line
, col
): (Symbol
, u32, u32),
31 trace
!("const_caller_location: {}:{}:{}", file
, line
, col
);
32 let mut ecx
= mk_eval_cx(tcx
, DUMMY_SP
, ty
::ParamEnv
::reveal_all(), false);
34 let loc_place
= ecx
.alloc_caller_location(file
, line
, col
);
35 if intern_const_alloc_recursive(&mut ecx
, InternKind
::Constant
, &loc_place
).is_err() {
36 bug
!("intern_const_alloc_recursive should not error in this case")
38 ConstValue
::Scalar(Scalar
::from_maybe_pointer(loc_place
.ptr
, &tcx
))
41 /// This function should never fail for validated constants. However, it is also invoked from the
42 /// pretty printer which might attempt to format invalid constants and in that case it might fail.
43 pub(crate) fn try_destructure_const
<'tcx
>(
45 param_env
: ty
::ParamEnv
<'tcx
>,
47 ) -> InterpResult
<'tcx
, mir
::DestructuredConst
<'tcx
>> {
48 trace
!("destructure_const: {:?}", val
);
49 let ecx
= mk_eval_cx(tcx
, DUMMY_SP
, param_env
, false);
50 let op
= ecx
.const_to_op(val
, None
)?
;
52 // We go to `usize` as we cannot allocate anything bigger anyway.
53 let (field_count
, variant
, down
) = match val
.ty().kind() {
54 ty
::Array(_
, len
) => (usize::try_from(len
.eval_usize(tcx
, param_env
)).unwrap(), None
, op
),
55 // Checks if we have any variants, to avoid downcasting to a non-existing variant (when
56 // there are no variants `read_discriminant` successfully returns a non-existing variant
58 ty
::Adt(def
, _
) if def
.variants().is_empty() => throw_ub
!(Unreachable
),
60 let variant
= ecx
.read_discriminant(&op
)?
.1;
61 let down
= ecx
.operand_downcast(&op
, variant
)?
;
62 (def
.variant(variant
).fields
.len(), Some(variant
), down
)
64 ty
::Tuple(substs
) => (substs
.len(), None
, op
),
65 _
=> bug
!("cannot destructure constant {:?}", val
),
68 let fields
= (0..field_count
)
70 let field_op
= ecx
.operand_field(&down
, i
)?
;
71 let val
= op_to_const(&ecx
, &field_op
);
72 Ok(ty
::Const
::from_value(tcx
, val
, field_op
.layout
.ty
))
74 .collect
::<InterpResult
<'tcx
, Vec
<_
>>>()?
;
75 let fields
= tcx
.arena
.alloc_from_iter(fields
);
77 Ok(mir
::DestructuredConst { variant, fields }
)
80 #[instrument(skip(tcx), level = "debug")]
81 pub(crate) fn deref_const
<'tcx
>(
83 param_env
: ty
::ParamEnv
<'tcx
>,
85 ) -> ty
::Const
<'tcx
> {
86 trace
!("deref_const: {:?}", val
);
87 let ecx
= mk_eval_cx(tcx
, DUMMY_SP
, param_env
, false);
88 let op
= ecx
.const_to_op(val
, None
).unwrap();
89 let mplace
= ecx
.deref_operand(&op
).unwrap();
90 if let Some(alloc_id
) = mplace
.ptr
.provenance
{
92 tcx
.get_global_alloc(alloc_id
).unwrap().unwrap_memory().inner().mutability
,
94 "deref_const cannot be used with mutable allocations as \
95 that could allow pattern matching to observe mutable statics",
99 let ty
= match mplace
.meta
{
100 MemPlaceMeta
::None
=> mplace
.layout
.ty
,
101 MemPlaceMeta
::Poison
=> bug
!("poison metadata in `deref_const`: {:#?}", mplace
),
102 // In case of unsized types, figure out the real type behind.
103 MemPlaceMeta
::Meta(scalar
) => match mplace
.layout
.ty
.kind() {
104 ty
::Str
=> bug
!("there's no sized equivalent of a `str`"),
105 ty
::Slice(elem_ty
) => tcx
.mk_array(*elem_ty
, scalar
.to_machine_usize(&tcx
).unwrap()),
107 "type {} should not have metadata, but had {:?}",
114 tcx
.mk_const(ty
::ConstS { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty }
)