Skip to content

Suppress errors in const eval during trait selection v2 #92674

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
6 changes: 6 additions & 0 deletions compiler/rustc_codegen_cranelift/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
err
);
}
ErrorHandled::Silent => {
span_bug!(
constant.span,
"codegen encountered silent error",
);
}
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// errored or at least linted
ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {}
ErrorHandled::TooGeneric => {
span_bug!(const_.span, "codgen encountered polymorphic constant: {:?}", err)
span_bug!(const_.span, "codegen encountered polymorphic constant: {:?}", err)
}
ErrorHandled::Silent => {
span_bug!(const_.span, "silent error during codegen")
}
}
}
Expand Down
119 changes: 73 additions & 46 deletions compiler/rustc_const_eval/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc_middle::mir;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::mir::pretty::display_allocation;
use rustc_middle::traits::Reveal;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, subst::Subst, TyCtxt};
use rustc_span::source_map::Span;
Expand All @@ -28,6 +28,7 @@ pub fn note_on_undefined_behavior_error() -> &'static str {
}

// Returns a pointer to where the result lives
#[instrument(skip(ecx, body), level = "debug")]
fn eval_body_using_ecx<'mir, 'tcx>(
ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
cid: GlobalId<'tcx>,
Expand Down Expand Up @@ -160,6 +161,7 @@ pub(super) fn op_to_const<'tcx>(
ConstValue::Scalar(Scalar::ZST)
}
};

match immediate {
Ok(ref mplace) => to_const_value(mplace),
// see comment on `let try_as_immediate` above
Expand Down Expand Up @@ -212,77 +214,65 @@ fn turn_into_const_value<'tcx>(
op_to_const(&ecx, &mplace.into())
}

#[instrument(skip(tcx), level = "debug")]
pub fn eval_to_const_value_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
assert!(key.param_env.constness() == hir::Constness::Const);
// see comment in eval_to_allocation_raw_provider for what we're doing here
if key.param_env.reveal() == Reveal::All {
let mut key = key;
key.param_env = key.param_env.with_user_facing();
match tcx.eval_to_const_value_raw(key) {
// try again with reveal all as requested
Err(ErrorHandled::TooGeneric) => {}
// deduplicate calls
other => return other,
}
}
let (param_env, id) = key.into_parts();
let reveal = param_env.reveal();

// We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def {
let ty = key.value.instance.ty(tcx, key.param_env);
let ty = key.value.instance.ty(tcx, param_env);
let substs = match ty.kind() {
ty::FnDef(_, substs) => substs,
_ => bug!("intrinsic with type {:?}", ty),
};
return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| {
let span = tcx.def_span(def_id);
let error = ConstEvalErr { error: error.into_kind(), stacktrace: vec![], span };
error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic")
});

match eval_nullary_intrinsic(tcx, param_env, def_id, substs) {
Ok(val) => {
// store result for deduplication
tcx.save_const_value_for_dedup(id, reveal);

return Ok(val);
}
Err(e) => {
let span = tcx.def_span(def_id);
let error = ConstEvalErr { error: e.into_kind(), stacktrace: vec![], span };

return Err(
error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic")
);
}
}
}

tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
tcx.dedup_eval_alloc_raw(key, None).map(|val| turn_into_const_value(tcx, val, key))
}

#[instrument(skip(tcx), level = "debug")]
pub fn eval_to_allocation_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
assert!(key.param_env.constness() == hir::Constness::Const);
// Because the constant is computed twice (once per value of `Reveal`), we are at risk of
// reporting the same error twice here. To resolve this, we check whether we can evaluate the
// constant in the more restrictive `Reveal::UserFacing`, which most likely already was
// computed. For a large percentage of constants that will already have succeeded. Only
// associated constants of generic functions will fail due to not enough monomorphization
// information being available.

// In case we fail in the `UserFacing` variant, we just do the real computation.
if key.param_env.reveal() == Reveal::All {
let mut key = key;
key.param_env = key.param_env.with_user_facing();
match tcx.eval_to_allocation_raw(key) {
// try again with reveal all as requested
Err(ErrorHandled::TooGeneric) => {}
// deduplicate calls
other => return other,
}
}
let (param_env, cid) = key.into_parts();
let reveal = param_env.reveal();
let def = cid.instance.def.with_opt_param();

if cfg!(debug_assertions) {
// Make sure we format the instance even if we do not print it.
// This serves as a regression test against an ICE on printing.
// The next two lines concatenated contain some discussion:
// https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/
// subject/anon_const_instance_printing/near/135980032
let instance = with_no_trimmed_paths(|| key.value.instance.to_string());
let instance = with_no_trimmed_paths(|| cid.instance.to_string());
trace!("const eval: {:?} ({})", key, instance);
}

let cid = key.value;
let def = cid.instance.def.with_opt_param();

if let Some(def) = def.as_local() {
if tcx.has_typeck_results(def.did) {
if let Some(error_reported) = tcx.typeck_opt_const_arg(def).tainted_by_errors {
Expand Down Expand Up @@ -316,6 +306,20 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
let res = ecx.load_mir(cid.instance.def, cid.promoted);
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
Err(error) => {
debug!("error from eval_body_using_ecx: {:?}", error);
if reveal == Reveal::Selection {
match error.kind() {
err_inval!(Layout(LayoutError::Unknown(_)))
| err_inval!(TooGeneric)
| err_inval!(AlreadyReported(_)) => {
// We do want to report these errors
}
_ => {
return Err(ErrorHandled::Silent);
}
}
}

let err = ConstEvalErr::new(&ecx, error, None);
// Some CTFE errors raise just a lint, not a hard error; see
// <https://github.com/rust-lang/rust/issues/71800>.
Expand All @@ -328,7 +332,6 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
// use of broken constant from other crate: always an error
true
};

if is_hard_err {
let msg = if is_static {
Cow::from("could not evaluate static initializer")
Expand All @@ -345,7 +348,6 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
Cow::from("evaluation of constant value failed")
}
};

Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), &msg))
} else {
let hir_id = tcx.hir().local_def_id_to_hir_id(def.as_local().unwrap().did);
Expand Down Expand Up @@ -377,10 +379,26 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
}
};
let alloc_id = mplace.ptr.provenance.unwrap();

if let Err(error) = validation {
// Validation failed, report an error. This is always a hard error.
let err = ConstEvalErr::new(&ecx, error, None);
Err(err.struct_error(

// FIXME Do we also want to keep these silent with Reveal::Selection?
if reveal == Reveal::Selection {
match err.error {
err_inval!(Layout(LayoutError::Unknown(_)))
| err_inval!(TooGeneric)
| err_inval!(AlreadyReported(_)) => {
// We do want to report these errors
}
_ => {
return Err(ErrorHandled::Silent);
}
}
}

let error = Err(err.struct_error(
ecx.tcx,
"it is undefined behavior to use this value",
|mut diag| {
Expand All @@ -394,10 +412,19 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
));
diag.emit();
},
))
));

debug!(?error);

error
} else {
// Convert to raw constant
Ok(ConstAlloc { alloc_id, ty: mplace.layout.ty })
let const_alloc = ConstAlloc { alloc_id, ty: mplace.layout.ty };

// store information that allows deduplication
tcx.save_alloc_for_dedup(cid, reveal);

Ok(const_alloc)
}
}
}
Expand Down
12 changes: 8 additions & 4 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ use rustc_middle::ty::{
use rustc_mir_dataflow::storage::AlwaysLiveLocals;
use rustc_query_system::ich::StableHashingContext;
use rustc_session::Limit;
use rustc_span::{Pos, Span};
use rustc_span::Pos;
use rustc_span::Span;
use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout};

use super::{
Expand Down Expand Up @@ -809,7 +810,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// cause us to continue unwinding.
pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx> {
info!(
"popping stack frame ({})",
"popping following stack frame ({})",
if unwinding { "during unwinding" } else { "returning from function" }
);

Expand Down Expand Up @@ -926,6 +927,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ok(())
}

#[instrument(skip(self), level = "debug")]
pub fn eval_to_allocation(
&self,
gid: GlobalId<'tcx>,
Expand All @@ -941,8 +943,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.param_env
};
let param_env = param_env.with_const();
let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?;
self.raw_const_to_mplace(val)
let val = self.tcx.dedup_eval_alloc_raw(param_env.and(gid), None);
debug!(?val);

self.raw_const_to_mplace(val?)
}

#[must_use]
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_middle/src/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub enum ErrorHandled {
Reported(ErrorReported),
/// Already emitted a lint for this evaluation.
Linted,
/// Encountered an error without emitting anything. Only returned
/// with `Reveal::Selection`.
Silent,
/// Don't emit an error, the evaluation failed because the MIR was generic
/// and the substs didn't fully monomorphize it.
TooGeneric,
Expand Down Expand Up @@ -88,7 +91,7 @@ fn print_backtrace(backtrace: &Backtrace) {
impl From<ErrorHandled> for InterpErrorInfo<'_> {
fn from(err: ErrorHandled) -> Self {
match err {
ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {
ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted | ErrorHandled::Silent => {
err_inval!(ReferencedConstant)
}
ErrorHandled::TooGeneric => err_inval!(TooGeneric),
Expand Down
Loading