Skip to content

suppress errors in const eval during selection #81339

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 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -59,6 +59,12 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, impl Module>) {
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 @@ -194,7 +194,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
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
ErrorHandled::TooGeneric => {
bug!("codegen encountered polymorphic constant")
}
ErrorHandled::Silent => {
bug!("silent error encountered codegen for {:?}", operand)
}
}
// Allow RalfJ to sleep soundly knowing that even refactorings that remove
// the above error (or silence it under some conditions) will not cause UB.
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 @@ -72,7 +75,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
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner
/// more or less conservative.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
pub enum Reveal {
// Similar to `Reveal::UserFacing`, except that we also do not emit errors
// when failing const evaluation.
//
// Used by `feature(const_evaluatable_checked)` to allow for `ConstEvaluatable`
// predicates to not hold without emitting an error.
Selection,
/// At type-checking time, we refuse to project any associated
/// type that is marked `default`. Non-`default` ("final") types
/// are always projected. This is necessary in general for
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/consts/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl<'tcx> ConstKind<'tcx> {
// (which may be identity substs, see above),
// can leak through `val` into the const we return.
Ok(val) => Some(Ok(val)),
Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
Err(ErrorHandled::TooGeneric | ErrorHandled::Linted | ErrorHandled::Silent) => None,
Err(ErrorHandled::Reported(e)) => Some(Err(e)),
}
} else {
Expand Down
20 changes: 14 additions & 6 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1768,17 +1768,19 @@ pub struct ParamEnv<'tcx> {
}

unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal {
const BITS: usize = 1;
const BITS: usize = 2;
fn into_usize(self) -> usize {
match self {
traits::Reveal::UserFacing => 0,
traits::Reveal::All => 1,
traits::Reveal::Selection => 0,
traits::Reveal::UserFacing => 1,
traits::Reveal::All => 2,
}
}
unsafe fn from_usize(ptr: usize) -> Self {
match ptr {
0 => traits::Reveal::UserFacing,
1 => traits::Reveal::All,
0 => traits::Reveal::Selection,
1 => traits::Reveal::UserFacing,
2 => traits::Reveal::All,
_ => std::hint::unreachable_unchecked(),
}
}
Expand Down Expand Up @@ -1849,6 +1851,11 @@ impl<'tcx> ParamEnv<'tcx> {
ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) }
}

pub fn with_reveal_selection(mut self) -> Self {
self.packed.set_tag(Reveal::Selection);
self
}

pub fn with_user_facing(mut self) -> Self {
self.packed.set_tag(Reveal::UserFacing);
self
Expand Down Expand Up @@ -1890,7 +1897,7 @@ impl<'tcx> ParamEnv<'tcx> {
/// although the surrounding function is never reachable.
pub fn and<T: TypeFoldable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
match self.reveal() {
Reveal::UserFacing => ParamEnvAnd { param_env: self, value },
Reveal::Selection | Reveal::UserFacing => ParamEnvAnd { param_env: self, value },

Reveal::All => {
if value.is_global() {
Expand Down Expand Up @@ -2561,6 +2568,7 @@ impl<'tcx> AdtDef {
"enum discriminant evaluation failed"
}
ErrorHandled::TooGeneric => "enum discriminant depends on generics",
ErrorHandled::Silent => return None,
};
tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg);
None
Expand Down
71 changes: 53 additions & 18 deletions compiler/rustc_mir/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use rustc_hir::def::DefKind;
use rustc_middle::mir;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::traits::Reveal;
use rustc_middle::ty::layout::LayoutError;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, subst::Subst, TyCtxt};
use rustc_span::source_map::Span;
Expand Down Expand Up @@ -209,14 +210,28 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
// see comment in const_eval_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,
match key.param_env.reveal() {
Reveal::Selection => {}
Reveal::UserFacing => {
let mut key = key;
key.param_env = key.param_env.with_reveal_selection();
match tcx.eval_to_const_value_raw(key) {
// try again with reveal all as requested
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will try again with reveal "user facing" though, won't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, didn't update all the comments yet. Opened this case I wanted other people to look at this PR in case there's a fundamental issue I've missed.

Err(ErrorHandled::Silent) => {}
// deduplicate calls
other => return other,
}
}
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::Silent) => bug!("unexpected error for {:?}", key),
Err(ErrorHandled::TooGeneric) => {}
// deduplicate calls
other => return other,
}
}
}

Expand Down Expand Up @@ -248,18 +263,29 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
// 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You lost this comment.

Also, the Reveal logic here is an exact duplicate of the one above, isn't it? By now it looks non-trivial enough to justify doing some refactoring to share it.

Err(ErrorHandled::TooGeneric) => {}
// deduplicate calls
other => return other,
match key.param_env.reveal() {
Reveal::Selection => {}
Reveal::UserFacing => {
let mut key = key;
key.param_env = key.param_env.with_reveal_selection();
match tcx.eval_to_allocation_raw(key) {
Err(ErrorHandled::Silent) => {}
// deduplicate calls
other => return other,
}
}
Reveal::All => {
let mut key = key;
key.param_env = key.param_env.with_user_facing();
match tcx.eval_to_allocation_raw(key) {
Err(ErrorHandled::Silent) => bug!("unexpected error for {:?}", key),
Err(ErrorHandled::TooGeneric) => {}
// deduplicate calls
other => return other,
}
}
}

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.
Expand Down Expand Up @@ -304,6 +330,15 @@ 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) => {
if key.param_env.reveal() == Reveal::Selection {
match error.kind {
err_inval!(Layout(LayoutError::Unknown(_)))
| err_inval!(TooGeneric)
| err_inval!(AlreadyReported(_)) => {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are those exact three treated differently here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That will cause some new issues though -- it will be much harder to avoid printing the same const error multiple times.

when const eval prints an error the InterpError is AlreadyReported. So we don't return Silent here to prevent emitting the error twice.

err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) because these result in ErrorHandled::TooGeneric which we still want to emit

Probably needs a comment as well ^^

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are quoting me entirely out of context here.^^ In that quote I was referring to "have the query return a Result".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when const eval prints an error the InterpError is AlreadyReported. So we don't return Silent here to prevent emitting the error twice.

Well but it means we hit the code path below for reporting it? Or is report_as_lint et al silent for AlreadyReported?

err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) because these result in ErrorHandled::TooGeneric which we still want to emit

Oh we do? I thought TooGeneric should never be emitted, it means "please re-evaluate with RevealAll?

_ => return Err(ErrorHandled::Silent),
}
}

let err = ConstEvalErr::new(&ecx, error, None);
// errors in statics are always emitted as fatal errors
if is_static {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir/src/monomorphize/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
"collection encountered polymorphic constant: {}",
substituted_constant
),
Err(ErrorHandled::Silent) => span_bug!(
self.body.source_info(location).span,
"silent error emitted during collection",
),
}
}
_ => {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
// and hopefully soon change this to an error.
//
// See #74595 for more details about this.
let concrete = infcx.const_eval_resolve(param_env, def, substs, None, Some(span));
let concrete =
infcx.const_eval_resolve(param_env.with_reveal_selection(), def, substs, None, Some(span));

if concrete.is_ok() && substs.has_param_types_or_consts() {
match infcx.tcx.def_kind(def.did) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let violations = self.tcx.object_safety_violations(did);
report_object_safety_error(self.tcx, span, did, violations)
}
ConstEvalFailure(ErrorHandled::Silent) => {
tcx.sess.struct_span_err(span, "failed to evaluate the given constant")
}
ConstEvalFailure(ErrorHandled::TooGeneric) => {
bug!("too generic should have been handled in `is_const_evaluatable`");
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_trait_selection/src/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,11 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
"ConstEquate: const_eval_resolve returned an unexpected error"
)
}
(Err(ErrorHandled::Silent), _) | (_, Err(ErrorHandled::Silent)) => {
ProcessResult::Error(CodeSelectionError(ConstEvalFailure(
ErrorHandled::Silent,
)))
}
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
ProcessResult::Unchanged
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty,
Reveal::Selection | Reveal::UserFacing => ty,

Reveal::All => {
let recursion_limit = self.tcx().sess.recursion_limit();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty,
Reveal::Selection | Reveal::UserFacing => ty,

Reveal::All => {
let recursion_limit = self.tcx().sess.recursion_limit();
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
self.infcx
.const_eval_resolve(
obligation.param_env,
obligation.param_env.with_reveal_selection(),
def,
substs,
promoted,
Expand All @@ -585,8 +585,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Err(_) => Ok(EvaluatedToErr),
}
}
(Err(ErrorHandled::Reported(ErrorReported)), _)
| (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr),
(Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Silent), _)
| (_, Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Silent)) => {
Ok(EvaluatedToErr)
}
(Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => {
span_bug!(
obligation.cause.span(self.tcx()),
Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/associated-consts/defaults-cyclic-fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ note: ...which requires simplifying constant for the type system `Tr::A`...
|
LL | const A: u8 = Self::B;
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `Tr::A`...
--> $DIR/defaults-cyclic-fail.rs:6:5
|
LL | const A: u8 = Self::B;
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `Tr::A`...
--> $DIR/defaults-cyclic-fail.rs:6:5
|
Expand All @@ -26,6 +31,11 @@ note: ...which requires simplifying constant for the type system `Tr::B`...
|
LL | const B: u8 = Self::A;
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `Tr::B`...
--> $DIR/defaults-cyclic-fail.rs:8:5
|
LL | const B: u8 = Self::A;
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `Tr::B`...
--> $DIR/defaults-cyclic-fail.rs:8:5
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`.
|
LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
|
LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `IMPL_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
|
Expand All @@ -25,6 +30,11 @@ note: ...which requires simplifying constant for the type system `<impl at $DIR/
|
LL | const BAR: u32 = IMPL_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
|
LL | const BAR: u32 = IMPL_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ note: ...which requires simplifying constant for the type system `DEFAULT_REF_BA
|
LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1
|
LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1
|
Expand All @@ -25,6 +30,11 @@ note: ...which requires simplifying constant for the type system `FooDefault::BA
|
LL | const BAR: u32 = DEFAULT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `FooDefault::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
|
LL | const BAR: u32 = DEFAULT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `FooDefault::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
|
Expand Down
Loading