@@ -21,6 +21,144 @@ pub fn note_on_undefined_behavior_error() -> &'static str {
21
21
repository if you believe it should not be considered undefined behavior."
22
22
}
23
23
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
+
24
162
fn validate_and_turn_into_const < ' tcx > (
25
163
tcx : TyCtxt < ' tcx > ,
26
164
constant : RawConst < ' tcx > ,
@@ -219,141 +357,3 @@ pub fn const_eval_raw_provider<'tcx>(
219
357
}
220
358
} )
221
359
}
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