Skip to content

Commit 7e4b8d7

Browse files
committed
Auto merge of #146659 - cjgillot:impossible-taint, r=oli-obk
Consider errors in MIR as impossible predicates to empty the body. The ICEs come from elaborating drops or performing state transform in MIR bodies that fail typeck or borrowck. If the body is tainted, replace it with `unreachable`. Fixes #122630 Fixes #122904 Fixes #125185 Fixes #139556
2 parents 6710835 + 3934fc9 commit 7e4b8d7

13 files changed

+201
-61
lines changed

compiler/rustc_mir_transform/src/impossible_predicates.rs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,30 +28,37 @@
2828
2929
use rustc_middle::mir::{Body, START_BLOCK, TerminatorKind};
3030
use rustc_middle::ty::{TyCtxt, TypeFlags, TypeVisitableExt};
31+
use rustc_span::def_id::DefId;
3132
use rustc_trait_selection::traits;
3233
use tracing::trace;
3334

3435
use crate::pass_manager::MirPass;
3536

3637
pub(crate) struct ImpossiblePredicates;
3738

39+
fn has_impossible_predicates(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
40+
let predicates = tcx.predicates_of(def_id).instantiate_identity(tcx);
41+
tracing::trace!(?predicates);
42+
let predicates = predicates.predicates.into_iter().filter(|p| {
43+
!p.has_type_flags(
44+
// Only consider global clauses to simplify.
45+
TypeFlags::HAS_FREE_LOCAL_NAMES
46+
// Clauses that refer to unevaluated constants as they cause cycles.
47+
| TypeFlags::HAS_CT_PROJECTION,
48+
)
49+
});
50+
let predicates: Vec<_> = traits::elaborate(tcx, predicates).collect();
51+
tracing::trace!(?predicates);
52+
predicates.references_error() || traits::impossible_predicates(tcx, predicates)
53+
}
54+
3855
impl<'tcx> MirPass<'tcx> for ImpossiblePredicates {
3956
#[tracing::instrument(level = "trace", skip(self, tcx, body))]
4057
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
4158
tracing::trace!(def_id = ?body.source.def_id());
42-
let predicates = tcx.predicates_of(body.source.def_id()).instantiate_identity(tcx);
43-
tracing::trace!(?predicates);
44-
let predicates = predicates.predicates.into_iter().filter(|p| {
45-
!p.has_type_flags(
46-
// Only consider global clauses to simplify.
47-
TypeFlags::HAS_FREE_LOCAL_NAMES
48-
// Clauses that refer to unevaluated constants as they cause cycles.
49-
| TypeFlags::HAS_CT_PROJECTION,
50-
)
51-
});
52-
let predicates: Vec<_> = traits::elaborate(tcx, predicates).collect();
53-
tracing::trace!(?predicates);
54-
if predicates.references_error() || traits::impossible_predicates(tcx, predicates) {
59+
let impossible = body.tainted_by_errors.is_some()
60+
|| has_impossible_predicates(tcx, body.source.def_id());
61+
if impossible {
5562
trace!("found unsatisfiable predicates");
5663
// Clear the body to only contain a single `unreachable` statement.
5764
let bbs = body.basic_blocks.as_mut();

tests/crashes/122904-2.rs

Lines changed: 0 additions & 17 deletions
This file was deleted.

tests/crashes/139556.rs

Lines changed: 0 additions & 13 deletions
This file was deleted.

tests/ui/consts/promoted_const_call2.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ pub const C: () = {
44
let _: &'static _ = &id(&String::new());
55
//~^ ERROR: temporary value dropped while borrowed
66
//~| ERROR: temporary value dropped while borrowed
7-
//~| ERROR: destructor of `String` cannot be evaluated at compile-time
87
};
98

109
fn main() {

tests/ui/consts/promoted_const_call2.stderr

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,8 @@ LL | let _: &'static _ = &id(&String::new());
1818
| | creates a temporary value which is freed while still in use
1919
| type annotation requires that borrow lasts for `'static`
2020

21-
error[E0493]: destructor of `String` cannot be evaluated at compile-time
22-
--> $DIR/promoted_const_call2.rs:4:30
23-
|
24-
LL | let _: &'static _ = &id(&String::new());
25-
| ^^^^^^^^^^^^^ - value is dropped here
26-
| |
27-
| the destructor for this type cannot be evaluated in constants
28-
2921
error[E0716]: temporary value dropped while borrowed
30-
--> $DIR/promoted_const_call2.rs:11:26
22+
--> $DIR/promoted_const_call2.rs:10:26
3123
|
3224
LL | let _: &'static _ = &id(&String::new());
3325
| ---------- ^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -38,15 +30,14 @@ LL | }
3830
| - temporary value is freed at the end of this statement
3931

4032
error[E0716]: temporary value dropped while borrowed
41-
--> $DIR/promoted_const_call2.rs:11:30
33+
--> $DIR/promoted_const_call2.rs:10:30
4234
|
4335
LL | let _: &'static _ = &id(&String::new());
4436
| ---------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
4537
| | |
4638
| | creates a temporary value which is freed while still in use
4739
| type annotation requires that borrow lasts for `'static`
4840

49-
error: aborting due to 5 previous errors
41+
error: aborting due to 4 previous errors
5042

51-
Some errors have detailed explanations: E0493, E0716.
52-
For more information about an error, try `rustc --explain E0493`.
43+
For more information about this error, try `rustc --explain E0716`.
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
1-
//@ known-bug: #122630
1+
//! Regression test for #122630
22
//@ compile-flags: -Zvalidate-mir
33

4+
#![feature(coroutines, coroutine_trait, yield_expr)]
5+
46
use std::ops::Coroutine;
57

68
const FOO_SIZE: usize = 1024;
79
struct Foo([u8; FOO_SIZE]);
810

911
impl Drop for Foo {
10-
fn move_before_yield_with_noop() -> impl Coroutine<Yield = ()> {}
12+
fn drop(&mut self) {}
1113
}
1214

1315
fn overlap_move_points() -> impl Coroutine<Yield = ()> {
14-
static || {
16+
#[coroutine] static || {
1517
let first = Foo([0; FOO_SIZE]);
1618
yield;
1719
let second = first;
1820
yield;
1921
let second = first;
22+
//~^ ERROR: use of moved value: `first` [E0382]
2023
yield;
2124
}
2225
}
26+
27+
fn main() {}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0382]: use of moved value: `first`
2+
--> $DIR/moved-twice.rs:21:22
3+
|
4+
LL | let first = Foo([0; FOO_SIZE]);
5+
| ----- move occurs because `first` has type `Foo`, which does not implement the `Copy` trait
6+
LL | yield;
7+
LL | let second = first;
8+
| ----- value moved here
9+
LL | yield;
10+
LL | let second = first;
11+
| ^^^^^ value used here after move
12+
|
13+
note: if `Foo` implemented `Clone`, you could clone the value
14+
--> $DIR/moved-twice.rs:9:1
15+
|
16+
LL | struct Foo([u8; FOO_SIZE]);
17+
| ^^^^^^^^^^ consider implementing `Clone` for this type
18+
...
19+
LL | let second = first;
20+
| ----- you could clone this value
21+
22+
error: aborting due to 1 previous error
23+
24+
For more information about this error, try `rustc --explain E0382`.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//! Regression test for ICE #139556
2+
3+
#![feature(type_alias_impl_trait)]
4+
5+
trait T {}
6+
7+
type Alias<'a> = impl T;
8+
9+
struct S;
10+
impl<'a> T for &'a S {}
11+
12+
#[define_opaque(Alias)]
13+
fn with_positive(fun: impl Fn(Alias<'_>)) {
14+
//~^ WARN: function cannot return without recursing
15+
with_positive(|&n| ());
16+
//~^ ERROR: cannot move out of a shared reference
17+
}
18+
19+
fn main() {}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
warning: function cannot return without recursing
2+
--> $DIR/recursive-drop-elaboration-2.rs:13:1
3+
|
4+
LL | fn with_positive(fun: impl Fn(Alias<'_>)) {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
6+
LL |
7+
LL | with_positive(|&n| ());
8+
| ---------------------- recursive call site
9+
|
10+
= help: a `loop` may express intention better if this is on purpose
11+
= note: `#[warn(unconditional_recursion)]` on by default
12+
13+
error[E0507]: cannot move out of a shared reference
14+
--> $DIR/recursive-drop-elaboration-2.rs:15:20
15+
|
16+
LL | with_positive(|&n| ());
17+
| ^-
18+
| |
19+
| data moved here
20+
| move occurs because `n` has type `S`, which does not implement the `Copy` trait
21+
|
22+
help: consider removing the borrow
23+
|
24+
LL - with_positive(|&n| ());
25+
LL + with_positive(|n| ());
26+
|
27+
28+
error: aborting due to 1 previous error; 1 warning emitted
29+
30+
For more information about this error, try `rustc --explain E0507`.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//! Regression test for #122904.
2+
3+
#![feature(type_alias_impl_trait)]
4+
5+
trait T {}
6+
7+
type Alias<'a> = impl T;
8+
9+
struct S;
10+
impl<'a> T for &'a S {}
11+
12+
#[define_opaque(Alias)]
13+
fn with_positive(fun: impl Fn(Alias<'_>)) {
14+
//~^ WARN: function cannot return without recursing
15+
with_positive(|&n| ());
16+
//~^ ERROR: cannot move out of a shared reference
17+
}
18+
19+
#[define_opaque(Alias)]
20+
fn main(_: Alias<'_>) {
21+
//~^ ERROR: `main` function has wrong type [E0580]
22+
with_positive(|&a| ());
23+
//~^ ERROR: cannot move out of a shared reference
24+
}

0 commit comments

Comments
 (0)