Consider errors in MIR as impossible predicates.
This commit is contained in:
parent
59043567a5
commit
3934fc9eb2
13 changed files with 201 additions and 61 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 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() {
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
24
tests/ui/coroutine/moved-twice.stderr
Normal file
24
tests/ui/coroutine/moved-twice.stderr
Normal 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`.
|
||||
|
|
@ -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`.
|
||||
24
tests/ui/type-alias-impl-trait/recursive-drop-elaboration.rs
Normal file
24
tests/ui/type-alias-impl-trait/recursive-drop-elaboration.rs
Normal 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
|
||||
}
|
||||
|
|
@ -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`.
|
||||
|
|
@ -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();
|
||||
|
|
@ -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`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue