Skip to content

Commit

Permalink
Rollup merge of rust-lang#67914 - Aaron1011:fix/const-prop-impossible…
Browse files Browse the repository at this point in the history
…, 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.
  • Loading branch information
Centril authored Jan 12, 2020
2 parents eec0cbd + b4125f0 commit c40b394
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 1 deletion.
25 changes: 25 additions & 0 deletions src/librustc_mir/transform/const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,31 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
return;
}

// Check if it's even possible to satisfy the 'where' clauses
// for this item.
// This branch will never be taken for any normal function.
// However, it's possible to `#!feature(trivial_bounds)]` to write
// a function with impossible to satisfy clauses, e.g.:
// `fn foo() where String: Copy {}`
//
// We don't usually need to worry about this kind of case,
// since we would get a compilation error if the user tried
// to call it. However, since we can do const propagation
// even without any calls to the function, we need to make
// sure that it even makes sense to try to evaluate the body.
// If there are unsatisfiable where clauses, then all bets are
// off, and we just give up.
if !tcx.substitute_normalize_and_test_predicates((
source.def_id(),
InternalSubsts::identity_for_item(tcx, source.def_id()),
)) {
trace!(
"ConstProp skipped for item with unsatisfiable predicates: {:?}",
source.def_id()
);
return;
}

trace!("ConstProp starting for {:?}", source.def_id());

let dummy_body = &Body::new(
Expand Down
20 changes: 20 additions & 0 deletions src/test/ui/consts/issue-67696-const-prop-ice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// check-pass
// compile-flags: --emit=mir,link
// Checks that we don't ICE due to attempting to run const prop
// on a function with unsatisifable 'where' clauses

#![allow(unused)]

trait A {
fn foo(&self) -> Self where Self: Copy;
}

impl A for [fn(&())] {
fn foo(&self) -> Self where Self: Copy { *(&[] as &[_]) }
}

impl A for i32 {
fn foo(&self) -> Self { 3 }
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
// run-pass
// check-pass
// compile-flags: --emit=mir,link
// Force mir to be emitted, to ensure that const
// propagation doesn't ICE on a function
// with an 'impossible' body. See issue #67696
// Inconsistent bounds with trait implementations

#![feature(trivial_bounds)]
Expand Down

0 comments on commit c40b394

Please sign in to comment.