about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-10-17 09:47:46 -0700
committerGitHub <noreply@github.com>2016-10-17 09:47:46 -0700
commitce316268014ed7bc3599324b379be1331997d3ab (patch)
tree56145cd332167835fedc966d89dec96db9c6ec71
parent07b86d0d4d41976f52aa318960e605534ee42d4f (diff)
parent05626546081394f4ba0c9d916c35e48cc29d2af6 (diff)
downloadrust-ce316268014ed7bc3599324b379be1331997d3ab.tar.gz
rust-ce316268014ed7bc3599324b379be1331997d3ab.zip
Auto merge of #37112 - pnkfelix:fix-issue-36744, r=arielb1
Fix ICE: inject bitcast if types mismatch for invokes/calls/stores

Fix ICE: inject bitcast if types mismatch for invokes/calls

Fix #36744
-rw-r--r--src/librustc_trans/builder.rs73
-rw-r--r--src/test/run-pass/issue-36744-bitcast-args-if-needed.rs32
-rw-r--r--src/test/run-pass/issue-36744-without-calls.rs22
3 files changed, 110 insertions, 17 deletions
diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs
index 90f96af5496..8556e95903c 100644
--- a/src/librustc_trans/builder.rs
+++ b/src/librustc_trans/builder.rs
@@ -22,6 +22,7 @@ use value::Value;
 use util::nodemap::FnvHashMap;
 use libc::{c_uint, c_char};
 
+use std::borrow::Cow;
 use std::ffi::CString;
 use std::ptr;
 use syntax_pos::Span;
@@ -175,8 +176,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                    .collect::<Vec<String>>()
                    .join(", "));
 
-        check_call("invoke", llfn, args);
-
+        let args = self.check_call("invoke", llfn, args);
         let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut());
 
         unsafe {
@@ -543,6 +543,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
         assert!(!self.llbuilder.is_null());
         self.count_insn("store");
+        let ptr = self.check_store(val, ptr);
         unsafe {
             llvm::LLVMBuildStore(self.llbuilder, val, ptr)
         }
@@ -552,6 +553,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
         assert!(!self.llbuilder.is_null());
         self.count_insn("store.volatile");
+        let ptr = self.check_store(val, ptr);
         unsafe {
             let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
             llvm::LLVMSetVolatile(insn, llvm::True);
@@ -562,6 +564,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef, order: AtomicOrdering) {
         debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
         self.count_insn("store.atomic");
+        let ptr = self.check_store(val, ptr);
         unsafe {
             let ty = Type::from_ref(llvm::LLVMTypeOf(ptr));
             let align = llalign_of_pref(self.ccx, ty.element_type());
@@ -857,8 +860,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                    .collect::<Vec<String>>()
                    .join(", "));
 
-        check_call("call", llfn, args);
-
+        let args = self.check_call("call", llfn, args);
         let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut());
 
         unsafe {
@@ -1100,10 +1102,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             llvm::LLVMRustBuildAtomicFence(self.llbuilder, order, scope);
         }
     }
-}
 
-fn check_call(typ: &str, llfn: ValueRef, args: &[ValueRef]) {
-    if cfg!(debug_assertions) {
+    /// Returns the ptr value that should be used for storing `val`.
+    fn check_store<'b>(&self,
+                       val: ValueRef,
+                       ptr: ValueRef) -> ValueRef {
+        let dest_ptr_ty = val_ty(ptr);
+        let stored_ty = val_ty(val);
+        let stored_ptr_ty = stored_ty.ptr_to();
+
+        assert_eq!(dest_ptr_ty.kind(), llvm::TypeKind::Pointer);
+
+        if dest_ptr_ty == stored_ptr_ty {
+            ptr
+        } else {
+            debug!("Type mismatch in store. \
+                    Expected {:?}, got {:?}; inserting bitcast",
+                   dest_ptr_ty, stored_ptr_ty);
+            self.bitcast(ptr, stored_ptr_ty)
+        }
+    }
+
+    /// Returns the args that should be used for a call to `llfn`.
+    fn check_call<'b>(&self,
+                      typ: &str,
+                      llfn: ValueRef,
+                      args: &'b [ValueRef]) -> Cow<'b, [ValueRef]> {
         let mut fn_ty = val_ty(llfn);
         // Strip off pointers
         while fn_ty.kind() == llvm::TypeKind::Pointer {
@@ -1115,16 +1139,31 @@ fn check_call(typ: &str, llfn: ValueRef, args: &[ValueRef]) {
 
         let param_tys = fn_ty.func_params();
 
-        let iter = param_tys.into_iter()
-            .zip(args.iter().map(|&v| val_ty(v)));
-        for (i, (expected_ty, actual_ty)) in iter.enumerate() {
-            if expected_ty != actual_ty {
-                bug!("Type mismatch in function call of {:?}. \
-                      Expected {:?} for param {}, got {:?}",
-                     Value(llfn),
-                     expected_ty, i, actual_ty);
+        let all_args_match = param_tys.iter()
+            .zip(args.iter().map(|&v| val_ty(v)))
+            .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);
+
+        if all_args_match {
+            return Cow::Borrowed(args);
+        }
+
+        let casted_args: Vec<_> = param_tys.into_iter()
+            .zip(args.iter())
+            .enumerate()
+            .map(|(i, (expected_ty, &actual_val))| {
+                let actual_ty = val_ty(actual_val);
+                if expected_ty != actual_ty {
+                    debug!("Type mismatch in function call of {:?}. \
+                            Expected {:?} for param {}, got {:?}; injecting bitcast",
+                           Value(llfn),
+                           expected_ty, i, actual_ty);
+                    self.bitcast(actual_val, expected_ty)
+                } else {
+                    actual_val
+                }
+            })
+            .collect();
 
-            }
-        }
+        return Cow::Owned(casted_args);
     }
 }
diff --git a/src/test/run-pass/issue-36744-bitcast-args-if-needed.rs b/src/test/run-pass/issue-36744-bitcast-args-if-needed.rs
new file mode 100644
index 00000000000..1859cc9ca00
--- /dev/null
+++ b/src/test/run-pass/issue-36744-bitcast-args-if-needed.rs
@@ -0,0 +1,32 @@
+// 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.
+
+// This tests for an ICE (and, if ignored, subsequent LLVM abort) when
+// a lifetime-parametric fn is passed into a context whose expected
+// type has a differing lifetime parameterization.
+
+struct A<'a> {
+    _a: &'a i32,
+}
+
+fn call<T>(s: T, functions: &Vec<for <'n> fn(&'n T)>) {
+    for function in functions {
+        function(&s);
+    }
+}
+
+fn f(a: &A) { println!("a holds {}", a._a); }
+
+fn main() {
+    let a = A { _a: &10 };
+
+    let vec: Vec<for <'u,'v> fn(&'u A<'v>)> = vec![f];
+    call(a, &vec);
+}
diff --git a/src/test/run-pass/issue-36744-without-calls.rs b/src/test/run-pass/issue-36744-without-calls.rs
new file mode 100644
index 00000000000..1766edb06b4
--- /dev/null
+++ b/src/test/run-pass/issue-36744-without-calls.rs
@@ -0,0 +1,22 @@
+// 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.
+
+// Tests for an LLVM abort when storing a lifetime-parametric fn into
+// context that is expecting one that is not lifetime-parametric
+// (i.e. has no `for <'_>`).
+
+pub struct A<'a>(&'a ());
+pub struct S<T>(T);
+
+pub fn bad<'s>(v: &mut S<fn(A<'s>)>, y: S<for<'b> fn(A<'b>)>) {
+    *v = y;
+}
+
+fn main() {}