Rollup merge of #139025 - compiler-errors:trim-validator-err, r=jieyouxu

Do not trim paths in MIR validator

From my inline comment:

```
// The type checker formats a bunch of strings with type names in it, but these strings
// are not always going to be encountered on the error path since the inliner also uses
// the validator, and there are certain kinds of inlining (even for valid code) that
// can cause validation errors (mostly around where clauses and rigid projections).
```

Fixes https://github.com/rust-lang/rust/issues/138979

r? `@jieyouxu`
This commit is contained in:
Jacob Pratt 2025-03-27 21:41:49 -04:00 committed by GitHub
commit d837ab4489
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 67 additions and 26 deletions

View File

@ -12,6 +12,7 @@ use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{
self, CoroutineArgsExt, InstanceKind, ScalarInt, Ty, TyCtxt, TypeVisitableExt, Upcast, Variance,
};
@ -56,7 +57,7 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
ty::Coroutine(..) => ExternAbi::Rust,
// No need to do MIR validation on error bodies
ty::Error(_) => return,
_ => span_bug!(body.span, "unexpected body ty: {body_ty:?}"),
_ => span_bug!(body.span, "unexpected body ty: {body_ty}"),
};
ty::layout::fn_can_unwind(tcx, Some(def_id), body_abi)
@ -543,7 +544,13 @@ pub(super) fn validate_types<'tcx>(
caller_body: &Body<'tcx>,
) -> Vec<(Location, String)> {
let mut type_checker = TypeChecker { body, caller_body, tcx, typing_env, failures: Vec::new() };
type_checker.visit_body(body);
// The type checker formats a bunch of strings with type names in it, but these strings
// are not always going to be encountered on the error path since the inliner also uses
// the validator, and there are certain kinds of inlining (even for valid code) that
// can cause validation errors (mostly around where clauses and rigid projections).
with_no_trimmed_paths!({
type_checker.visit_body(body);
});
type_checker.failures
}
@ -655,7 +662,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
ProjectionElem::Index(index) => {
let index_ty = self.body.local_decls[index].ty;
if index_ty != self.tcx.types.usize {
self.fail(location, format!("bad index ({index_ty:?} != usize)"))
self.fail(location, format!("bad index ({index_ty} != usize)"))
}
}
ProjectionElem::Deref
@ -664,10 +671,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
let base_ty = place_ref.ty(&self.body.local_decls, self.tcx).ty;
if base_ty.is_box() {
self.fail(
location,
format!("{base_ty:?} dereferenced after ElaborateBoxDerefs"),
)
self.fail(location, format!("{base_ty} dereferenced after ElaborateBoxDerefs"))
}
}
ProjectionElem::Field(f, ty) => {
@ -680,7 +684,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
this.fail(
location,
format!(
"Field projection `{place_ref:?}.{f:?}` specified type `{ty:?}`, but actual type is `{f_ty:?}`"
"Field projection `{place_ref:?}.{f:?}` specified type `{ty}`, but actual type is `{f_ty}`"
)
)
}
@ -806,7 +810,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.fail(
location,
format!(
"Failed subtyping {ty:#?} and {:#?}",
"Failed subtyping {ty} and {}",
place_ref.ty(&self.body.local_decls, self.tcx).ty
),
)
@ -826,7 +830,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.fail(
location,
format!(
"Cannot unwrap unsafe binder {binder_ty:?} into type {unwrapped_ty:?}"
"Cannot unwrap unsafe binder {binder_ty:?} into type {unwrapped_ty}"
),
);
}
@ -841,7 +845,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if ty.is_union() || ty.is_enum() {
self.fail(
START_BLOCK.start_location(),
format!("invalid type {ty:?} in debuginfo for {:?}", debuginfo.name),
format!("invalid type {ty} in debuginfo for {:?}", debuginfo.name),
);
}
if projection.is_empty() {
@ -1064,15 +1068,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if !self.mir_assign_valid_types(a, b) {
self.fail(
location,
format!("Cannot {op:?} compare incompatible types {a:?} and {b:?}"),
format!("Cannot {op:?} compare incompatible types {a} and {b}"),
);
}
} else if a != b {
self.fail(
location,
format!(
"Cannot perform binary op {op:?} on unequal types {a:?} and {b:?}"
),
format!("Cannot perform binary op {op:?} on unequal types {a} and {b}"),
);
}
}
@ -1081,7 +1083,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
Offset => {
check_kinds!(a, "Cannot offset non-pointer type {:?}", ty::RawPtr(..));
if b != self.tcx.types.isize && b != self.tcx.types.usize {
self.fail(location, format!("Cannot offset by non-isize type {b:?}"));
self.fail(location, format!("Cannot offset by non-isize type {b}"));
}
}
Eq | Lt | Le | Ne | Ge | Gt => {
@ -1313,7 +1315,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
{
self.fail(
location,
format!("Cannot transmute from non-`Sized` type {op_ty:?}"),
format!("Cannot transmute from non-`Sized` type {op_ty}"),
);
}
if !self
@ -1340,7 +1342,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
Rvalue::NullaryOp(NullOp::OffsetOf(indices), container) => {
let fail_out_of_bounds = |this: &mut Self, location, field, ty| {
this.fail(location, format!("Out of bounds field {field:?} for {ty:?}"));
this.fail(location, format!("Out of bounds field {field:?} for {ty}"));
};
let mut current_ty = *container;
@ -1374,7 +1376,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
_ => {
self.fail(
location,
format!("Cannot get offset ({variant:?}, {field:?}) from type {current_ty:?}"),
format!("Cannot get offset ({variant:?}, {field:?}) from type {current_ty}"),
);
return;
}
@ -1403,7 +1405,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if !self.mir_assign_valid_types(unwrapped_ty, binder_inner_ty) {
self.fail(
location,
format!("Cannot wrap {unwrapped_ty:?} into unsafe binder {binder_ty:?}"),
format!("Cannot wrap {unwrapped_ty} into unsafe binder {binder_ty:?}"),
);
}
}
@ -1489,24 +1491,27 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// since CopyNonOverlapping is parametrized by 1 type,
// we only need to check that they are equal and not keep an extra parameter.
if !self.mir_assign_valid_types(op_src_ty, op_dst_ty) {
self.fail(location, format!("bad arg ({op_src_ty:?} != {op_dst_ty:?})"));
self.fail(location, format!("bad arg ({op_src_ty} != {op_dst_ty})"));
}
let op_cnt_ty = count.ty(&self.body.local_decls, self.tcx);
if op_cnt_ty != self.tcx.types.usize {
self.fail(location, format!("bad arg ({op_cnt_ty:?} != usize)"))
self.fail(location, format!("bad arg ({op_cnt_ty} != usize)"))
}
}
StatementKind::SetDiscriminant { place, .. } => {
if self.body.phase < MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location, "`SetDiscriminant`is not allowed until deaggregation");
}
let pty = place.ty(&self.body.local_decls, self.tcx).ty.kind();
if !matches!(pty, ty::Adt(..) | ty::Coroutine(..) | ty::Alias(ty::Opaque, ..)) {
let pty = place.ty(&self.body.local_decls, self.tcx).ty;
if !matches!(
pty.kind(),
ty::Adt(..) | ty::Coroutine(..) | ty::Alias(ty::Opaque, ..)
) {
self.fail(
location,
format!(
"`SetDiscriminant` is only allowed on ADTs and coroutines, not {pty:?}"
"`SetDiscriminant` is only allowed on ADTs and coroutines, not {pty}"
),
);
}
@ -1555,7 +1560,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if ScalarInt::try_from_uint(value, size).is_none() {
self.fail(
location,
format!("the value {value:#x} is not a proper {switch_ty:?}"),
format!("the value {value:#x} is not a proper {switch_ty}"),
)
}
}

View File

@ -0,0 +1,36 @@
//@ build-pass
//@ compile-flags: -Zinline-mir
trait Storage {
type Buffer: ?Sized;
}
struct Array<const N: usize>;
impl<const N: usize> Storage for Array<N> {
type Buffer = [(); N];
}
struct Slice;
impl Storage for Slice {
type Buffer = [()];
}
struct Wrap<S: Storage> {
_b: S::Buffer,
}
fn coerce<const N: usize>(this: &Wrap<Array<N>>) -> &Wrap<Slice>
where
Array<N>: Storage,
{
coerce_again(this)
}
fn coerce_again<const N: usize>(this: &Wrap<Array<N>>) -> &Wrap<Slice> {
this
}
fn main() {
let inner: Wrap<Array<1>> = Wrap { _b: [(); 1] };
let _: &Wrap<Slice> = coerce(&inner);
}