Rollup merge of #142976 - compiler-errors:coerce-ice, r=fee1-dead

Check CoerceUnsized impl validity before coercing

Self-explanatory from the title.

Fixes rust-lang/rust#126982
Fixes rust-lang/rust#131048
Fixes rust-lang/rust#134217
Fixes rust-lang/rust#126269
Fixes rust-lang/rust#138265
This commit is contained in:
Jana Dönszelmann
2025-06-25 22:14:56 +02:00
committed by GitHub
8 changed files with 46 additions and 59 deletions
+14 -1
View File
@@ -46,7 +46,7 @@
use rustc_infer::infer::relate::RelateResult;
use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
use rustc_infer::traits::{
IfExpressionCause, MatchExpressionArmCause, Obligation, PredicateObligation,
IfExpressionCause, ImplSource, MatchExpressionArmCause, Obligation, PredicateObligation,
PredicateObligations, SelectionError,
};
use rustc_middle::span_bug;
@@ -704,6 +704,19 @@ fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceRe
// be silent, as it causes a type mismatch later.
}
Ok(Some(ImplSource::UserDefined(impl_source))) => {
queue.extend(impl_source.nested);
// Certain incoherent `CoerceUnsized` implementations may cause ICEs,
// so check the impl's validity. Taint the body so that we don't try
// to evaluate these invalid coercions in CTFE. We only need to do this
// for local impls, since upstream impls should be valid.
if impl_source.impl_def_id.is_local()
&& let Err(guar) =
self.tcx.ensure_ok().coerce_unsized_info(impl_source.impl_def_id)
{
self.fcx.set_tainted_by_errors(guar);
}
}
Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()),
}
}
-12
View File
@@ -1,12 +0,0 @@
//@ known-bug: rust-lang/rust#126269
#![feature(coerce_unsized)]
pub enum Foo<T> {
Bar([T; usize::MAX]),
}
use std::ops::CoerceUnsized;
impl<T, U> CoerceUnsized<U> for T {}
fn main() {}
-18
View File
@@ -1,18 +0,0 @@
//@ known-bug: rust-lang/rust#126982
#![feature(coerce_unsized)]
use std::ops::CoerceUnsized;
struct Foo<T: ?Sized> {
a: T,
}
impl<T, U> CoerceUnsized<U> for Foo<T> {}
union U {
a: usize,
}
const C: U = Foo { a: 10 };
fn main() {}
-7
View File
@@ -1,7 +0,0 @@
//@ known-bug: #131048
impl<A> std::ops::CoerceUnsized<A> for A {}
fn main() {
format_args!("Hello, world!");
}
-9
View File
@@ -1,9 +0,0 @@
//@ known-bug: #134217
impl<A> std::ops::CoerceUnsized<A> for A {}
fn main() {
if let _ = true
&& true
{}
}
-12
View File
@@ -1,12 +0,0 @@
//@ known-bug: #138265
#![feature(coerce_unsized)]
#![crate_type = "lib"]
impl<A> std::ops::CoerceUnsized<A> for A {}
pub fn f() {
[0; {
let mut c = &0;
c = &0;
0
}]
}
@@ -0,0 +1,13 @@
// Regression test minimized from #126982.
// We used to apply a coerce_unsized coercion to literally every argument since
// the blanket applied in literally all cases, even though it was incoherent.
#![feature(coerce_unsized)]
impl<A> std::ops::CoerceUnsized<A> for A {}
//~^ ERROR type parameter `A` must be used as the type parameter for some local type
//~| ERROR the trait `CoerceUnsized` may only be implemented for a coercion between structures
const C: usize = 1;
fn main() {}
@@ -0,0 +1,19 @@
error[E0210]: type parameter `A` must be used as the type parameter for some local type (e.g., `MyStruct<A>`)
--> $DIR/invalid-blanket-coerce-unsized-impl.rs:7:6
|
LL | impl<A> std::ops::CoerceUnsized<A> for A {}
| ^ type parameter `A` must be used as the type parameter for some local type
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
= note: only traits defined in the current crate can be implemented for a type parameter
error[E0377]: the trait `CoerceUnsized` may only be implemented for a coercion between structures
--> $DIR/invalid-blanket-coerce-unsized-impl.rs:7:1
|
LL | impl<A> std::ops::CoerceUnsized<A> for A {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0210, E0377.
For more information about an error, try `rustc --explain E0210`.