1 // Not in interpret to make sure we do not use private implementation details
3 use crate::errors
::MaxNumNodesInConstErr
;
4 use crate::interpret
::{
5 intern_const_alloc_recursive
, ConstValue
, InternKind
, InterpCx
, InterpResult
, MemPlaceMeta
,
8 use rustc_hir
::Mutability
;
10 use rustc_middle
::mir
::interpret
::{EvalToValTreeResult, GlobalId}
;
11 use rustc_middle
::ty
::{self, TyCtxt}
;
12 use rustc_span
::{source_map::DUMMY_SP, symbol::Symbol}
;
21 pub use eval_queries
::*;
22 pub use fn_queries
::*;
24 pub(crate) use valtrees
::{const_to_valtree_inner, valtree_to_const_value}
;
26 pub(crate) fn const_caller_location(
28 (file
, line
, col
): (Symbol
, u32, u32),
30 trace
!("const_caller_location: {}:{}:{}", file
, line
, col
);
31 let mut ecx
= mk_eval_cx(tcx
, DUMMY_SP
, ty
::ParamEnv
::reveal_all(), false);
33 let loc_place
= ecx
.alloc_caller_location(file
, line
, col
);
34 if intern_const_alloc_recursive(&mut ecx
, InternKind
::Constant
, &loc_place
).is_err() {
35 bug
!("intern_const_alloc_recursive should not error in this case")
37 ConstValue
::Scalar(Scalar
::from_maybe_pointer(loc_place
.ptr
, &tcx
))
40 // We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
41 const VALTREE_MAX_NODES
: usize = 100000;
43 pub(crate) enum ValTreeCreationError
{
48 pub(crate) type ValTreeCreationResult
<'tcx
> = Result
<ty
::ValTree
<'tcx
>, ValTreeCreationError
>;
50 /// Evaluates a constant and turns it into a type-level constant value.
51 pub(crate) fn eval_to_valtree
<'tcx
>(
53 param_env
: ty
::ParamEnv
<'tcx
>,
55 ) -> EvalToValTreeResult
<'tcx
> {
56 let const_alloc
= tcx
.eval_to_allocation_raw(param_env
.and(cid
))?
;
58 // FIXME Need to provide a span to `eval_to_valtree`
60 tcx
, DUMMY_SP
, param_env
,
61 // It is absolutely crucial for soundness that
62 // we do not read from static items or other mutable memory.
65 let place
= ecx
.raw_const_to_mplace(const_alloc
).unwrap();
68 let mut num_nodes
= 0;
69 let valtree_result
= const_to_valtree_inner(&ecx
, &place
, &mut num_nodes
);
71 match valtree_result
{
72 Ok(valtree
) => Ok(Some(valtree
)),
74 let did
= cid
.instance
.def_id();
75 let global_const_id
= cid
.display(tcx
);
77 ValTreeCreationError
::NodesOverflow
=> {
79 "maximum number of nodes exceeded in constant {}",
82 let mut diag
= match tcx
.hir().span_if_local(did
) {
84 tcx
.sess
.create_err(MaxNumNodesInConstErr { span, global_const_id }
)
86 None
=> tcx
.sess
.struct_err(&msg
),
92 ValTreeCreationError
::NonSupportedType
| ValTreeCreationError
::Other
=> Ok(None
),
98 #[instrument(skip(tcx), level = "debug")]
99 pub(crate) fn try_destructure_mir_constant
<'tcx
>(
101 param_env
: ty
::ParamEnv
<'tcx
>,
102 val
: mir
::ConstantKind
<'tcx
>,
103 ) -> InterpResult
<'tcx
, mir
::DestructuredConstant
<'tcx
>> {
104 trace
!("destructure_mir_constant: {:?}", val
);
105 let ecx
= mk_eval_cx(tcx
, DUMMY_SP
, param_env
, false);
106 let op
= ecx
.eval_mir_constant(&val
, None
, None
)?
;
108 // We go to `usize` as we cannot allocate anything bigger anyway.
109 let (field_count
, variant
, down
) = match val
.ty().kind() {
110 ty
::Array(_
, len
) => (len
.eval_usize(tcx
, param_env
) as usize, None
, op
),
111 ty
::Adt(def
, _
) if def
.variants().is_empty() => {
112 throw_ub
!(Unreachable
)
115 let variant
= ecx
.read_discriminant(&op
)?
.1;
116 let down
= ecx
.operand_downcast(&op
, variant
)?
;
117 (def
.variants()[variant
].fields
.len(), Some(variant
), down
)
119 ty
::Tuple(substs
) => (substs
.len(), None
, op
),
120 _
=> bug
!("cannot destructure mir constant {:?}", val
),
123 let fields_iter
= (0..field_count
)
125 let field_op
= ecx
.operand_field(&down
, i
)?
;
126 let val
= op_to_const(&ecx
, &field_op
);
127 Ok(mir
::ConstantKind
::Val(val
, field_op
.layout
.ty
))
129 .collect
::<InterpResult
<'tcx
, Vec
<_
>>>()?
;
130 let fields
= tcx
.arena
.alloc_from_iter(fields_iter
);
132 Ok(mir
::DestructuredConstant { variant, fields }
)
135 #[instrument(skip(tcx), level = "debug")]
136 pub(crate) fn deref_mir_constant
<'tcx
>(
138 param_env
: ty
::ParamEnv
<'tcx
>,
139 val
: mir
::ConstantKind
<'tcx
>,
140 ) -> mir
::ConstantKind
<'tcx
> {
141 let ecx
= mk_eval_cx(tcx
, DUMMY_SP
, param_env
, false);
142 let op
= ecx
.eval_mir_constant(&val
, None
, None
).unwrap();
143 let mplace
= ecx
.deref_operand(&op
).unwrap();
144 if let Some(alloc_id
) = mplace
.ptr
.provenance
{
146 tcx
.global_alloc(alloc_id
).unwrap_memory().0.0.mutability
,
148 "deref_mir_constant cannot be used with mutable allocations as \
149 that could allow pattern matching to observe mutable statics",
153 let ty
= match mplace
.meta
{
154 MemPlaceMeta
::None
=> mplace
.layout
.ty
,
155 // In case of unsized types, figure out the real type behind.
156 MemPlaceMeta
::Meta(scalar
) => match mplace
.layout
.ty
.kind() {
157 ty
::Str
=> bug
!("there's no sized equivalent of a `str`"),
158 ty
::Slice(elem_ty
) => tcx
.mk_array(*elem_ty
, scalar
.to_machine_usize(&tcx
).unwrap()),
160 "type {} should not have metadata, but had {:?}",
167 mir
::ConstantKind
::Val(op_to_const(&ecx
, &mplace
.into()), ty
)