@@ -10,10 +10,10 @@ use rustc_errors::ErrorReported;
10
10
use rustc_hir as hir;
11
11
use rustc_hir:: def:: DefKind ;
12
12
use rustc_middle:: mir;
13
- use rustc_middle:: mir:: interpret:: ErrorHandled ;
13
+ use rustc_middle:: mir:: interpret:: { ConstDedupResult , ErrorHandled } ;
14
14
use rustc_middle:: mir:: pretty:: display_allocation;
15
15
use rustc_middle:: traits:: Reveal ;
16
- use rustc_middle:: ty:: layout:: LayoutOf ;
16
+ use rustc_middle:: ty:: layout:: { LayoutError , LayoutOf } ;
17
17
use rustc_middle:: ty:: print:: with_no_trimmed_paths;
18
18
use rustc_middle:: ty:: { self , subst:: Subst , TyCtxt } ;
19
19
use rustc_span:: source_map:: Span ;
@@ -28,6 +28,7 @@ pub fn note_on_undefined_behavior_error() -> &'static str {
28
28
}
29
29
30
30
// Returns a pointer to where the result lives
31
+ #[ instrument( skip( ecx, body) , level = "debug" ) ]
31
32
fn eval_body_using_ecx < ' mir , ' tcx > (
32
33
ecx : & mut CompileTimeEvalContext < ' mir , ' tcx > ,
33
34
cid : GlobalId < ' tcx > ,
@@ -160,6 +161,7 @@ pub(super) fn op_to_const<'tcx>(
160
161
ConstValue :: Scalar ( Scalar :: ZST )
161
162
}
162
163
} ;
164
+
163
165
match immediate {
164
166
Ok ( ref mplace) => to_const_value ( mplace) ,
165
167
// see comment on `let try_as_immediate` above
@@ -212,77 +214,76 @@ fn turn_into_const_value<'tcx>(
212
214
op_to_const ( & ecx, & mplace. into ( ) )
213
215
}
214
216
217
+ #[ instrument( skip( tcx) , level = "debug" ) ]
215
218
pub fn eval_to_const_value_raw_provider < ' tcx > (
216
219
tcx : TyCtxt < ' tcx > ,
217
220
key : ty:: ParamEnvAnd < ' tcx , GlobalId < ' tcx > > ,
218
221
) -> :: rustc_middle:: mir:: interpret:: EvalToConstValueResult < ' tcx > {
219
222
assert ! ( key. param_env. constness( ) == hir:: Constness :: Const ) ;
220
- // see comment in eval_to_allocation_raw_provider for what we're doing here
221
- if key. param_env . reveal ( ) == Reveal :: All {
222
- let mut key = key;
223
- key. param_env = key. param_env . with_user_facing ( ) ;
224
- match tcx. eval_to_const_value_raw ( key) {
225
- // try again with reveal all as requested
226
- Err ( ErrorHandled :: TooGeneric ) => { }
227
- // deduplicate calls
228
- other => return other,
229
- }
230
- }
223
+ let ( param_env, id) = key. into_parts ( ) ;
224
+ let reveal = param_env. reveal ( ) ;
231
225
232
226
// We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
233
227
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
234
228
if let ty:: InstanceDef :: Intrinsic ( def_id) = key. value . instance . def {
235
- let ty = key. value . instance . ty ( tcx, key . param_env ) ;
229
+ let ty = key. value . instance . ty ( tcx, param_env) ;
236
230
let substs = match ty. kind ( ) {
237
231
ty:: FnDef ( _, substs) => substs,
238
232
_ => bug ! ( "intrinsic with type {:?}" , ty) ,
239
233
} ;
240
- return eval_nullary_intrinsic ( tcx, key. param_env , def_id, substs) . map_err ( |error| {
241
- let span = tcx. def_span ( def_id) ;
242
- let error = ConstEvalErr { error : error. into_kind ( ) , stacktrace : vec ! [ ] , span } ;
243
- error. report_as_error ( tcx. at ( span) , "could not evaluate nullary intrinsic" )
244
- } ) ;
234
+
235
+ match eval_nullary_intrinsic ( tcx, param_env, def_id, substs) {
236
+ Ok ( val) => {
237
+ // store result for deduplication
238
+ let res = ConstDedupResult :: new ( reveal, val) ;
239
+ tcx. save_const_value_for_dedup ( id, res) ;
240
+
241
+ return Ok ( val) ;
242
+ }
243
+ Err ( e) => {
244
+ let span = tcx. def_span ( def_id) ;
245
+ let error = ConstEvalErr { error : e. into_kind ( ) , stacktrace : vec ! [ ] , span } ;
246
+
247
+ return Err (
248
+ error. report_as_error ( tcx. at ( span) , "could not evaluate nullary intrinsic" )
249
+ ) ;
250
+ }
251
+ }
252
+ }
253
+
254
+ let result =
255
+ tcx. dedup_eval_alloc_raw ( key, None ) . map ( |val| turn_into_const_value ( tcx, val, key) ) ;
256
+
257
+ match result {
258
+ Ok ( val) => {
259
+ tcx. save_const_value_for_dedup ( id, ConstDedupResult :: new ( reveal, val) ) ;
260
+ }
261
+ _ => { }
245
262
}
246
263
247
- tcx . eval_to_allocation_raw ( key ) . map ( |val| turn_into_const_value ( tcx , val , key ) )
264
+ result
248
265
}
249
266
267
+ #[ instrument( skip( tcx) , level = "debug" ) ]
250
268
pub fn eval_to_allocation_raw_provider < ' tcx > (
251
269
tcx : TyCtxt < ' tcx > ,
252
270
key : ty:: ParamEnvAnd < ' tcx , GlobalId < ' tcx > > ,
253
271
) -> :: rustc_middle:: mir:: interpret:: EvalToAllocationRawResult < ' tcx > {
254
272
assert ! ( key. param_env. constness( ) == hir:: Constness :: Const ) ;
255
- // Because the constant is computed twice (once per value of `Reveal`), we are at risk of
256
- // reporting the same error twice here. To resolve this, we check whether we can evaluate the
257
- // constant in the more restrictive `Reveal::UserFacing`, which most likely already was
258
- // computed. For a large percentage of constants that will already have succeeded. Only
259
- // associated constants of generic functions will fail due to not enough monomorphization
260
- // information being available.
261
-
262
- // In case we fail in the `UserFacing` variant, we just do the real computation.
263
- if key. param_env . reveal ( ) == Reveal :: All {
264
- let mut key = key;
265
- key. param_env = key. param_env . with_user_facing ( ) ;
266
- match tcx. eval_to_allocation_raw ( key) {
267
- // try again with reveal all as requested
268
- Err ( ErrorHandled :: TooGeneric ) => { }
269
- // deduplicate calls
270
- other => return other,
271
- }
272
- }
273
+ let ( param_env, cid) = key. into_parts ( ) ;
274
+ let reveal = param_env. reveal ( ) ;
275
+ let def = cid. instance . def . with_opt_param ( ) ;
276
+
273
277
if cfg ! ( debug_assertions) {
274
278
// Make sure we format the instance even if we do not print it.
275
279
// This serves as a regression test against an ICE on printing.
276
280
// The next two lines concatenated contain some discussion:
277
281
// https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/
278
282
// subject/anon_const_instance_printing/near/135980032
279
- let instance = with_no_trimmed_paths ( || key . value . instance . to_string ( ) ) ;
283
+ let instance = with_no_trimmed_paths ( || cid . instance . to_string ( ) ) ;
280
284
trace ! ( "const eval: {:?} ({})" , key, instance) ;
281
285
}
282
286
283
- let cid = key. value ;
284
- let def = cid. instance . def . with_opt_param ( ) ;
285
-
286
287
if let Some ( def) = def. as_local ( ) {
287
288
if tcx. has_typeck_results ( def. did ) {
288
289
if let Some ( error_reported) = tcx. typeck_opt_const_arg ( def) . tainted_by_errors {
@@ -316,6 +317,20 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
316
317
let res = ecx. load_mir ( cid. instance . def , cid. promoted ) ;
317
318
match res. and_then ( |body| eval_body_using_ecx ( & mut ecx, cid, & body) ) {
318
319
Err ( error) => {
320
+ debug ! ( "error from eval_body_using_ecx: {:?}" , error) ;
321
+ if reveal == Reveal :: Selection {
322
+ match error. kind ( ) {
323
+ err_inval ! ( Layout ( LayoutError :: Unknown ( _) ) )
324
+ | err_inval ! ( TooGeneric )
325
+ | err_inval ! ( AlreadyReported ( _) ) => {
326
+ // We do want to report these errors
327
+ }
328
+ _ => {
329
+ return Err ( ErrorHandled :: Silent ) ;
330
+ }
331
+ }
332
+ }
333
+
319
334
let err = ConstEvalErr :: new ( & ecx, error, None ) ;
320
335
// Some CTFE errors raise just a lint, not a hard error; see
321
336
// <https://github.com/rust-lang/rust/issues/71800>.
@@ -328,7 +343,6 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
328
343
// use of broken constant from other crate: always an error
329
344
true
330
345
} ;
331
-
332
346
if is_hard_err {
333
347
let msg = if is_static {
334
348
Cow :: from ( "could not evaluate static initializer" )
@@ -345,7 +359,6 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
345
359
Cow :: from ( "evaluation of constant value failed" )
346
360
}
347
361
} ;
348
-
349
362
Err ( err. report_as_error ( ecx. tcx . at ( ecx. cur_span ( ) ) , & msg) )
350
363
} else {
351
364
let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def. as_local ( ) . unwrap ( ) . did ) ;
@@ -377,10 +390,26 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
377
390
}
378
391
} ;
379
392
let alloc_id = mplace. ptr . provenance . unwrap ( ) ;
393
+
380
394
if let Err ( error) = validation {
381
395
// Validation failed, report an error. This is always a hard error.
382
396
let err = ConstEvalErr :: new ( & ecx, error, None ) ;
383
- Err ( err. struct_error (
397
+
398
+ // FIXME Do we also want to keep these silent with Reveal::Selection?
399
+ if reveal == Reveal :: Selection {
400
+ match err. error {
401
+ err_inval ! ( Layout ( LayoutError :: Unknown ( _) ) )
402
+ | err_inval ! ( TooGeneric )
403
+ | err_inval ! ( AlreadyReported ( _) ) => {
404
+ // We do want to report these errors
405
+ }
406
+ _ => {
407
+ return Err ( ErrorHandled :: Silent ) ;
408
+ }
409
+ }
410
+ }
411
+
412
+ let error = Err ( err. struct_error (
384
413
ecx. tcx ,
385
414
"it is undefined behavior to use this value" ,
386
415
|mut diag| {
@@ -394,10 +423,20 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
394
423
) ) ;
395
424
diag. emit ( ) ;
396
425
} ,
397
- ) )
426
+ ) ) ;
427
+
428
+ debug ! ( ?error) ;
429
+
430
+ error
398
431
} else {
399
432
// Convert to raw constant
400
- Ok ( ConstAlloc { alloc_id, ty : mplace. layout . ty } )
433
+ let const_alloc = ConstAlloc { alloc_id, ty : mplace. layout . ty } ;
434
+ let val = ConstDedupResult :: new ( reveal, const_alloc) ;
435
+
436
+ // store result in order to deduplicate later
437
+ tcx. save_alloc_for_dedup ( cid, val) ;
438
+
439
+ Ok ( const_alloc)
401
440
}
402
441
}
403
442
}
0 commit comments