Skip to content

Commit 171fe82

Browse files
committed
Filter and test predicates using normalize_and_test_predicates for const-prop
Fixes #68264 Previously, I attempted to use `substitute_normalize_and_test_predicates` to detect unsatisfiable bounds. Unfortunately, since const-prop runs in a generic environment (we don't have any of the function's generic parameters substituted), this could lead to cycle errors when attempting to normalize predicates. This check is replaced with a more precise check. We now only call `normalize_and_test_predicates` on predicates that have the possibility of being proved unsatisfiable - that is, predicates that don't depend on anything local to the function (e.g. generic parameters). This ensures that we don't hit cycle errors when we normalize said predicates, while still ensuring that we detect unsatisfiable predicates.
1 parent d088d8a commit 171fe82

File tree

1 file changed

+22
-22
lines changed

1 file changed

+22
-22
lines changed

Diff for: src/librustc_mir/transform/const_prop.rs

+22-22
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc::mir::{
1414
SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind,
1515
UnOp, RETURN_PLACE,
1616
};
17-
use rustc::traits::TraitQueryMode;
17+
use rustc::traits;
1818
use rustc::ty::layout::{
1919
HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout,
2020
};
@@ -90,28 +90,28 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
9090
// If there are unsatisfiable where clauses, then all bets are
9191
// off, and we just give up.
9292
//
93-
// Note that we use TraitQueryMode::Canonical here, which causes
94-
// us to treat overflow like any other error. This is because we
95-
// are "speculatively" evaluating this item with the default substs.
96-
// While this usually succeeds, it may fail with tricky impls
97-
// (e.g. the typenum crate). Const-propagation is fundamentally
98-
// "best-effort", and does not affect correctness in any way.
99-
// Therefore, it's perfectly fine to just "give up" if we're
100-
// unable to check the bounds with the default substs.
93+
// We manually filter the predicates, skipping anything that's not
94+
// "global". We are in a potentially generic context
95+
// (e.g. we are evaluating a function without substituging generic
96+
// parameters, so this filtering serves two purposes:
10197
//
102-
// False negatives (failing to run const-prop on something when we actually
103-
// could) are fine. However, false positives (running const-prop on
104-
// an item with unsatisfiable bounds) can lead to us generating invalid
105-
// MIR.
106-
if !tcx.substitute_normalize_and_test_predicates((
107-
source.def_id(),
108-
InternalSubsts::identity_for_item(tcx, source.def_id()),
109-
TraitQueryMode::Canonical,
110-
)) {
111-
trace!(
112-
"ConstProp skipped for item with unsatisfiable predicates: {:?}",
113-
source.def_id()
114-
);
98+
// 1. We skip evaluating any predicates that we would
99+
// never be able prove are unsatisfiable (e.g. `<T as Foo>`
100+
// 2. We avoid trying to normalize predicates involving generic
101+
// parameters (e.g. `<T as Foo>::MyItem`). This can confuse
102+
// the normalization code (leading to cycle errors), since
103+
// it's usually never invoked in this way.
104+
let predicates = tcx
105+
.predicates_of(source.def_id())
106+
.predicates
107+
.iter()
108+
.filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None })
109+
.collect();
110+
if !traits::normalize_and_test_predicates(
111+
tcx,
112+
traits::elaborate_predicates(tcx, predicates).collect(),
113+
) {
114+
trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", source.def_id());
115115
return;
116116
}
117117

0 commit comments

Comments
 (0)