Consider errors in MIR as impossible predicates.

This commit is contained in:
Camille Gillot 2025-09-16 02:33:24 +00:00
parent 59043567a5
commit 3934fc9eb2
13 changed files with 201 additions and 61 deletions

View file

@ -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 @@ use crate::pass_manager::MirPass;
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();

View file

@ -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| ());
}

View file

@ -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| ());
}

View file

@ -4,7 +4,6 @@ pub const C: () = {
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() {

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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
}

View file

@ -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`.

View file

@ -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 @@ struct A;
#[define_opaque(Foo)]
const fn foo() -> Foo {
value()
//~^ ERROR: cannot find function `value` in this scope
}
const VALUE: Foo = foo();

View file

@ -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`.