Skip to content

Commit c40b394

Browse files
authored
Rollup merge of rust-lang#67914 - Aaron1011:fix/const-prop-impossible, r=matthewjasper
Don't run const propagation on items with inconsistent bounds Fixes rust-lang#67696 Using `#![feature(trivial_bounds)]`, it's possible to write functions with unsatisfiable 'where' clauses, making them uncallable. However, the user can act as if these 'where' clauses are true inside the body of the function, leading to code that would normally be impossible to write. Since const propgation can run even without any user-written calls to a function, we need to explcitly check for these uncallable functions.
2 parents eec0cbd + b4125f0 commit c40b394

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

src/librustc_mir/transform/const_prop.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,31 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
7474
return;
7575
}
7676

77+
// Check if it's even possible to satisfy the 'where' clauses
78+
// for this item.
79+
// This branch will never be taken for any normal function.
80+
// However, it's possible to `#!feature(trivial_bounds)]` to write
81+
// a function with impossible to satisfy clauses, e.g.:
82+
// `fn foo() where String: Copy {}`
83+
//
84+
// We don't usually need to worry about this kind of case,
85+
// since we would get a compilation error if the user tried
86+
// to call it. However, since we can do const propagation
87+
// even without any calls to the function, we need to make
88+
// sure that it even makes sense to try to evaluate the body.
89+
// If there are unsatisfiable where clauses, then all bets are
90+
// off, and we just give up.
91+
if !tcx.substitute_normalize_and_test_predicates((
92+
source.def_id(),
93+
InternalSubsts::identity_for_item(tcx, source.def_id()),
94+
)) {
95+
trace!(
96+
"ConstProp skipped for item with unsatisfiable predicates: {:?}",
97+
source.def_id()
98+
);
99+
return;
100+
}
101+
77102
trace!("ConstProp starting for {:?}", source.def_id());
78103

79104
let dummy_body = &Body::new(
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// check-pass
2+
// compile-flags: --emit=mir,link
3+
// Checks that we don't ICE due to attempting to run const prop
4+
// on a function with unsatisifable 'where' clauses
5+
6+
#![allow(unused)]
7+
8+
trait A {
9+
fn foo(&self) -> Self where Self: Copy;
10+
}
11+
12+
impl A for [fn(&())] {
13+
fn foo(&self) -> Self where Self: Copy { *(&[] as &[_]) }
14+
}
15+
16+
impl A for i32 {
17+
fn foo(&self) -> Self { 3 }
18+
}
19+
20+
fn main() {}

src/test/ui/trivial-bounds/trivial-bounds-inconsistent-associated-functions.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
// run-pass
1+
// check-pass
2+
// compile-flags: --emit=mir,link
3+
// Force mir to be emitted, to ensure that const
4+
// propagation doesn't ICE on a function
5+
// with an 'impossible' body. See issue #67696
26
// Inconsistent bounds with trait implementations
37

48
#![feature(trivial_bounds)]

0 commit comments

Comments
 (0)