]>
Commit | Line | Data |
---|---|---|
b7449926 XL |
1 | // Not in interpret to make sure we do not use private implementation details |
2 | ||
f2b60f7d FG |
3 | use crate::errors::MaxNumNodesInConstErr; |
4 | use crate::interpret::{ | |
5 | intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta, | |
6 | Scalar, | |
7 | }; | |
1b1a35ee | 8 | use rustc_hir::Mutability; |
04454e1e | 9 | use rustc_middle::mir; |
923072b8 | 10 | use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; |
ba9703b0 | 11 | use rustc_middle::ty::{self, TyCtxt}; |
dfeec247 | 12 | use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; |
0bf4aa26 | 13 | |
dfeec247 XL |
14 | mod error; |
15 | mod eval_queries; | |
16 | mod fn_queries; | |
17 | mod machine; | |
04454e1e | 18 | mod valtrees; |
0bf4aa26 | 19 | |
dfeec247 XL |
20 | pub use error::*; |
21 | pub use eval_queries::*; | |
22 | pub use fn_queries::*; | |
23 | pub use machine::*; | |
923072b8 | 24 | pub(crate) use valtrees::{const_to_valtree_inner, valtree_to_const_value}; |
b7449926 | 25 | |
ba9703b0 | 26 | pub(crate) fn const_caller_location( |
a2a8927a | 27 | tcx: TyCtxt<'_>, |
e74abb32 | 28 | (file, line, col): (Symbol, u32, u32), |
a2a8927a | 29 | ) -> ConstValue<'_> { |
e74abb32 | 30 | trace!("const_caller_location: {}:{}:{}", file, line, col); |
dfeec247 | 31 | let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false); |
e74abb32 | 32 | |
60c5eb7d | 33 | let loc_place = ecx.alloc_caller_location(file, line, col); |
6a06907d | 34 | if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() { |
29967ef6 XL |
35 | bug!("intern_const_alloc_recursive should not error in this case") |
36 | } | |
04454e1e | 37 | ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx)) |
6a06907d XL |
38 | } |
39 | ||
923072b8 FG |
40 | // We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes. |
41 | const VALTREE_MAX_NODES: usize = 100000; | |
42 | ||
43 | pub(crate) enum ValTreeCreationError { | |
44 | NodesOverflow, | |
45 | NonSupportedType, | |
46 | Other, | |
47 | } | |
48 | pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>; | |
49 | ||
50 | /// Evaluates a constant and turns it into a type-level constant value. | |
51 | pub(crate) fn eval_to_valtree<'tcx>( | |
52 | tcx: TyCtxt<'tcx>, | |
53 | param_env: ty::ParamEnv<'tcx>, | |
54 | cid: GlobalId<'tcx>, | |
55 | ) -> EvalToValTreeResult<'tcx> { | |
56 | let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?; | |
57 | ||
58 | // FIXME Need to provide a span to `eval_to_valtree` | |
59 | let ecx = mk_eval_cx( | |
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. | |
63 | false, | |
64 | ); | |
65 | let place = ecx.raw_const_to_mplace(const_alloc).unwrap(); | |
66 | debug!(?place); | |
67 | ||
68 | let mut num_nodes = 0; | |
69 | let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes); | |
70 | ||
71 | match valtree_result { | |
72 | Ok(valtree) => Ok(Some(valtree)), | |
73 | Err(err) => { | |
74 | let did = cid.instance.def_id(); | |
f2b60f7d | 75 | let global_const_id = cid.display(tcx); |
923072b8 FG |
76 | match err { |
77 | ValTreeCreationError::NodesOverflow => { | |
f2b60f7d FG |
78 | let msg = format!( |
79 | "maximum number of nodes exceeded in constant {}", | |
80 | &global_const_id | |
81 | ); | |
923072b8 | 82 | let mut diag = match tcx.hir().span_if_local(did) { |
f2b60f7d FG |
83 | Some(span) => { |
84 | tcx.sess.create_err(MaxNumNodesInConstErr { span, global_const_id }) | |
85 | } | |
923072b8 FG |
86 | None => tcx.sess.struct_err(&msg), |
87 | }; | |
88 | diag.emit(); | |
89 | ||
90 | Ok(None) | |
91 | } | |
92 | ValTreeCreationError::NonSupportedType | ValTreeCreationError::Other => Ok(None), | |
93 | } | |
94 | } | |
95 | } | |
96 | } | |
97 | ||
923072b8 FG |
98 | #[instrument(skip(tcx), level = "debug")] |
99 | pub(crate) fn try_destructure_mir_constant<'tcx>( | |
dc9dc135 | 100 | tcx: TyCtxt<'tcx>, |
b7449926 | 101 | param_env: ty::ParamEnv<'tcx>, |
923072b8 FG |
102 | val: mir::ConstantKind<'tcx>, |
103 | ) -> InterpResult<'tcx, mir::DestructuredMirConstant<'tcx>> { | |
104 | trace!("destructure_mir_constant: {:?}", val); | |
dfeec247 | 105 | let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); |
923072b8 | 106 | let op = ecx.mir_const_to_op(&val, None)?; |
a1dfa0c6 | 107 | |
ba9703b0 | 108 | // We go to `usize` as we cannot allocate anything bigger anyway. |
5099ac24 | 109 | let (field_count, variant, down) = match val.ty().kind() { |
923072b8 FG |
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) | |
113 | } | |
f035d41b | 114 | ty::Adt(def, _) => { |
5099ac24 FG |
115 | let variant = ecx.read_discriminant(&op)?.1; |
116 | let down = ecx.operand_downcast(&op, variant)?; | |
923072b8 | 117 | (def.variants()[variant].fields.len(), Some(variant), down) |
f035d41b XL |
118 | } |
119 | ty::Tuple(substs) => (substs.len(), None, op), | |
923072b8 | 120 | _ => bug!("cannot destructure mir constant {:?}", val), |
dfeec247 | 121 | }; |
b7449926 | 122 | |
923072b8 | 123 | let fields_iter = (0..field_count) |
5099ac24 FG |
124 | .map(|i| { |
125 | let field_op = ecx.operand_field(&down, i)?; | |
126 | let val = op_to_const(&ecx, &field_op); | |
923072b8 | 127 | Ok(mir::ConstantKind::Val(val, field_op.layout.ty)) |
5099ac24 FG |
128 | }) |
129 | .collect::<InterpResult<'tcx, Vec<_>>>()?; | |
923072b8 | 130 | let fields = tcx.arena.alloc_from_iter(fields_iter); |
b7449926 | 131 | |
923072b8 | 132 | Ok(mir::DestructuredMirConstant { variant, fields }) |
b7449926 | 133 | } |
1b1a35ee | 134 | |
04454e1e | 135 | #[instrument(skip(tcx), level = "debug")] |
923072b8 | 136 | pub(crate) fn deref_mir_constant<'tcx>( |
1b1a35ee XL |
137 | tcx: TyCtxt<'tcx>, |
138 | param_env: ty::ParamEnv<'tcx>, | |
923072b8 FG |
139 | val: mir::ConstantKind<'tcx>, |
140 | ) -> mir::ConstantKind<'tcx> { | |
1b1a35ee | 141 | let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); |
923072b8 | 142 | let op = ecx.mir_const_to_op(&val, None).unwrap(); |
6a06907d | 143 | let mplace = ecx.deref_operand(&op).unwrap(); |
136023e0 | 144 | if let Some(alloc_id) = mplace.ptr.provenance { |
1b1a35ee | 145 | assert_eq!( |
064997fb | 146 | tcx.global_alloc(alloc_id).unwrap_memory().0.0.mutability, |
1b1a35ee | 147 | Mutability::Not, |
923072b8 | 148 | "deref_mir_constant cannot be used with mutable allocations as \ |
1b1a35ee XL |
149 | that could allow pattern matching to observe mutable statics", |
150 | ); | |
151 | } | |
152 | ||
153 | let ty = match mplace.meta { | |
154 | MemPlaceMeta::None => mplace.layout.ty, | |
1b1a35ee XL |
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`"), | |
5099ac24 | 158 | ty::Slice(elem_ty) => tcx.mk_array(*elem_ty, scalar.to_machine_usize(&tcx).unwrap()), |
1b1a35ee XL |
159 | _ => bug!( |
160 | "type {} should not have metadata, but had {:?}", | |
161 | mplace.layout.ty, | |
162 | mplace.meta | |
163 | ), | |
164 | }, | |
165 | }; | |
166 | ||
923072b8 | 167 | mir::ConstantKind::Val(op_to_const(&ecx, &mplace.into()), ty) |
1b1a35ee | 168 | } |