|
1 | 1 | // Not in interpret to make sure we do not use private implementation details |
2 | 2 |
|
3 | | -use std::convert::TryInto; |
4 | | -use std::error::Error; |
5 | | -use std::fmt; |
6 | | -use std::hash::Hash; |
7 | | - |
8 | 3 | use rustc::mir; |
9 | | -use rustc::ty::layout::{self, VariantIdx}; |
| 4 | +use rustc::ty::layout::VariantIdx; |
10 | 5 | use rustc::ty::{self, TyCtxt}; |
11 | 6 |
|
12 | | -use syntax::{ |
13 | | - source_map::{Span, DUMMY_SP}, |
14 | | - symbol::Symbol, |
15 | | -}; |
| 7 | +use syntax::{source_map::DUMMY_SP, symbol::Symbol}; |
16 | 8 |
|
17 | | -use crate::interpret::{ |
18 | | - intern_const_alloc_recursive, Allocation, ConstValue, ImmTy, Immediate, InterpCx, OpTy, Scalar, |
19 | | -}; |
| 9 | +use crate::interpret::{intern_const_alloc_recursive, ConstValue, InterpCx}; |
20 | 10 |
|
21 | 11 | mod error; |
22 | 12 | mod query; |
23 | 13 |
|
24 | 14 | pub use error::*; |
25 | 15 | pub use query::*; |
26 | 16 |
|
27 | | -/// The `InterpCx` is only meant to be used to do field and index projections into constants for |
28 | | -/// `simd_shuffle` and const patterns in match arms. |
29 | | -/// |
30 | | -/// The function containing the `match` that is currently being analyzed may have generic bounds |
31 | | -/// that inform us about the generic bounds of the constant. E.g., using an associated constant |
32 | | -/// of a function's generic parameter will require knowledge about the bounds on the generic |
33 | | -/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. |
34 | | -fn mk_eval_cx<'mir, 'tcx>( |
35 | | - tcx: TyCtxt<'tcx>, |
36 | | - span: Span, |
37 | | - param_env: ty::ParamEnv<'tcx>, |
38 | | - can_access_statics: bool, |
39 | | -) -> CompileTimeEvalContext<'mir, 'tcx> { |
40 | | - debug!("mk_eval_cx: {:?}", param_env); |
41 | | - InterpCx::new( |
42 | | - tcx.at(span), |
43 | | - param_env, |
44 | | - CompileTimeInterpreter::new(), |
45 | | - MemoryExtra { can_access_statics }, |
46 | | - ) |
47 | | -} |
48 | | - |
49 | | -fn op_to_const<'tcx>( |
50 | | - ecx: &CompileTimeEvalContext<'_, 'tcx>, |
51 | | - op: OpTy<'tcx>, |
52 | | -) -> &'tcx ty::Const<'tcx> { |
53 | | - // We do not have value optimizations for everything. |
54 | | - // Only scalars and slices, since they are very common. |
55 | | - // Note that further down we turn scalars of undefined bits back to `ByRef`. These can result |
56 | | - // from scalar unions that are initialized with one of their zero sized variants. We could |
57 | | - // instead allow `ConstValue::Scalar` to store `ScalarMaybeUndef`, but that would affect all |
58 | | - // the usual cases of extracting e.g. a `usize`, without there being a real use case for the |
59 | | - // `Undef` situation. |
60 | | - let try_as_immediate = match op.layout.abi { |
61 | | - layout::Abi::Scalar(..) => true, |
62 | | - layout::Abi::ScalarPair(..) => match op.layout.ty.kind { |
63 | | - ty::Ref(_, inner, _) => match inner.kind { |
64 | | - ty::Slice(elem) => elem == ecx.tcx.types.u8, |
65 | | - ty::Str => true, |
66 | | - _ => false, |
67 | | - }, |
68 | | - _ => false, |
69 | | - }, |
70 | | - _ => false, |
71 | | - }; |
72 | | - let immediate = if try_as_immediate { |
73 | | - Err(ecx.read_immediate(op).expect("normalization works on validated constants")) |
74 | | - } else { |
75 | | - // It is guaranteed that any non-slice scalar pair is actually ByRef here. |
76 | | - // When we come back from raw const eval, we are always by-ref. The only way our op here is |
77 | | - // by-val is if we are in const_field, i.e., if this is (a field of) something that we |
78 | | - // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or |
79 | | - // structs containing such. |
80 | | - op.try_as_mplace() |
81 | | - }; |
82 | | - let val = match immediate { |
83 | | - Ok(mplace) => { |
84 | | - let ptr = mplace.ptr.to_ptr().unwrap(); |
85 | | - let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); |
86 | | - ConstValue::ByRef { alloc, offset: ptr.offset } |
87 | | - } |
88 | | - // see comment on `let try_as_immediate` above |
89 | | - Err(ImmTy { imm: Immediate::Scalar(x), .. }) => match x { |
90 | | - ScalarMaybeUndef::Scalar(s) => ConstValue::Scalar(s), |
91 | | - ScalarMaybeUndef::Undef => { |
92 | | - // When coming out of "normal CTFE", we'll always have an `Indirect` operand as |
93 | | - // argument and we will not need this. The only way we can already have an |
94 | | - // `Immediate` is when we are called from `const_field`, and that `Immediate` |
95 | | - // comes from a constant so it can happen have `Undef`, because the indirect |
96 | | - // memory that was read had undefined bytes. |
97 | | - let mplace = op.assert_mem_place(); |
98 | | - let ptr = mplace.ptr.to_ptr().unwrap(); |
99 | | - let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); |
100 | | - ConstValue::ByRef { alloc, offset: ptr.offset } |
101 | | - } |
102 | | - }, |
103 | | - Err(ImmTy { imm: Immediate::ScalarPair(a, b), .. }) => { |
104 | | - let (data, start) = match a.not_undef().unwrap() { |
105 | | - Scalar::Ptr(ptr) => { |
106 | | - (ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), ptr.offset.bytes()) |
107 | | - } |
108 | | - Scalar::Raw { .. } => ( |
109 | | - ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(b"" as &[u8])), |
110 | | - 0, |
111 | | - ), |
112 | | - }; |
113 | | - let len = b.to_machine_usize(&ecx.tcx.tcx).unwrap(); |
114 | | - let start = start.try_into().unwrap(); |
115 | | - let len: usize = len.try_into().unwrap(); |
116 | | - ConstValue::Slice { data, start, end: start + len } |
117 | | - } |
118 | | - }; |
119 | | - ecx.tcx.mk_const(ty::Const { val: ty::ConstKind::Value(val), ty: op.layout.ty }) |
120 | | -} |
121 | | - |
122 | 17 | /// Extracts a field of a (variant of a) const. |
123 | 18 | // this function uses `unwrap` copiously, because an already validated constant must have valid |
124 | 19 | // fields and can thus never fail outside of compiler bugs |
|
0 commit comments