Skip to content

Commit 3131f84

Browse files
Account for impossible bounds making seemingly unsatisfyable dyn-to-dyn casts
1 parent 239e8b1 commit 3131f84

File tree

2 files changed

+38
-11
lines changed

2 files changed

+38
-11
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use rustc_mir_dataflow::points::DenseLocationMap;
3535
use rustc_span::def_id::CRATE_DEF_ID;
3636
use rustc_span::source_map::Spanned;
3737
use rustc_span::{Span, sym};
38+
use rustc_trait_selection::infer::InferCtxtExt;
3839
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
3940
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
4041
use tracing::{debug, instrument, trace};
@@ -1473,22 +1474,32 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
14731474
let ty_from = op.ty(self.body, tcx);
14741475
let cast_ty_from = CastTy::from_ty(ty_from);
14751476
let cast_ty_to = CastTy::from_ty(*ty);
1477+
14761478
match (cast_ty_from, cast_ty_to) {
14771479
(Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
1478-
let src_tail = self.struct_tail(src.ty, location);
1479-
let dst_tail = self.struct_tail(dst.ty, location);
1480-
1481-
// This checks (lifetime part of) vtable validity for pointer casts,
1482-
// which is irrelevant when there are aren't principal traits on
1483-
// both sides (aka only auto traits).
1484-
//
1485-
// Note that other checks (such as denying `dyn Send` -> `dyn
1486-
// Debug`) are in `rustc_hir_typeck`.
1487-
if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) = *src_tail.kind()
1488-
&& let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) = *dst_tail.kind()
1480+
if self
1481+
.infcx
1482+
.type_is_sized_modulo_regions(self.infcx.param_env, dst.ty)
1483+
{
1484+
// Wide to thin ptr cast. This may even occur in an env with
1485+
// impossible predicates, such as `where dyn Trait: Sized`.
1486+
// In this case, we don't want to fall into the case below,
1487+
// since the types may not actually be equatable, but it's
1488+
// fine to perform this operation in an impossible env.
1489+
} else if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) =
1490+
*self.struct_tail(src.ty, location).kind()
1491+
&& let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) =
1492+
*self.struct_tail(dst.ty, location).kind()
14891493
&& src_tty.principal().is_some()
14901494
&& dst_tty.principal().is_some()
14911495
{
1496+
// This checks (lifetime part of) vtable validity for pointer casts,
1497+
// which is irrelevant when there are aren't principal traits on
1498+
// both sides (aka only auto traits).
1499+
//
1500+
// Note that other checks (such as denying `dyn Send` -> `dyn
1501+
// Debug`) are in `rustc_hir_typeck`.
1502+
14921503
// Remove auto traits.
14931504
// Auto trait checks are handled in `rustc_hir_typeck` as FCW.
14941505
let src_obj = Ty::new_dynamic(
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)