@@ -21,6 +21,144 @@ pub fn note_on_undefined_behavior_error() -> &'static str {
2121 repository if you believe it should not be considered undefined behavior."
2222}
2323
24+ // Returns a pointer to where the result lives
25+ fn eval_body_using_ecx < ' mir , ' tcx > (
26+ ecx : & mut CompileTimeEvalContext < ' mir , ' tcx > ,
27+ cid : GlobalId < ' tcx > ,
28+ body : & ' mir mir:: Body < ' tcx > ,
29+ ) -> InterpResult < ' tcx , MPlaceTy < ' tcx > > {
30+ debug ! ( "eval_body_using_ecx: {:?}, {:?}" , cid, ecx. param_env) ;
31+ let tcx = ecx. tcx . tcx ;
32+ let layout = ecx. layout_of ( body. return_ty ( ) . subst ( tcx, cid. instance . substs ) ) ?;
33+ assert ! ( !layout. is_unsized( ) ) ;
34+ let ret = ecx. allocate ( layout, MemoryKind :: Stack ) ;
35+
36+ let name = ty:: tls:: with ( |tcx| tcx. def_path_str ( cid. instance . def_id ( ) ) ) ;
37+ let prom = cid. promoted . map_or ( String :: new ( ) , |p| format ! ( "::promoted[{:?}]" , p) ) ;
38+ trace ! ( "eval_body_using_ecx: pushing stack frame for global: {}{}" , name, prom) ;
39+
40+ // Assert all args (if any) are zero-sized types; `eval_body_using_ecx` doesn't
41+ // make sense if the body is expecting nontrivial arguments.
42+ // (The alternative would be to use `eval_fn_call` with an args slice.)
43+ for arg in body. args_iter ( ) {
44+ let decl = body. local_decls . get ( arg) . expect ( "arg missing from local_decls" ) ;
45+ let layout = ecx. layout_of ( decl. ty . subst ( tcx, cid. instance . substs ) ) ?;
46+ assert ! ( layout. is_zst( ) )
47+ }
48+
49+ ecx. push_stack_frame (
50+ cid. instance ,
51+ body. span ,
52+ body,
53+ Some ( ret. into ( ) ) ,
54+ StackPopCleanup :: None { cleanup : false } ,
55+ ) ?;
56+
57+ // The main interpreter loop.
58+ ecx. run ( ) ?;
59+
60+ // Intern the result
61+ intern_const_alloc_recursive ( ecx, tcx. static_mutability ( cid. instance . def_id ( ) ) , ret) ?;
62+
63+ debug ! ( "eval_body_using_ecx done: {:?}" , * ret) ;
64+ Ok ( ret)
65+ }
66+
67+ /// The `InterpCx` is only meant to be used to do field and index projections into constants for
68+ /// `simd_shuffle` and const patterns in match arms.
69+ ///
70+ /// The function containing the `match` that is currently being analyzed may have generic bounds
71+ /// that inform us about the generic bounds of the constant. E.g., using an associated constant
72+ /// of a function's generic parameter will require knowledge about the bounds on the generic
73+ /// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument.
74+ pub ( super ) fn mk_eval_cx < ' mir , ' tcx > (
75+ tcx : TyCtxt < ' tcx > ,
76+ span : Span ,
77+ param_env : ty:: ParamEnv < ' tcx > ,
78+ can_access_statics : bool ,
79+ ) -> CompileTimeEvalContext < ' mir , ' tcx > {
80+ debug ! ( "mk_eval_cx: {:?}" , param_env) ;
81+ InterpCx :: new (
82+ tcx. at ( span) ,
83+ param_env,
84+ CompileTimeInterpreter :: new ( ) ,
85+ MemoryExtra { can_access_statics } ,
86+ )
87+ }
88+
89+ pub ( super ) fn op_to_const < ' tcx > (
90+ ecx : & CompileTimeEvalContext < ' _ , ' tcx > ,
91+ op : OpTy < ' tcx > ,
92+ ) -> & ' tcx ty:: Const < ' tcx > {
93+ // We do not have value optimizations for everything.
94+ // Only scalars and slices, since they are very common.
95+ // Note that further down we turn scalars of undefined bits back to `ByRef`. These can result
96+ // from scalar unions that are initialized with one of their zero sized variants. We could
97+ // instead allow `ConstValue::Scalar` to store `ScalarMaybeUndef`, but that would affect all
98+ // the usual cases of extracting e.g. a `usize`, without there being a real use case for the
99+ // `Undef` situation.
100+ let try_as_immediate = match op. layout . abi {
101+ layout:: Abi :: Scalar ( ..) => true ,
102+ layout:: Abi :: ScalarPair ( ..) => match op. layout . ty . kind {
103+ ty:: Ref ( _, inner, _) => match inner. kind {
104+ ty:: Slice ( elem) => elem == ecx. tcx . types . u8 ,
105+ ty:: Str => true ,
106+ _ => false ,
107+ } ,
108+ _ => false ,
109+ } ,
110+ _ => false ,
111+ } ;
112+ let immediate = if try_as_immediate {
113+ Err ( ecx. read_immediate ( op) . expect ( "normalization works on validated constants" ) )
114+ } else {
115+ // It is guaranteed that any non-slice scalar pair is actually ByRef here.
116+ // When we come back from raw const eval, we are always by-ref. The only way our op here is
117+ // by-val is if we are in const_field, i.e., if this is (a field of) something that we
118+ // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or
119+ // structs containing such.
120+ op. try_as_mplace ( )
121+ } ;
122+ let val = match immediate {
123+ Ok ( mplace) => {
124+ let ptr = mplace. ptr . to_ptr ( ) . unwrap ( ) ;
125+ let alloc = ecx. tcx . alloc_map . lock ( ) . unwrap_memory ( ptr. alloc_id ) ;
126+ ConstValue :: ByRef { alloc, offset : ptr. offset }
127+ }
128+ // see comment on `let try_as_immediate` above
129+ Err ( ImmTy { imm : Immediate :: Scalar ( x) , .. } ) => match x {
130+ ScalarMaybeUndef :: Scalar ( s) => ConstValue :: Scalar ( s) ,
131+ ScalarMaybeUndef :: Undef => {
132+ // When coming out of "normal CTFE", we'll always have an `Indirect` operand as
133+ // argument and we will not need this. The only way we can already have an
134+ // `Immediate` is when we are called from `const_field`, and that `Immediate`
135+ // comes from a constant so it can happen have `Undef`, because the indirect
136+ // memory that was read had undefined bytes.
137+ let mplace = op. assert_mem_place ( ) ;
138+ let ptr = mplace. ptr . to_ptr ( ) . unwrap ( ) ;
139+ let alloc = ecx. tcx . alloc_map . lock ( ) . unwrap_memory ( ptr. alloc_id ) ;
140+ ConstValue :: ByRef { alloc, offset : ptr. offset }
141+ }
142+ } ,
143+ Err ( ImmTy { imm : Immediate :: ScalarPair ( a, b) , .. } ) => {
144+ let ( data, start) = match a. not_undef ( ) . unwrap ( ) {
145+ Scalar :: Ptr ( ptr) => {
146+ ( ecx. tcx . alloc_map . lock ( ) . unwrap_memory ( ptr. alloc_id ) , ptr. offset . bytes ( ) )
147+ }
148+ Scalar :: Raw { .. } => (
149+ ecx. tcx . intern_const_alloc ( Allocation :: from_byte_aligned_bytes ( b"" as & [ u8 ] ) ) ,
150+ 0 ,
151+ ) ,
152+ } ;
153+ let len = b. to_machine_usize ( & ecx. tcx . tcx ) . unwrap ( ) ;
154+ let start = start. try_into ( ) . unwrap ( ) ;
155+ let len: usize = len. try_into ( ) . unwrap ( ) ;
156+ ConstValue :: Slice { data, start, end : start + len }
157+ }
158+ } ;
159+ ecx. tcx . mk_const ( ty:: Const { val : ty:: ConstKind :: Value ( val) , ty : op. layout . ty } )
160+ }
161+
24162fn validate_and_turn_into_const < ' tcx > (
25163 tcx : TyCtxt < ' tcx > ,
26164 constant : RawConst < ' tcx > ,
@@ -219,141 +357,3 @@ pub fn const_eval_raw_provider<'tcx>(
219357 }
220358 } )
221359}
222-
223- // Returns a pointer to where the result lives
224- fn eval_body_using_ecx < ' mir , ' tcx > (
225- ecx : & mut CompileTimeEvalContext < ' mir , ' tcx > ,
226- cid : GlobalId < ' tcx > ,
227- body : & ' mir mir:: Body < ' tcx > ,
228- ) -> InterpResult < ' tcx , MPlaceTy < ' tcx > > {
229- debug ! ( "eval_body_using_ecx: {:?}, {:?}" , cid, ecx. param_env) ;
230- let tcx = ecx. tcx . tcx ;
231- let layout = ecx. layout_of ( body. return_ty ( ) . subst ( tcx, cid. instance . substs ) ) ?;
232- assert ! ( !layout. is_unsized( ) ) ;
233- let ret = ecx. allocate ( layout, MemoryKind :: Stack ) ;
234-
235- let name = ty:: tls:: with ( |tcx| tcx. def_path_str ( cid. instance . def_id ( ) ) ) ;
236- let prom = cid. promoted . map_or ( String :: new ( ) , |p| format ! ( "::promoted[{:?}]" , p) ) ;
237- trace ! ( "eval_body_using_ecx: pushing stack frame for global: {}{}" , name, prom) ;
238-
239- // Assert all args (if any) are zero-sized types; `eval_body_using_ecx` doesn't
240- // make sense if the body is expecting nontrivial arguments.
241- // (The alternative would be to use `eval_fn_call` with an args slice.)
242- for arg in body. args_iter ( ) {
243- let decl = body. local_decls . get ( arg) . expect ( "arg missing from local_decls" ) ;
244- let layout = ecx. layout_of ( decl. ty . subst ( tcx, cid. instance . substs ) ) ?;
245- assert ! ( layout. is_zst( ) )
246- }
247-
248- ecx. push_stack_frame (
249- cid. instance ,
250- body. span ,
251- body,
252- Some ( ret. into ( ) ) ,
253- StackPopCleanup :: None { cleanup : false } ,
254- ) ?;
255-
256- // The main interpreter loop.
257- ecx. run ( ) ?;
258-
259- // Intern the result
260- intern_const_alloc_recursive ( ecx, tcx. static_mutability ( cid. instance . def_id ( ) ) , ret) ?;
261-
262- debug ! ( "eval_body_using_ecx done: {:?}" , * ret) ;
263- Ok ( ret)
264- }
265-
266- /// The `InterpCx` is only meant to be used to do field and index projections into constants for
267- /// `simd_shuffle` and const patterns in match arms.
268- ///
269- /// The function containing the `match` that is currently being analyzed may have generic bounds
270- /// that inform us about the generic bounds of the constant. E.g., using an associated constant
271- /// of a function's generic parameter will require knowledge about the bounds on the generic
272- /// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument.
273- pub ( super ) fn mk_eval_cx < ' mir , ' tcx > (
274- tcx : TyCtxt < ' tcx > ,
275- span : Span ,
276- param_env : ty:: ParamEnv < ' tcx > ,
277- can_access_statics : bool ,
278- ) -> CompileTimeEvalContext < ' mir , ' tcx > {
279- debug ! ( "mk_eval_cx: {:?}" , param_env) ;
280- InterpCx :: new (
281- tcx. at ( span) ,
282- param_env,
283- CompileTimeInterpreter :: new ( ) ,
284- MemoryExtra { can_access_statics } ,
285- )
286- }
287-
288- pub ( super ) fn op_to_const < ' tcx > (
289- ecx : & CompileTimeEvalContext < ' _ , ' tcx > ,
290- op : OpTy < ' tcx > ,
291- ) -> & ' tcx ty:: Const < ' tcx > {
292- // We do not have value optimizations for everything.
293- // Only scalars and slices, since they are very common.
294- // Note that further down we turn scalars of undefined bits back to `ByRef`. These can result
295- // from scalar unions that are initialized with one of their zero sized variants. We could
296- // instead allow `ConstValue::Scalar` to store `ScalarMaybeUndef`, but that would affect all
297- // the usual cases of extracting e.g. a `usize`, without there being a real use case for the
298- // `Undef` situation.
299- let try_as_immediate = match op. layout . abi {
300- layout:: Abi :: Scalar ( ..) => true ,
301- layout:: Abi :: ScalarPair ( ..) => match op. layout . ty . kind {
302- ty:: Ref ( _, inner, _) => match inner. kind {
303- ty:: Slice ( elem) => elem == ecx. tcx . types . u8 ,
304- ty:: Str => true ,
305- _ => false ,
306- } ,
307- _ => false ,
308- } ,
309- _ => false ,
310- } ;
311- let immediate = if try_as_immediate {
312- Err ( ecx. read_immediate ( op) . expect ( "normalization works on validated constants" ) )
313- } else {
314- // It is guaranteed that any non-slice scalar pair is actually ByRef here.
315- // When we come back from raw const eval, we are always by-ref. The only way our op here is
316- // by-val is if we are in const_field, i.e., if this is (a field of) something that we
317- // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or
318- // structs containing such.
319- op. try_as_mplace ( )
320- } ;
321- let val = match immediate {
322- Ok ( mplace) => {
323- let ptr = mplace. ptr . to_ptr ( ) . unwrap ( ) ;
324- let alloc = ecx. tcx . alloc_map . lock ( ) . unwrap_memory ( ptr. alloc_id ) ;
325- ConstValue :: ByRef { alloc, offset : ptr. offset }
326- }
327- // see comment on `let try_as_immediate` above
328- Err ( ImmTy { imm : Immediate :: Scalar ( x) , .. } ) => match x {
329- ScalarMaybeUndef :: Scalar ( s) => ConstValue :: Scalar ( s) ,
330- ScalarMaybeUndef :: Undef => {
331- // When coming out of "normal CTFE", we'll always have an `Indirect` operand as
332- // argument and we will not need this. The only way we can already have an
333- // `Immediate` is when we are called from `const_field`, and that `Immediate`
334- // comes from a constant so it can happen have `Undef`, because the indirect
335- // memory that was read had undefined bytes.
336- let mplace = op. assert_mem_place ( ) ;
337- let ptr = mplace. ptr . to_ptr ( ) . unwrap ( ) ;
338- let alloc = ecx. tcx . alloc_map . lock ( ) . unwrap_memory ( ptr. alloc_id ) ;
339- ConstValue :: ByRef { alloc, offset : ptr. offset }
340- }
341- } ,
342- Err ( ImmTy { imm : Immediate :: ScalarPair ( a, b) , .. } ) => {
343- let ( data, start) = match a. not_undef ( ) . unwrap ( ) {
344- Scalar :: Ptr ( ptr) => {
345- ( ecx. tcx . alloc_map . lock ( ) . unwrap_memory ( ptr. alloc_id ) , ptr. offset . bytes ( ) )
346- }
347- Scalar :: Raw { .. } => (
348- ecx. tcx . intern_const_alloc ( Allocation :: from_byte_aligned_bytes ( b"" as & [ u8 ] ) ) ,
349- 0 ,
350- ) ,
351- } ;
352- let len = b. to_machine_usize ( & ecx. tcx . tcx ) . unwrap ( ) ;
353- let start = start. try_into ( ) . unwrap ( ) ;
354- let len: usize = len. try_into ( ) . unwrap ( ) ;
355- ConstValue :: Slice { data, start, end : start + len }
356- }
357- } ;
358- ecx. tcx . mk_const ( ty:: Const { val : ty:: ConstKind :: Value ( val) , ty : op. layout . ty } )
359- }
0 commit comments