diff options
| author | Luqman Aden <me@luqman.ca> | 2016-05-18 22:25:03 -0400 |
|---|---|---|
| committer | Luqman Aden <me@luqman.ca> | 2016-05-19 02:42:24 -0400 |
| commit | 94f0918c19a6f4f260535620cf66b6c4589d7a67 (patch) | |
| tree | 2a969a30723bc5a2d37400dfdea25661518b494b /src | |
| parent | 9a140454ea47b7fd107b6e963b7ea2aef74e9518 (diff) | |
| download | rust-94f0918c19a6f4f260535620cf66b6c4589d7a67.tar.gz rust-94f0918c19a6f4f260535620cf66b6c4589d7a67.zip | |
[MIR] Add PointerCast for Unsize casts of fat pointers.
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc_trans/base.rs | 8 | ||||
| -rw-r--r-- | src/librustc_trans/mir/rvalue.rs | 9 | ||||
| -rw-r--r-- | src/librustc_trans/type_of.rs | 11 | ||||
| -rw-r--r-- | src/test/run-pass/issue-33387.rs | 44 |
4 files changed, 68 insertions, 4 deletions
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 481154ba29f..0b54ccef7a3 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 bcbf3e1fa18..5945e8813a4 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 98ec87ebbcf..e5acb9b6699 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 00000000000..a4b85bc7a09 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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: ?Sized>(T); + +#[rustc_mir] +fn unsize_fat_ptr<'a>(x: &'a Bar<Foo + Send + 'a>) -> &'a Bar<Foo + 'a> { + x +} + +#[rustc_mir] +fn unsize_nested_fat_ptr(x: Arc<Foo + Send>) -> Arc<Foo> { + x +} + +#[rustc_mir] +fn main() { + let x: Box<Bar<Foo + Send>> = Box::new(Bar([1,2])); + assert_eq!(unsize_fat_ptr(&*x).0.get(), [1, 2]); + + let x: Arc<Foo + Send> = Arc::new([3, 4]); + assert_eq!(unsize_nested_fat_ptr(x).get(), [3, 4]); +} |
