Skip to content

Commit deaebac

Browse files
committed
update queries for deduplication
1 parent 910c09b commit deaebac

File tree

4 files changed

+169
-148
lines changed

4 files changed

+169
-148
lines changed

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

Lines changed: 147 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra};
1+
use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalError, MemoryExtra};
22
use crate::interpret::eval_nullary_intrinsic;
33
use crate::interpret::{
44
intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId,
@@ -10,15 +10,16 @@ use rustc_errors::ErrorReported;
1010
use rustc_hir as hir;
1111
use rustc_hir::def::DefKind;
1212
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+
};
1416
use rustc_middle::mir::pretty::display_allocation;
1517
use rustc_middle::traits::Reveal;
16-
use rustc_middle::ty::layout::LayoutOf;
18+
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
1719
use rustc_middle::ty::print::with_no_trimmed_paths;
1820
use rustc_middle::ty::{self, subst::Subst, TyCtxt};
1921
use rustc_span::source_map::Span;
2022
use rustc_target::abi::Abi;
21-
use std::borrow::Cow;
2223
use std::convert::TryInto;
2324

2425
pub fn note_on_undefined_behavior_error() -> &'static str {
@@ -28,6 +29,7 @@ pub fn note_on_undefined_behavior_error() -> &'static str {
2829
}
2930

3031
// Returns a pointer to where the result lives
32+
#[instrument(skip(ecx, body), level = "debug")]
3133
fn eval_body_using_ecx<'mir, 'tcx>(
3234
ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
3335
cid: GlobalId<'tcx>,
@@ -66,6 +68,8 @@ fn eval_body_using_ecx<'mir, 'tcx>(
6668
StackPopCleanup::None { cleanup: false },
6769
)?;
6870

71+
debug!("returned from push_stack_frame");
72+
6973
// The main interpreter loop.
7074
ecx.run()?;
7175

@@ -160,6 +164,7 @@ pub(super) fn op_to_const<'tcx>(
160164
ConstValue::Scalar(Scalar::ZST)
161165
}
162166
};
167+
163168
match immediate {
164169
Ok(ref mplace) => to_const_value(mplace),
165170
// see comment on `let try_as_immediate` above
@@ -212,92 +217,119 @@ fn turn_into_const_value<'tcx>(
212217
op_to_const(&ecx, &mplace.into())
213218
}
214219

220+
#[instrument(skip(tcx), level = "debug")]
215221
pub fn eval_to_const_value_raw_provider<'tcx>(
216222
tcx: TyCtxt<'tcx>,
217223
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
218224
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
219225
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();
231228

232229
// We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
233230
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
234231
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);
236233
let substs = match ty.kind() {
237234
ty::FnDef(_, substs) => substs,
238235
_ => bug!("intrinsic with type {:?}", ty),
239236
};
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+
}
245268
}
246269

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
248282
}
249283

284+
#[instrument(skip(tcx), level = "debug")]
250285
pub fn eval_to_allocation_raw_provider<'tcx>(
251286
tcx: TyCtxt<'tcx>,
252287
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
253288
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
254289
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+
273293
if cfg!(debug_assertions) {
274294
// Make sure we format the instance even if we do not print it.
275295
// This serves as a regression test against an ICE on printing.
276296
// The next two lines concatenated contain some discussion:
277297
// https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/
278298
// 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());
280300
trace!("const eval: {:?} ({})", key, instance);
281301
}
282302

283-
let cid = key.value;
284303
let def = cid.instance.def.with_opt_param();
285304

286305
if let Some(def) = def.as_local() {
287306
if tcx.has_typeck_results(def.did) {
288307
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);
290313
}
291314
}
292315
if !tcx.is_mir_available(def.did) {
293316
tcx.sess.delay_span_bug(
294317
tcx.def_span(def.did),
295318
&format!("no MIR body is available for {:?}", def.did),
296319
);
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);
298326
}
299327
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);
301333
}
302334
}
303335

@@ -316,46 +348,41 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
316348
let res = ecx.load_mir(cid.instance.def, cid.promoted);
317349
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
318350
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
346358
}
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+
);
348369

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+
}
358373
}
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)
359386
}
360387
Ok(mplace) => {
361388
// Since evaluation had no errors, validate the resulting constant.
@@ -377,27 +404,49 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
377404
}
378405
};
379406
let alloc_id = mplace.ptr.provenance.unwrap();
407+
380408
if let Err(error) = validation {
381409
// 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()
396436
},
397-
))
437+
);
438+
439+
Err(error_handled)
398440
} else {
399441
// 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)
401450
}
402451
}
403452
}

0 commit comments

Comments
 (0)