Skip to content

Commit 3a113f1

Browse files
authored
Rollup merge of #82707 - BoxyUwU:errooaaar, r=oli-obk
const_evaluatable_checked: Stop eagerly erroring in `is_const_evaluatable` Fixes #82279 We don't want to be emitting errors inside of is_const_evaluatable because we may call this during selection where it should be able to fail silently There were two errors being emitted in `is_const_evaluatable`. The one causing the compile error in #82279 was inside the match arm for `FailureKind::MentionsParam` but I moved the other error being emitted too since it made things cleaner imo The `NotConstEvaluatable` enum \*should\* have a fourth variant for when we fail to evaluate a concrete const, e.g. `0 - 1` but that cant happen until #81339 cc `@oli-obk` `@lcnr` r? `@nikomatsakis`
2 parents 61edfd5 + 8e353bb commit 3a113f1

File tree

11 files changed

+141
-109
lines changed

11 files changed

+141
-109
lines changed

compiler/rustc_middle/src/mir/abstract_const.rs

+17
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,20 @@ pub enum Node<'tcx> {
1818
UnaryOp(mir::UnOp, NodeId),
1919
FunctionCall(NodeId, &'tcx [NodeId]),
2020
}
21+
22+
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
23+
pub enum NotConstEvaluatable {
24+
Error(rustc_errors::ErrorReported),
25+
MentionsInfer,
26+
MentionsParam,
27+
}
28+
29+
impl From<rustc_errors::ErrorReported> for NotConstEvaluatable {
30+
fn from(e: rustc_errors::ErrorReported) -> NotConstEvaluatable {
31+
NotConstEvaluatable::Error(e)
32+
}
33+
}
34+
35+
TrivialTypeFoldableAndLiftImpls! {
36+
NotConstEvaluatable,
37+
}

compiler/rustc_middle/src/traits/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub mod specialization_graph;
99
mod structural_impls;
1010

1111
use crate::infer::canonical::Canonical;
12-
use crate::mir::interpret::ErrorHandled;
12+
use crate::mir::abstract_const::NotConstEvaluatable;
1313
use crate::ty::subst::SubstsRef;
1414
use crate::ty::{self, AdtKind, Ty, TyCtxt};
1515

@@ -398,7 +398,7 @@ pub enum SelectionError<'tcx> {
398398
ty::error::TypeError<'tcx>,
399399
),
400400
TraitNotObjectSafe(DefId),
401-
ConstEvalFailure(ErrorHandled),
401+
NotConstEvaluatable(NotConstEvaluatable),
402402
Overflow,
403403
}
404404

compiler/rustc_trait_selection/src/traits/const_evaluatable.rs

+13-50
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_hir::def::DefKind;
1313
use rustc_index::bit_set::BitSet;
1414
use rustc_index::vec::IndexVec;
1515
use rustc_infer::infer::InferCtxt;
16-
use rustc_middle::mir::abstract_const::{Node, NodeId};
16+
use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable};
1717
use rustc_middle::mir::interpret::ErrorHandled;
1818
use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
1919
use rustc_middle::ty::subst::{Subst, SubstsRef};
@@ -32,7 +32,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
3232
substs: SubstsRef<'tcx>,
3333
param_env: ty::ParamEnv<'tcx>,
3434
span: Span,
35-
) -> Result<(), ErrorHandled> {
35+
) -> Result<(), NotConstEvaluatable> {
3636
debug!("is_const_evaluatable({:?}, {:?})", def, substs);
3737
if infcx.tcx.features().const_evaluatable_checked {
3838
let tcx = infcx.tcx;
@@ -103,29 +103,10 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
103103

104104
match failure_kind {
105105
FailureKind::MentionsInfer => {
106-
return Err(ErrorHandled::TooGeneric);
106+
return Err(NotConstEvaluatable::MentionsInfer);
107107
}
108108
FailureKind::MentionsParam => {
109-
// FIXME(const_evaluatable_checked): Better error message.
110-
let mut err =
111-
infcx.tcx.sess.struct_span_err(span, "unconstrained generic constant");
112-
let const_span = tcx.def_span(def.did);
113-
// FIXME(const_evaluatable_checked): Update this suggestion once
114-
// explicit const evaluatable bounds are implemented.
115-
if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(const_span)
116-
{
117-
err.span_help(
118-
tcx.def_span(def.did),
119-
&format!("try adding a `where` bound using this expression: `where [u8; {}]: Sized`", snippet),
120-
);
121-
} else {
122-
err.span_help(
123-
const_span,
124-
"consider adding a `where` bound for this expression",
125-
);
126-
}
127-
err.emit();
128-
return Err(ErrorHandled::Reported(ErrorReported));
109+
return Err(NotConstEvaluatable::MentionsParam);
129110
}
130111
FailureKind::Concrete => {
131112
// Dealt with below by the same code which handles this
@@ -180,34 +161,16 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
180161

181162
debug!(?concrete, "is_const_evaluatable");
182163
match concrete {
183-
Err(ErrorHandled::TooGeneric) if !substs.has_infer_types_or_consts() => {
184-
// FIXME(const_evaluatable_checked): We really should move
185-
// emitting this error message to fulfill instead. For
186-
// now this is easier.
187-
//
188-
// This is not a problem without `const_evaluatable_checked` as
189-
// all `ConstEvaluatable` predicates have to be fulfilled for compilation
190-
// to succeed.
191-
//
192-
// @lcnr: We already emit an error for things like
193-
// `fn test<const N: usize>() -> [0 - N]` eagerly here,
194-
// so until we fix this I don't really care.
195-
196-
let mut err = infcx
197-
.tcx
198-
.sess
199-
.struct_span_err(span, "constant expression depends on a generic parameter");
200-
// FIXME(const_generics): we should suggest to the user how they can resolve this
201-
// issue. However, this is currently not actually possible
202-
// (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083).
203-
//
204-
// Note that with `feature(const_evaluatable_checked)` this case should not
205-
// be reachable.
206-
err.note("this may fail depending on what value the parameter takes");
207-
err.emit();
208-
Err(ErrorHandled::Reported(ErrorReported))
164+
Err(ErrorHandled::TooGeneric) => Err(match substs.has_infer_types_or_consts() {
165+
true => NotConstEvaluatable::MentionsInfer,
166+
false => NotConstEvaluatable::MentionsParam,
167+
}),
168+
Err(ErrorHandled::Linted) => {
169+
infcx.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint");
170+
Err(NotConstEvaluatable::Error(ErrorReported))
209171
}
210-
c => c.map(drop),
172+
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
173+
Ok(_) => Ok(()),
211174
}
212175
}
213176

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+51-16
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ pub mod on_unimplemented;
22
pub mod suggestions;
33

44
use super::{
5-
ConstEvalFailure, EvaluationResult, FulfillmentError, FulfillmentErrorCode,
6-
MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
7-
OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow,
8-
PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
5+
EvaluationResult, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
6+
Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective,
7+
OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, PredicateObligation,
8+
SelectionContext, SelectionError, TraitNotObjectSafe,
99
};
1010

1111
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
@@ -17,7 +17,7 @@ use rustc_hir as hir;
1717
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
1818
use rustc_hir::intravisit::Visitor;
1919
use rustc_hir::Node;
20-
use rustc_middle::mir::interpret::ErrorHandled;
20+
use rustc_middle::mir::abstract_const::NotConstEvaluatable;
2121
use rustc_middle::ty::error::ExpectedFound;
2222
use rustc_middle::ty::fold::TypeFolder;
2323
use rustc_middle::ty::{
@@ -738,24 +738,59 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
738738
let violations = self.tcx.object_safety_violations(did);
739739
report_object_safety_error(self.tcx, span, did, violations)
740740
}
741-
ConstEvalFailure(ErrorHandled::TooGeneric) => {
742-
bug!("too generic should have been handled in `is_const_evaluatable`");
741+
742+
SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => {
743+
bug!(
744+
"MentionsInfer should have been handled in `traits/fulfill.rs` or `traits/select/mod.rs`"
745+
)
746+
}
747+
SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => {
748+
if !self.tcx.features().const_evaluatable_checked {
749+
let mut err = self.tcx.sess.struct_span_err(
750+
span,
751+
"constant expression depends on a generic parameter",
752+
);
753+
// FIXME(const_generics): we should suggest to the user how they can resolve this
754+
// issue. However, this is currently not actually possible
755+
// (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083).
756+
//
757+
// Note that with `feature(const_evaluatable_checked)` this case should not
758+
// be reachable.
759+
err.note("this may fail depending on what value the parameter takes");
760+
err.emit();
761+
return;
762+
}
763+
764+
match obligation.predicate.kind().skip_binder() {
765+
ty::PredicateKind::ConstEvaluatable(def, _) => {
766+
let mut err =
767+
self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
768+
let const_span = self.tcx.def_span(def.did);
769+
match self.tcx.sess.source_map().span_to_snippet(const_span) {
770+
Ok(snippet) => err.help(&format!(
771+
"try adding a `where` bound using this expression: `where [(); {}]:`",
772+
snippet
773+
)),
774+
_ => err.help("consider adding a `where` bound using this expression"),
775+
};
776+
err
777+
}
778+
_ => {
779+
span_bug!(
780+
span,
781+
"unexpected non-ConstEvaluatable predicate, this should not be reachable"
782+
)
783+
}
784+
}
743785
}
786+
744787
// Already reported in the query.
745-
ConstEvalFailure(ErrorHandled::Reported(ErrorReported)) => {
788+
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(ErrorReported)) => {
746789
// FIXME(eddyb) remove this once `ErrorReported` becomes a proof token.
747790
self.tcx.sess.delay_span_bug(span, "`ErrorReported` without an error");
748791
return;
749792
}
750793

751-
// Already reported in the query, but only as a lint.
752-
// This shouldn't actually happen for constants used in types, modulo
753-
// bugs. The `delay_span_bug` here ensures it won't be ignored.
754-
ConstEvalFailure(ErrorHandled::Linted) => {
755-
self.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint");
756-
return;
757-
}
758-
759794
Overflow => {
760795
bug!("overflow should be handled before the `report_selection_error` path");
761796
}

compiler/rustc_trait_selection/src/traits/fulfill.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use rustc_data_structures::obligation_forest::ProcessResult;
33
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
44
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
55
use rustc_errors::ErrorReported;
6-
use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation};
6+
use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
7+
use rustc_middle::mir::abstract_const::NotConstEvaluatable;
78
use rustc_middle::mir::interpret::ErrorHandled;
89
use rustc_middle::ty::error::ExpectedFound;
910
use rustc_middle::ty::subst::SubstsRef;
@@ -18,7 +19,7 @@ use super::wf;
1819
use super::CodeAmbiguity;
1920
use super::CodeProjectionError;
2021
use super::CodeSelectionError;
21-
use super::{ConstEvalFailure, Unimplemented};
22+
use super::Unimplemented;
2223
use super::{FulfillmentError, FulfillmentErrorCode};
2324
use super::{ObligationCause, PredicateObligation};
2425

@@ -498,14 +499,19 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
498499
obligation.cause.span,
499500
) {
500501
Ok(()) => ProcessResult::Changed(vec![]),
501-
Err(ErrorHandled::TooGeneric) => {
502+
Err(NotConstEvaluatable::MentionsInfer) => {
502503
pending_obligation.stalled_on.clear();
503504
pending_obligation.stalled_on.extend(
504505
substs.iter().filter_map(TyOrConstInferVar::maybe_from_generic_arg),
505506
);
506507
ProcessResult::Unchanged
507508
}
508-
Err(e) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(e))),
509+
Err(
510+
e @ NotConstEvaluatable::MentionsParam
511+
| e @ NotConstEvaluatable::Error(_),
512+
) => ProcessResult::Error(CodeSelectionError(
513+
SelectionError::NotConstEvaluatable(e),
514+
)),
509515
}
510516
}
511517

@@ -576,11 +582,11 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
576582
}
577583
}
578584
(Err(ErrorHandled::Reported(ErrorReported)), _)
579-
| (_, Err(ErrorHandled::Reported(ErrorReported))) => {
580-
ProcessResult::Error(CodeSelectionError(ConstEvalFailure(
581-
ErrorHandled::Reported(ErrorReported),
582-
)))
583-
}
585+
| (_, Err(ErrorHandled::Reported(ErrorReported))) => ProcessResult::Error(
586+
CodeSelectionError(SelectionError::NotConstEvaluatable(
587+
NotConstEvaluatable::Error(ErrorReported),
588+
)),
589+
),
584590
(Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => {
585591
span_bug!(
586592
obligation.cause.span(self.selcx.tcx()),

compiler/rustc_trait_selection/src/traits/select/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use rustc_hir::def_id::DefId;
3434
use rustc_hir::Constness;
3535
use rustc_infer::infer::LateBoundRegionConversionTime;
3636
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
37+
use rustc_middle::mir::abstract_const::NotConstEvaluatable;
3738
use rustc_middle::mir::interpret::ErrorHandled;
3839
use rustc_middle::ty::fast_reject;
3940
use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -547,7 +548,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
547548
obligation.cause.span,
548549
) {
549550
Ok(()) => Ok(EvaluatedToOk),
550-
Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig),
551+
Err(NotConstEvaluatable::MentionsInfer) => Ok(EvaluatedToAmbig),
552+
Err(NotConstEvaluatable::MentionsParam) => Ok(EvaluatedToErr),
551553
Err(_) => Ok(EvaluatedToErr),
552554
}
553555
}

src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr

+20-16
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,52 @@ error: unconstrained generic constant
33
|
44
LL | let _ = const_evaluatable_lib::test1::<T>();
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6-
|
7-
help: try adding a `where` bound using this expression: `where [u8; std::mem::size_of::<T>() - 1]: Sized`
8-
--> $DIR/auxiliary/const_evaluatable_lib.rs:6:10
6+
|
7+
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10
98
|
109
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
11-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
10+
| ---------------------------- required by this bound in `test1`
11+
|
12+
= help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::<T>() - 1]:`
1213

1314
error: unconstrained generic constant
1415
--> $DIR/cross_crate_predicate.rs:7:13
1516
|
1617
LL | let _ = const_evaluatable_lib::test1::<T>();
1718
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18-
|
19-
help: try adding a `where` bound using this expression: `where [u8; std::mem::size_of::<T>() - 1]: Sized`
20-
--> $DIR/auxiliary/const_evaluatable_lib.rs:4:27
19+
|
20+
::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27
2121
|
2222
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
23-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23+
| ---------------------------- required by this bound in `test1`
24+
|
25+
= help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::<T>() - 1]:`
2426

2527
error: unconstrained generic constant
2628
--> $DIR/cross_crate_predicate.rs:7:13
2729
|
2830
LL | let _ = const_evaluatable_lib::test1::<T>();
2931
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30-
|
31-
help: try adding a `where` bound using this expression: `where [u8; std::mem::size_of::<T>() - 1]: Sized`
32-
--> $DIR/auxiliary/const_evaluatable_lib.rs:6:10
32+
|
33+
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10
3334
|
3435
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
35-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
36+
| ---------------------------- required by this bound in `test1`
37+
|
38+
= help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::<T>() - 1]:`
3639

3740
error: unconstrained generic constant
3841
--> $DIR/cross_crate_predicate.rs:7:13
3942
|
4043
LL | let _ = const_evaluatable_lib::test1::<T>();
4144
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
42-
|
43-
help: try adding a `where` bound using this expression: `where [u8; std::mem::size_of::<T>() - 1]: Sized`
44-
--> $DIR/auxiliary/const_evaluatable_lib.rs:4:27
45+
|
46+
::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27
4547
|
4648
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
47-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49+
| ---------------------------- required by this bound in `test1`
50+
|
51+
= help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::<T>() - 1]:`
4852

4953
error: aborting due to 4 previous errors
5054

src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr

+1-5
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@ error: unconstrained generic constant
44
LL | [0; size_of::<Foo<T>>()]
55
| ^^^^^^^^^^^^^^^^^^^
66
|
7-
help: try adding a `where` bound using this expression: `where [u8; size_of::<Foo<T>>()]: Sized`
8-
--> $DIR/different-fn.rs:10:9
9-
|
10-
LL | [0; size_of::<Foo<T>>()]
11-
| ^^^^^^^^^^^^^^^^^^^
7+
= help: try adding a `where` bound using this expression: `where [(); size_of::<Foo<T>>()]:`
128

139
error: aborting due to previous error
1410

0 commit comments

Comments
 (0)