about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorLuqman Aden <me@luqman.ca>2016-05-18 22:25:03 -0400
committerLuqman Aden <me@luqman.ca>2016-05-19 02:42:24 -0400
commit94f0918c19a6f4f260535620cf66b6c4589d7a67 (patch)
tree2a969a30723bc5a2d37400dfdea25661518b494b /src
parent9a140454ea47b7fd107b6e963b7ea2aef74e9518 (diff)
downloadrust-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.rs8
-rw-r--r--src/librustc_trans/mir/rvalue.rs9
-rw-r--r--src/librustc_trans/type_of.rs11
-rw-r--r--src/test/run-pass/issue-33387.rs44
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]);
+}