1
- use super :: { CompileTimeEvalContext , CompileTimeInterpreter , ConstEvalErr , MemoryExtra } ;
1
+ use super :: { CompileTimeEvalContext , CompileTimeInterpreter , ConstEvalError , MemoryExtra } ;
2
2
use crate :: interpret:: eval_nullary_intrinsic;
3
3
use crate :: interpret:: {
4
4
intern_const_alloc_recursive, Allocation , ConstAlloc , ConstValue , CtfeValidationMode , GlobalId ,
@@ -10,15 +10,16 @@ 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:: {
14
+ ConstDedupError , ConstDedupResult , ConstErrorEmitted , ConstEvalErr , ConstOrigin , ErrorHandled ,
15
+ } ;
14
16
use rustc_middle:: mir:: pretty:: display_allocation;
15
17
use rustc_middle:: traits:: Reveal ;
16
- use rustc_middle:: ty:: layout:: LayoutOf ;
18
+ use rustc_middle:: ty:: layout:: { LayoutError , LayoutOf } ;
17
19
use rustc_middle:: ty:: print:: with_no_trimmed_paths;
18
20
use rustc_middle:: ty:: { self , subst:: Subst , TyCtxt } ;
19
21
use rustc_span:: source_map:: Span ;
20
22
use rustc_target:: abi:: Abi ;
21
- use std:: borrow:: Cow ;
22
23
use std:: convert:: TryInto ;
23
24
24
25
pub fn note_on_undefined_behavior_error ( ) -> & ' static str {
@@ -28,6 +29,7 @@ pub fn note_on_undefined_behavior_error() -> &'static str {
28
29
}
29
30
30
31
// Returns a pointer to where the result lives
32
+ #[ instrument( skip( ecx, body) , level = "debug" ) ]
31
33
fn eval_body_using_ecx < ' mir , ' tcx > (
32
34
ecx : & mut CompileTimeEvalContext < ' mir , ' tcx > ,
33
35
cid : GlobalId < ' tcx > ,
@@ -66,6 +68,8 @@ fn eval_body_using_ecx<'mir, 'tcx>(
66
68
StackPopCleanup :: None { cleanup : false } ,
67
69
) ?;
68
70
71
+ debug ! ( "returned from push_stack_frame" ) ;
72
+
69
73
// The main interpreter loop.
70
74
ecx. run ( ) ?;
71
75
@@ -160,6 +164,7 @@ pub(super) fn op_to_const<'tcx>(
160
164
ConstValue :: Scalar ( Scalar :: ZST )
161
165
}
162
166
} ;
167
+
163
168
match immediate {
164
169
Ok ( ref mplace) => to_const_value ( mplace) ,
165
170
// see comment on `let try_as_immediate` above
@@ -212,92 +217,119 @@ fn turn_into_const_value<'tcx>(
212
217
op_to_const ( & ecx, & mplace. into ( ) )
213
218
}
214
219
220
+ #[ instrument( skip( tcx) , level = "debug" ) ]
215
221
pub fn eval_to_const_value_raw_provider < ' tcx > (
216
222
tcx : TyCtxt < ' tcx > ,
217
223
key : ty:: ParamEnvAnd < ' tcx , GlobalId < ' tcx > > ,
218
224
) -> :: rustc_middle:: mir:: interpret:: EvalToConstValueResult < ' tcx > {
219
225
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
- }
226
+ let ( param_env, id) = key. into_parts ( ) ;
227
+ let reveal = param_env. reveal ( ) ;
231
228
232
229
// We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
233
230
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
234
231
if let ty:: InstanceDef :: Intrinsic ( def_id) = key. value . instance . def {
235
- let ty = key. value . instance . ty ( tcx, key . param_env ) ;
232
+ let ty = key. value . instance . ty ( tcx, param_env) ;
236
233
let substs = match ty. kind ( ) {
237
234
ty:: FnDef ( _, substs) => substs,
238
235
_ => bug ! ( "intrinsic with type {:?}" , ty) ,
239
236
} ;
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
- } ) ;
237
+ match eval_nullary_intrinsic ( tcx, param_env, def_id, substs) {
238
+ Ok ( val) => {
239
+ // store result for deduplication
240
+ let res = ConstDedupResult :: new ( reveal, Ok ( val) , None ) ;
241
+ tcx. save_const_value_for_dedup ( id, res) ;
242
+
243
+ return Ok ( val) ;
244
+ }
245
+ Err ( e) => {
246
+ let span = tcx. def_span ( def_id) ;
247
+ let error = ConstEvalErr { error : e. into_kind ( ) , stacktrace : vec ! [ ] , span } ;
248
+
249
+ let error_handled = tcx. handle_err_for_dedup (
250
+ id,
251
+ ConstOrigin :: ConstValue ,
252
+ error,
253
+ reveal,
254
+ span,
255
+ |e| {
256
+ tcx. report_and_add_error (
257
+ id,
258
+ e,
259
+ span,
260
+ "could not evaluate nullary intrinsic" ,
261
+ )
262
+ } ,
263
+ ) ;
264
+
265
+ return Err ( error_handled) ;
266
+ }
267
+ }
245
268
}
246
269
247
- tcx. eval_to_allocation_raw ( key) . map ( |val| turn_into_const_value ( tcx, val, key) )
270
+ let result =
271
+ tcx. dedup_eval_alloc_raw ( key, None ) . map ( |val| turn_into_const_value ( tcx, val, key) ) ;
272
+
273
+ // store result for deduplication
274
+ let val = ConstDedupResult :: new (
275
+ reveal,
276
+ result. map_err ( |e| ConstDedupError :: new_handled ( e, reveal) ) ,
277
+ None ,
278
+ ) ;
279
+ tcx. save_const_value_for_dedup ( id, val) ;
280
+
281
+ result
248
282
}
249
283
284
+ #[ instrument( skip( tcx) , level = "debug" ) ]
250
285
pub fn eval_to_allocation_raw_provider < ' tcx > (
251
286
tcx : TyCtxt < ' tcx > ,
252
287
key : ty:: ParamEnvAnd < ' tcx , GlobalId < ' tcx > > ,
253
288
) -> :: rustc_middle:: mir:: interpret:: EvalToAllocationRawResult < ' tcx > {
254
289
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
- }
290
+ let ( param_env, cid) = key. into_parts ( ) ;
291
+ let reveal = param_env. reveal ( ) ;
292
+
273
293
if cfg ! ( debug_assertions) {
274
294
// Make sure we format the instance even if we do not print it.
275
295
// This serves as a regression test against an ICE on printing.
276
296
// The next two lines concatenated contain some discussion:
277
297
// https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/
278
298
// subject/anon_const_instance_printing/near/135980032
279
- let instance = with_no_trimmed_paths ( || key . value . instance . to_string ( ) ) ;
299
+ let instance = with_no_trimmed_paths ( || cid . instance . to_string ( ) ) ;
280
300
trace ! ( "const eval: {:?} ({})" , key, instance) ;
281
301
}
282
302
283
- let cid = key. value ;
284
303
let def = cid. instance . def . with_opt_param ( ) ;
285
304
286
305
if let Some ( def) = def. as_local ( ) {
287
306
if tcx. has_typeck_results ( def. did ) {
288
307
if let Some ( error_reported) = tcx. typeck_opt_const_arg ( def) . tainted_by_errors {
289
- return Err ( ErrorHandled :: Reported ( error_reported) ) ;
308
+ let err = ConstErrorEmitted :: Emitted ( ErrorHandled :: Reported ( error_reported) ) ;
309
+ let err_handled =
310
+ tcx. handle_reported_error_for_dedup ( cid, ConstOrigin :: Alloc , err, reveal) ;
311
+
312
+ return Err ( err_handled) ;
290
313
}
291
314
}
292
315
if !tcx. is_mir_available ( def. did ) {
293
316
tcx. sess . delay_span_bug (
294
317
tcx. def_span ( def. did ) ,
295
318
& format ! ( "no MIR body is available for {:?}" , def. did) ,
296
319
) ;
297
- return Err ( ErrorHandled :: Reported ( ErrorReported { } ) ) ;
320
+
321
+ let err = ConstErrorEmitted :: Emitted ( ErrorHandled :: Reported ( ErrorReported { } ) ) ;
322
+ let err_handled =
323
+ tcx. handle_reported_error_for_dedup ( cid, ConstOrigin :: Alloc , err, reveal) ;
324
+
325
+ return Err ( err_handled) ;
298
326
}
299
327
if let Some ( error_reported) = tcx. mir_const_qualif_opt_const_arg ( def) . error_occured {
300
- return Err ( ErrorHandled :: Reported ( error_reported) ) ;
328
+ let err = ConstErrorEmitted :: Emitted ( ErrorHandled :: Reported ( error_reported) ) ;
329
+ let err_handled =
330
+ tcx. handle_reported_error_for_dedup ( cid, ConstOrigin :: Alloc , err, reveal) ;
331
+
332
+ return Err ( err_handled) ;
301
333
}
302
334
}
303
335
@@ -316,46 +348,41 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
316
348
let res = ecx. load_mir ( cid. instance . def , cid. promoted ) ;
317
349
match res. and_then ( |body| eval_body_using_ecx ( & mut ecx, cid, & body) ) {
318
350
Err ( error) => {
319
- let err = ConstEvalErr :: new ( & ecx, error, None ) ;
320
- // Some CTFE errors raise just a lint, not a hard error; see
321
- // <https://github.com/rust-lang/rust/issues/71800>.
322
- let is_hard_err = if let Some ( def) = def. as_local ( ) {
323
- // (Associated) consts only emit a lint, since they might be unused.
324
- !matches ! ( tcx. def_kind( def. did. to_def_id( ) ) , DefKind :: Const | DefKind :: AssocConst )
325
- // check if the inner InterpError is hard
326
- || err. error . is_hard_err ( )
327
- } else {
328
- // use of broken constant from other crate: always an error
329
- true
330
- } ;
331
-
332
- if is_hard_err {
333
- let msg = if is_static {
334
- Cow :: from ( "could not evaluate static initializer" )
335
- } else {
336
- // If the current item has generics, we'd like to enrich the message with the
337
- // instance and its substs: to show the actual compile-time values, in addition to
338
- // the expression, leading to the const eval error.
339
- let instance = & key. value . instance ;
340
- if !instance. substs . is_empty ( ) {
341
- let instance = with_no_trimmed_paths ( || instance. to_string ( ) ) ;
342
- let msg = format ! ( "evaluation of `{}` failed" , instance) ;
343
- Cow :: from ( msg)
344
- } else {
345
- Cow :: from ( "evaluation of constant value failed" )
351
+ debug ! ( "error from eval_body_using_ecx: {:?}" , error) ;
352
+ if reveal == Reveal :: Selection {
353
+ match error. kind ( ) {
354
+ err_inval ! ( Layout ( LayoutError :: Unknown ( _) ) )
355
+ | err_inval ! ( TooGeneric )
356
+ | err_inval ! ( AlreadyReported ( _) ) => {
357
+ // We do want to report these errors
346
358
}
347
- } ;
359
+ _ => {
360
+ let err = ConstEvalError :: new ( & ecx, error, None ) ;
361
+ let error_handled = tcx. handle_err_for_dedup (
362
+ cid,
363
+ ConstOrigin :: Alloc ,
364
+ err. into_inner ( ) ,
365
+ reveal,
366
+ ecx. cur_span ( ) ,
367
+ |_e| ErrorHandled :: Silent ( cid) ,
368
+ ) ;
348
369
349
- Err ( err. report_as_error ( ecx. tcx . at ( ecx. cur_span ( ) ) , & msg) )
350
- } else {
351
- let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def. as_local ( ) . unwrap ( ) . did ) ;
352
- Err ( err. report_as_lint (
353
- tcx. at ( tcx. def_span ( def. did ) ) ,
354
- "any use of this value will cause an error" ,
355
- hir_id,
356
- Some ( err. span ) ,
357
- ) )
370
+ return Err ( error_handled) ;
371
+ }
372
+ }
358
373
}
374
+
375
+ let err = ConstEvalError :: new ( & ecx, error, None ) ;
376
+ let err_handled = tcx. handle_err_for_dedup (
377
+ cid,
378
+ ConstOrigin :: Alloc ,
379
+ err. into_inner ( ) ,
380
+ reveal,
381
+ ecx. cur_span ( ) ,
382
+ |e| tcx. report_alloc_error ( cid, param_env, e, is_static, def, ecx. cur_span ( ) ) ,
383
+ ) ;
384
+
385
+ Err ( err_handled)
359
386
}
360
387
Ok ( mplace) => {
361
388
// Since evaluation had no errors, validate the resulting constant.
@@ -377,27 +404,49 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
377
404
}
378
405
} ;
379
406
let alloc_id = mplace. ptr . provenance . unwrap ( ) ;
407
+
380
408
if let Err ( error) = validation {
381
409
// Validation failed, report an error. This is always a hard error.
382
- let err = ConstEvalErr :: new ( & ecx, error, None ) ;
383
- Err ( err. struct_error (
384
- ecx. tcx ,
385
- "it is undefined behavior to use this value" ,
386
- |mut diag| {
387
- diag. note ( note_on_undefined_behavior_error ( ) ) ;
388
- diag. note ( & format ! (
389
- "the raw bytes of the constant ({}" ,
390
- display_allocation(
391
- * ecx. tcx,
392
- ecx. tcx. global_alloc( alloc_id) . unwrap_memory( )
393
- )
394
- ) ) ;
395
- diag. emit ( ) ;
410
+ let err = ConstEvalError :: new ( & ecx, error, None ) . into_inner ( ) ;
411
+
412
+ // FIXME: Do we also want to keep these silent with Reveal::Selection?
413
+ let error_handled = tcx. handle_err_for_dedup (
414
+ cid,
415
+ ConstOrigin :: Alloc ,
416
+ err,
417
+ reveal,
418
+ ecx. cur_span ( ) ,
419
+ |e| {
420
+ e. struct_error (
421
+ ecx. tcx ,
422
+ "it is undefined behavior to use this value" ,
423
+ |mut diag| {
424
+ diag. note ( note_on_undefined_behavior_error ( ) ) ;
425
+ diag. note ( & format ! (
426
+ "the raw bytes of the constant ({}" ,
427
+ display_allocation(
428
+ * ecx. tcx,
429
+ ecx. tcx. global_alloc( alloc_id) . unwrap_memory( )
430
+ )
431
+ ) ) ;
432
+ diag. emit ( ) ;
433
+ } ,
434
+ )
435
+ . get_error ( )
396
436
} ,
397
- ) )
437
+ ) ;
438
+
439
+ Err ( error_handled)
398
440
} else {
399
441
// Convert to raw constant
400
- Ok ( ConstAlloc { alloc_id, ty : mplace. layout . ty } )
442
+ let const_alloc = ConstAlloc { alloc_id, ty : mplace. layout . ty } ;
443
+ let result = Ok ( const_alloc) ;
444
+ let val = ConstDedupResult :: new ( reveal, result, None ) ;
445
+
446
+ // store result in order to deduplicate later
447
+ tcx. save_alloc_for_dedup ( cid, val) ;
448
+
449
+ Ok ( const_alloc)
401
450
}
402
451
}
403
452
}
0 commit comments