mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
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 https://github.com/rust-lang/rust/issues/122630 Fixes https://github.com/rust-lang/rust/issues/122904 Fixes https://github.com/rust-lang/rust/issues/125185 Fixes https://github.com/rust-lang/rust/issues/139556
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
|
||||
use rustc_middle::mir::{Body, START_BLOCK, TerminatorKind};
|
||||
use rustc_middle::ty::{TyCtxt, TypeFlags, TypeVisitableExt};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_trait_selection::traits;
|
||||
use tracing::trace;
|
||||
|
||||
@@ -35,23 +36,29 @@
|
||||
|
||||
pub(crate) struct ImpossiblePredicates;
|
||||
|
||||
fn has_impossible_predicates(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
let predicates = tcx.predicates_of(def_id).instantiate_identity(tcx);
|
||||
tracing::trace!(?predicates);
|
||||
let predicates = predicates.predicates.into_iter().filter(|p| {
|
||||
!p.has_type_flags(
|
||||
// Only consider global clauses to simplify.
|
||||
TypeFlags::HAS_FREE_LOCAL_NAMES
|
||||
// Clauses that refer to unevaluated constants as they cause cycles.
|
||||
| TypeFlags::HAS_CT_PROJECTION,
|
||||
)
|
||||
});
|
||||
let predicates: Vec<_> = traits::elaborate(tcx, predicates).collect();
|
||||
tracing::trace!(?predicates);
|
||||
predicates.references_error() || traits::impossible_predicates(tcx, predicates)
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for ImpossiblePredicates {
|
||||
#[tracing::instrument(level = "trace", skip(self, tcx, body))]
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
tracing::trace!(def_id = ?body.source.def_id());
|
||||
let predicates = tcx.predicates_of(body.source.def_id()).instantiate_identity(tcx);
|
||||
tracing::trace!(?predicates);
|
||||
let predicates = predicates.predicates.into_iter().filter(|p| {
|
||||
!p.has_type_flags(
|
||||
// Only consider global clauses to simplify.
|
||||
TypeFlags::HAS_FREE_LOCAL_NAMES
|
||||
// Clauses that refer to unevaluated constants as they cause cycles.
|
||||
| TypeFlags::HAS_CT_PROJECTION,
|
||||
)
|
||||
});
|
||||
let predicates: Vec<_> = traits::elaborate(tcx, predicates).collect();
|
||||
tracing::trace!(?predicates);
|
||||
if predicates.references_error() || traits::impossible_predicates(tcx, predicates) {
|
||||
let impossible = body.tainted_by_errors.is_some()
|
||||
|| has_impossible_predicates(tcx, body.source.def_id());
|
||||
if impossible {
|
||||
trace!("found unsatisfiable predicates");
|
||||
// Clear the body to only contain a single `unreachable` statement.
|
||||
let bbs = body.basic_blocks.as_mut();
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
//@ known-bug: #122904
|
||||
trait T {}
|
||||
|
||||
type Alias<'a> = impl T;
|
||||
|
||||
struct S;
|
||||
impl<'a> T for &'a S {}
|
||||
|
||||
#[define_opaque(Alias)]
|
||||
fn with_positive(fun: impl Fn(Alias<'_>)) {
|
||||
with_positive(|&n| ());
|
||||
}
|
||||
|
||||
#[define_opaque(Alias)]
|
||||
fn main(Alias<'_>) {
|
||||
with_positive(|&a| ());
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
//@ known-bug: #139556
|
||||
|
||||
trait T {}
|
||||
|
||||
type Alias<'a> = impl T;
|
||||
|
||||
struct S;
|
||||
impl<'a> T for &'a S {}
|
||||
|
||||
#[define_opaque(Alias)]
|
||||
fn with_positive(fun: impl Fn(Alias<'_>)) {
|
||||
with_positive(|&n| ());
|
||||
}
|
||||
@@ -4,7 +4,6 @@ pub const fn id<T>(x: T) -> T { x }
|
||||
let _: &'static _ = &id(&String::new());
|
||||
//~^ ERROR: temporary value dropped while borrowed
|
||||
//~| ERROR: temporary value dropped while borrowed
|
||||
//~| ERROR: destructor of `String` cannot be evaluated at compile-time
|
||||
};
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -18,16 +18,8 @@ LL | let _: &'static _ = &id(&String::new());
|
||||
| | creates a temporary value which is freed while still in use
|
||||
| type annotation requires that borrow lasts for `'static`
|
||||
|
||||
error[E0493]: destructor of `String` cannot be evaluated at compile-time
|
||||
--> $DIR/promoted_const_call2.rs:4:30
|
||||
|
|
||||
LL | let _: &'static _ = &id(&String::new());
|
||||
| ^^^^^^^^^^^^^ - value is dropped here
|
||||
| |
|
||||
| the destructor for this type cannot be evaluated in constants
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promoted_const_call2.rs:11:26
|
||||
--> $DIR/promoted_const_call2.rs:10:26
|
||||
|
|
||||
LL | let _: &'static _ = &id(&String::new());
|
||||
| ---------- ^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
|
||||
@@ -38,7 +30,7 @@ LL | }
|
||||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/promoted_const_call2.rs:11:30
|
||||
--> $DIR/promoted_const_call2.rs:10:30
|
||||
|
|
||||
LL | let _: &'static _ = &id(&String::new());
|
||||
| ---------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
|
||||
@@ -46,7 +38,6 @@ LL | let _: &'static _ = &id(&String::new());
|
||||
| | creates a temporary value which is freed while still in use
|
||||
| type annotation requires that borrow lasts for `'static`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0493, E0716.
|
||||
For more information about an error, try `rustc --explain E0493`.
|
||||
For more information about this error, try `rustc --explain E0716`.
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
//@ known-bug: #122630
|
||||
//! Regression test for #122630
|
||||
//@ compile-flags: -Zvalidate-mir
|
||||
|
||||
#![feature(coroutines, coroutine_trait, yield_expr)]
|
||||
|
||||
use std::ops::Coroutine;
|
||||
|
||||
const FOO_SIZE: usize = 1024;
|
||||
struct Foo([u8; FOO_SIZE]);
|
||||
|
||||
impl Drop for Foo {
|
||||
fn move_before_yield_with_noop() -> impl Coroutine<Yield = ()> {}
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
fn overlap_move_points() -> impl Coroutine<Yield = ()> {
|
||||
static || {
|
||||
#[coroutine] static || {
|
||||
let first = Foo([0; FOO_SIZE]);
|
||||
yield;
|
||||
let second = first;
|
||||
yield;
|
||||
let second = first;
|
||||
//~^ ERROR: use of moved value: `first` [E0382]
|
||||
yield;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,24 @@
|
||||
error[E0382]: use of moved value: `first`
|
||||
--> $DIR/moved-twice.rs:21:22
|
||||
|
|
||||
LL | let first = Foo([0; FOO_SIZE]);
|
||||
| ----- move occurs because `first` has type `Foo`, which does not implement the `Copy` trait
|
||||
LL | yield;
|
||||
LL | let second = first;
|
||||
| ----- value moved here
|
||||
LL | yield;
|
||||
LL | let second = first;
|
||||
| ^^^^^ value used here after move
|
||||
|
|
||||
note: if `Foo` implemented `Clone`, you could clone the value
|
||||
--> $DIR/moved-twice.rs:9:1
|
||||
|
|
||||
LL | struct Foo([u8; FOO_SIZE]);
|
||||
| ^^^^^^^^^^ consider implementing `Clone` for this type
|
||||
...
|
||||
LL | let second = first;
|
||||
| ----- you could clone this value
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
||||
@@ -0,0 +1,19 @@
|
||||
//! Regression test for ICE #139556
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
trait T {}
|
||||
|
||||
type Alias<'a> = impl T;
|
||||
|
||||
struct S;
|
||||
impl<'a> T for &'a S {}
|
||||
|
||||
#[define_opaque(Alias)]
|
||||
fn with_positive(fun: impl Fn(Alias<'_>)) {
|
||||
//~^ WARN: function cannot return without recursing
|
||||
with_positive(|&n| ());
|
||||
//~^ ERROR: cannot move out of a shared reference
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,30 @@
|
||||
warning: function cannot return without recursing
|
||||
--> $DIR/recursive-drop-elaboration-2.rs:13:1
|
||||
|
|
||||
LL | fn with_positive(fun: impl Fn(Alias<'_>)) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
|
||||
LL |
|
||||
LL | with_positive(|&n| ());
|
||||
| ---------------------- recursive call site
|
||||
|
|
||||
= help: a `loop` may express intention better if this is on purpose
|
||||
= note: `#[warn(unconditional_recursion)]` on by default
|
||||
|
||||
error[E0507]: cannot move out of a shared reference
|
||||
--> $DIR/recursive-drop-elaboration-2.rs:15:20
|
||||
|
|
||||
LL | with_positive(|&n| ());
|
||||
| ^-
|
||||
| |
|
||||
| data moved here
|
||||
| move occurs because `n` has type `S`, which does not implement the `Copy` trait
|
||||
|
|
||||
help: consider removing the borrow
|
||||
|
|
||||
LL - with_positive(|&n| ());
|
||||
LL + with_positive(|n| ());
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0507`.
|
||||
@@ -0,0 +1,24 @@
|
||||
//! Regression test for #122904.
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
trait T {}
|
||||
|
||||
type Alias<'a> = impl T;
|
||||
|
||||
struct S;
|
||||
impl<'a> T for &'a S {}
|
||||
|
||||
#[define_opaque(Alias)]
|
||||
fn with_positive(fun: impl Fn(Alias<'_>)) {
|
||||
//~^ WARN: function cannot return without recursing
|
||||
with_positive(|&n| ());
|
||||
//~^ ERROR: cannot move out of a shared reference
|
||||
}
|
||||
|
||||
#[define_opaque(Alias)]
|
||||
fn main(_: Alias<'_>) {
|
||||
//~^ ERROR: `main` function has wrong type [E0580]
|
||||
with_positive(|&a| ());
|
||||
//~^ ERROR: cannot move out of a shared reference
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
warning: function cannot return without recursing
|
||||
--> $DIR/recursive-drop-elaboration.rs:13:1
|
||||
|
|
||||
LL | fn with_positive(fun: impl Fn(Alias<'_>)) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
|
||||
LL |
|
||||
LL | with_positive(|&n| ());
|
||||
| ---------------------- recursive call site
|
||||
|
|
||||
= help: a `loop` may express intention better if this is on purpose
|
||||
= note: `#[warn(unconditional_recursion)]` on by default
|
||||
|
||||
error[E0507]: cannot move out of a shared reference
|
||||
--> $DIR/recursive-drop-elaboration.rs:15:20
|
||||
|
|
||||
LL | with_positive(|&n| ());
|
||||
| ^-
|
||||
| |
|
||||
| data moved here
|
||||
| move occurs because `n` has type `S`, which does not implement the `Copy` trait
|
||||
|
|
||||
help: consider removing the borrow
|
||||
|
|
||||
LL - with_positive(|&n| ());
|
||||
LL + with_positive(|n| ());
|
||||
|
|
||||
|
||||
error[E0507]: cannot move out of a shared reference
|
||||
--> $DIR/recursive-drop-elaboration.rs:22:20
|
||||
|
|
||||
LL | with_positive(|&a| ());
|
||||
| ^-
|
||||
| |
|
||||
| data moved here
|
||||
| move occurs because `a` has type `S`, which does not implement the `Copy` trait
|
||||
|
|
||||
help: consider removing the borrow
|
||||
|
|
||||
LL - with_positive(|&a| ());
|
||||
LL + with_positive(|a| ());
|
||||
|
|
||||
|
||||
error[E0580]: `main` function has wrong type
|
||||
--> $DIR/recursive-drop-elaboration.rs:20:1
|
||||
|
|
||||
LL | type Alias<'a> = impl T;
|
||||
| ------ the found opaque type
|
||||
...
|
||||
LL | fn main(_: Alias<'_>) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
|
||||
|
|
||||
= note: expected signature `fn()`
|
||||
found signature `for<'a> fn(Alias<'a>)`
|
||||
|
||||
error: aborting due to 3 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0507, E0580.
|
||||
For more information about an error, try `rustc --explain E0507`.
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
//@ known-bug: rust-lang/rust#125185
|
||||
//! Regression test for #125185
|
||||
//@ compile-flags: -Zvalidate-mir
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
@@ -10,6 +10,7 @@
|
||||
#[define_opaque(Foo)]
|
||||
const fn foo() -> Foo {
|
||||
value()
|
||||
//~^ ERROR: cannot find function `value` in this scope
|
||||
}
|
||||
|
||||
const VALUE: Foo = foo();
|
||||
@@ -0,0 +1,12 @@
|
||||
error[E0425]: cannot find function `value` in this scope
|
||||
--> $DIR/type-error-drop-elaboration.rs:12:5
|
||||
|
|
||||
LL | value()
|
||||
| ^^^^^ help: a constant with a similar name exists: `VALUE`
|
||||
...
|
||||
LL | const VALUE: Foo = foo();
|
||||
| ------------------------- similarly named constant `VALUE` defined here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0425`.
|
||||
Reference in New Issue
Block a user