Skip to content

Commit 933692e

Browse files
Auto merge of #145620 - compiler-errors:fake-dyn-to-dyn, r=<try>
Account for impossible bounds making seemingly unsatisfyable dyn-to-dyn casts try-job: dist-various-2
2 parents a1dbb44 + e0fb6eb commit 933692e

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)