From 94f0918c19a6f4f260535620cf66b6c4589d7a67 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Wed, 18 May 2016 22:25:03 -0400 Subject: [PATCH] [MIR] Add PointerCast for Unsize casts of fat pointers. --- src/librustc_trans/base.rs | 8 +++++- src/librustc_trans/mir/rvalue.rs | 9 ++++--- src/librustc_trans/type_of.rs | 11 ++++++++ src/test/run-pass/issue-33387.rs | 44 ++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass/issue-33387.rs diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 481154ba29f8c..0b54ccef7a395 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -617,7 +617,13 @@ pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, (&ty::TyRawPtr(..), &ty::TyRawPtr(..)) => { let (base, info) = if common::type_is_fat_ptr(bcx.tcx(), src_ty) { // fat-ptr to fat-ptr unsize preserves the vtable - load_fat_ptr(bcx, src, src_ty) + // i.e. &'a fmt::Debug+Send => &'a fmt::Debug + // So we need to pointercast the base to ensure + // the types match up. + let (base, info) = load_fat_ptr(bcx, src, src_ty); + let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx(), dst_ty); + let base = PointerCast(bcx, base, llcast_ty); + (base, info) } else { let base = load_ty(bcx, src, src_ty); unsize_thin_ptr(bcx, base, src_ty, dst_ty) diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index bcbf3e1fa1836..5945e8813a48d 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -262,14 +262,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { assert!(common::type_is_fat_ptr(bcx.tcx(), cast_ty)); match operand.val { - OperandValue::FatPtr(..) => { + OperandValue::FatPtr(lldata, llextra) => { // unsize from a fat pointer - this is a // "trait-object-to-supertrait" coercion, for // example, // &'a fmt::Debug+Send => &'a fmt::Debug, - // and is a no-op at the LLVM level + // So we need to pointercast the base to ensure + // the types match up. self.set_operand_dropped(&bcx, source); - operand.val + let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx(), cast_ty); + let lldata = bcx.pointercast(lldata, llcast_ty); + OperandValue::FatPtr(lldata, llextra) } OperandValue::Immediate(lldata) => { // "standard" unsize diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 98ec87ebbcf6f..e5acb9b6699bd 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -157,6 +157,17 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ llsizingty } +pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { + match ty.sty { + ty::TyBox(t) | + ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) | + ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) if !type_is_sized(ccx.tcx(), t) => { + in_memory_type_of(ccx, t).ptr_to() + } + _ => bug!("expected fat ptr ty but got {:?}", ty) + } +} + fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { let unsized_part = ccx.tcx().struct_tail(ty); match unsized_part.sty { diff --git a/src/test/run-pass/issue-33387.rs b/src/test/run-pass/issue-33387.rs new file mode 100644 index 0000000000000..a4b85bc7a091d --- /dev/null +++ b/src/test/run-pass/issue-33387.rs @@ -0,0 +1,44 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] + +use std::sync::Arc; + +trait Foo { + fn get(&self) -> [u8; 2]; +} + +impl Foo for [u8; 2] { + fn get(&self) -> [u8; 2] { + *self + } +} + +struct Bar(T); + +#[rustc_mir] +fn unsize_fat_ptr<'a>(x: &'a Bar) -> &'a Bar { + x +} + +#[rustc_mir] +fn unsize_nested_fat_ptr(x: Arc) -> Arc { + x +} + +#[rustc_mir] +fn main() { + let x: Box> = Box::new(Bar([1,2])); + assert_eq!(unsize_fat_ptr(&*x).0.get(), [1, 2]); + + let x: Arc = Arc::new([3, 4]); + assert_eq!(unsize_nested_fat_ptr(x).get(), [3, 4]); +}