Skip to content

Commit 7e1aaaa

Browse files
authored
Rollup merge of rust-lang#145620 - compiler-errors:fake-dyn-to-dyn, r=lcnr
Account for impossible bounds making seemingly unsatisfyable dyn-to-dyn casts Fixes rust-lang#141806 When we have an impossible where clause like `dyn Trait<u8>: Sized`, this may make a dyn-to-dyn cast like `dyn Trait<()> -> dyn trait<u8>` to successfully type check as if it were a wide-to-thin ptr cast (discarding metadata): https://github.com/rust-lang/rust/blob/16ad385579cebb6f7d53367c552661b6b51a4a02/compiler/rustc_hir_typeck/src/cast.rs#L862-L865 In borrowck, we are expecting that the only meaningful dyn-to-dyn cast to be a metadata-preserving wide-to-wide ptr cast, which requires that the principals of the dyn pointers are equal. Borrowck additionally assumes that these principals have already been proven equal *modulo regions*, and we thus ICE since `Trait<u8>` and `Trait<()>` do not unify: https://github.com/rust-lang/rust/blob/16ad385579cebb6f7d53367c552661b6b51a4a02/compiler/rustc_borrowck/src/type_check/mod.rs#L1481-L1524 This PR fixes this ICE by checking whether the RHS of the cast is considered to be Sized in the environment of the MIR typeck, and if so then skipping over this dyn->dyn principal compatibility check. r? ``@lcnr`` perhaps?
2 parents 439f905 + e0fb6eb commit 7e1aaaa

File tree

2 files changed

+90
-62
lines changed

2 files changed

+90
-62
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 74 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use rustc_mir_dataflow::points::DenseLocationMap;
3434
use rustc_span::def_id::CRATE_DEF_ID;
3535
use rustc_span::source_map::Spanned;
3636
use rustc_span::{Span, sym};
37+
use rustc_trait_selection::infer::InferCtxtExt;
3738
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
3839
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
3940
use tracing::{debug, instrument, trace};
@@ -1454,68 +1455,79 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
14541455
}
14551456
CastKind::PtrToPtr => {
14561457
let ty_from = op.ty(self.body, tcx);
1457-
let cast_ty_from = CastTy::from_ty(ty_from);
1458-
let cast_ty_to = CastTy::from_ty(*ty);
1459-
match (cast_ty_from, cast_ty_to) {
1460-
(Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
1461-
let src_tail = self.struct_tail(src.ty, location);
1462-
let dst_tail = self.struct_tail(dst.ty, location);
1463-
1464-
// This checks (lifetime part of) vtable validity for pointer casts,
1465-
// which is irrelevant when there are aren't principal traits on
1466-
// both sides (aka only auto traits).
1467-
//
1468-
// Note that other checks (such as denying `dyn Send` -> `dyn
1469-
// Debug`) are in `rustc_hir_typeck`.
1470-
if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) = *src_tail.kind()
1471-
&& let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) = *dst_tail.kind()
1472-
&& src_tty.principal().is_some()
1473-
&& dst_tty.principal().is_some()
1474-
{
1475-
// Remove auto traits.
1476-
// Auto trait checks are handled in `rustc_hir_typeck` as FCW.
1477-
let src_obj = Ty::new_dynamic(
1478-
tcx,
1479-
tcx.mk_poly_existential_predicates(
1480-
&src_tty.without_auto_traits().collect::<Vec<_>>(),
1481-
),
1482-
// FIXME: Once we disallow casting `*const dyn Trait + 'short`
1483-
// to `*const dyn Trait + 'long`, then this can just be `src_lt`.
1484-
dst_lt,
1485-
ty::Dyn,
1486-
);
1487-
let dst_obj = Ty::new_dynamic(
1488-
tcx,
1489-
tcx.mk_poly_existential_predicates(
1490-
&dst_tty.without_auto_traits().collect::<Vec<_>>(),
1491-
),
1492-
dst_lt,
1493-
ty::Dyn,
1494-
);
1495-
1496-
debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
1497-
1498-
self.sub_types(
1499-
src_obj,
1500-
dst_obj,
1501-
location.to_locations(),
1502-
ConstraintCategory::Cast {
1503-
is_implicit_coercion: false,
1504-
unsize_to: None,
1505-
},
1506-
)
1507-
.unwrap();
1508-
}
1509-
}
1510-
_ => {
1511-
span_mirbug!(
1512-
self,
1513-
rvalue,
1514-
"Invalid PtrToPtr cast {:?} -> {:?}",
1515-
ty_from,
1516-
ty
1517-
)
1518-
}
1458+
let Some(CastTy::Ptr(src)) = CastTy::from_ty(ty_from) else {
1459+
unreachable!();
1460+
};
1461+
let Some(CastTy::Ptr(dst)) = CastTy::from_ty(*ty) else {
1462+
unreachable!();
1463+
};
1464+
1465+
if self.infcx.type_is_sized_modulo_regions(self.infcx.param_env, dst.ty) {
1466+
// Wide to thin ptr cast. This may even occur in an env with
1467+
// impossible predicates, such as `where dyn Trait: Sized`.
1468+
// In this case, we don't want to fall into the case below,
1469+
// since the types may not actually be equatable, but it's
1470+
// fine to perform this operation in an impossible env.
1471+
let trait_ref = ty::TraitRef::new(
1472+
tcx,
1473+
tcx.require_lang_item(LangItem::Sized, self.last_span),
1474+
[dst.ty],
1475+
);
1476+
self.prove_trait_ref(
1477+
trait_ref,
1478+
location.to_locations(),
1479+
ConstraintCategory::Cast {
1480+
is_implicit_coercion: true,
1481+
unsize_to: None,
1482+
},
1483+
);
1484+
} else if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) =
1485+
*self.struct_tail(src.ty, location).kind()
1486+
&& let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) =
1487+
*self.struct_tail(dst.ty, location).kind()
1488+
&& src_tty.principal().is_some()
1489+
&& dst_tty.principal().is_some()
1490+
{
1491+
// This checks (lifetime part of) vtable validity for pointer casts,
1492+
// which is irrelevant when there are aren't principal traits on
1493+
// both sides (aka only auto traits).
1494+
//
1495+
// Note that other checks (such as denying `dyn Send` -> `dyn
1496+
// Debug`) are in `rustc_hir_typeck`.
1497+
1498+
// Remove auto traits.
1499+
// Auto trait checks are handled in `rustc_hir_typeck` as FCW.
1500+
let src_obj = Ty::new_dynamic(
1501+
tcx,
1502+
tcx.mk_poly_existential_predicates(
1503+
&src_tty.without_auto_traits().collect::<Vec<_>>(),
1504+
),
1505+
// FIXME: Once we disallow casting `*const dyn Trait + 'short`
1506+
// to `*const dyn Trait + 'long`, then this can just be `src_lt`.
1507+
dst_lt,
1508+
ty::Dyn,
1509+
);
1510+
let dst_obj = Ty::new_dynamic(
1511+
tcx,
1512+
tcx.mk_poly_existential_predicates(
1513+
&dst_tty.without_auto_traits().collect::<Vec<_>>(),
1514+
),
1515+
dst_lt,
1516+
ty::Dyn,
1517+
);
1518+
1519+
debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
1520+
1521+
self.sub_types(
1522+
src_obj,
1523+
dst_obj,
1524+
location.to_locations(),
1525+
ConstraintCategory::Cast {
1526+
is_implicit_coercion: false,
1527+
unsize_to: None,
1528+
},
1529+
)
1530+
.unwrap();
15191531
}
15201532
}
15211533
CastKind::Transmute => {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Make sure borrowck doesn't ICE because it thinks a pointer cast is a metadata-preserving
2+
// wide-to-wide ptr cast when it's actually (falsely) a wide-to-thin ptr cast due to an
3+
// impossible dyn sized bound.
4+
5+
//@ check-pass
6+
7+
trait Trait<T> {}
8+
9+
fn func<'a>(x: *const (dyn Trait<()> + 'a))
10+
where
11+
dyn Trait<u8> + 'a: Sized,
12+
{
13+
let _x: *const dyn Trait<u8> = x as _;
14+
}
15+
16+
fn main() {}

0 commit comments

Comments
 (0)