Skip to content

Commit c957c4e

Browse files
Account for impossible bounds making seemingly unsatisfyable dyn-to-dyn casts
1 parent 6d6a08c commit c957c4e

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
@@ -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};
@@ -1457,22 +1458,32 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
14571458
let ty_from = op.ty(self.body, tcx);
14581459
let cast_ty_from = CastTy::from_ty(ty_from);
14591460
let cast_ty_to = CastTy::from_ty(*ty);
1461+
14601462
match (cast_ty_from, cast_ty_to) {
14611463
(Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
1462-
let src_tail = self.struct_tail(src.ty, location);
1463-
let dst_tail = self.struct_tail(dst.ty, location);
1464-
1465-
// This checks (lifetime part of) vtable validity for pointer casts,
1466-
// which is irrelevant when there are aren't principal traits on
1467-
// both sides (aka only auto traits).
1468-
//
1469-
// Note that other checks (such as denying `dyn Send` -> `dyn
1470-
// Debug`) are in `rustc_hir_typeck`.
1471-
if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) = *src_tail.kind()
1472-
&& let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) = *dst_tail.kind()
1464+
if self
1465+
.infcx
1466+
.type_is_sized_modulo_regions(self.infcx.param_env, dst.ty)
1467+
{
1468+
// Wide to thin ptr cast. This may even occur in an env with
1469+
// impossible predicates, such as `where dyn Trait: Sized`.
1470+
// In this case, we don't want to fall into the case below,
1471+
// since the types may not actually be equatable, but it's
1472+
// fine to perform this operation in an impossible env.
1473+
} else if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) =
1474+
*self.struct_tail(src.ty, location).kind()
1475+
&& let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) =
1476+
*self.struct_tail(dst.ty, location).kind()
14731477
&& src_tty.principal().is_some()
14741478
&& dst_tty.principal().is_some()
14751479
{
1480+
// This checks (lifetime part of) vtable validity for pointer casts,
1481+
// which is irrelevant when there are aren't principal traits on
1482+
// both sides (aka only auto traits).
1483+
//
1484+
// Note that other checks (such as denying `dyn Send` -> `dyn
1485+
// Debug`) are in `rustc_hir_typeck`.
1486+
14761487
// Remove auto traits.
14771488
// Auto trait checks are handled in `rustc_hir_typeck` as FCW.
14781489
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)