Skip to content

Commit ce31626

Browse files
authored
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
2 parents 07b86d0 + 0562654 commit ce31626

File tree

3 files changed

+110
-17
lines changed

3 files changed

+110
-17
lines changed

src/librustc_trans/builder.rs

+56-17
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use value::Value;
2222
use util::nodemap::FnvHashMap;
2323
use libc::{c_uint, c_char};
2424

25+
use std::borrow::Cow;
2526
use std::ffi::CString;
2627
use std::ptr;
2728
use syntax_pos::Span;
@@ -175,8 +176,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
175176
.collect::<Vec<String>>()
176177
.join(", "));
177178

178-
check_call("invoke", llfn, args);
179-
179+
let args = self.check_call("invoke", llfn, args);
180180
let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut());
181181

182182
unsafe {
@@ -543,6 +543,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
543543
debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
544544
assert!(!self.llbuilder.is_null());
545545
self.count_insn("store");
546+
let ptr = self.check_store(val, ptr);
546547
unsafe {
547548
llvm::LLVMBuildStore(self.llbuilder, val, ptr)
548549
}
@@ -552,6 +553,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
552553
debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
553554
assert!(!self.llbuilder.is_null());
554555
self.count_insn("store.volatile");
556+
let ptr = self.check_store(val, ptr);
555557
unsafe {
556558
let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
557559
llvm::LLVMSetVolatile(insn, llvm::True);
@@ -562,6 +564,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
562564
pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef, order: AtomicOrdering) {
563565
debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
564566
self.count_insn("store.atomic");
567+
let ptr = self.check_store(val, ptr);
565568
unsafe {
566569
let ty = Type::from_ref(llvm::LLVMTypeOf(ptr));
567570
let align = llalign_of_pref(self.ccx, ty.element_type());
@@ -857,8 +860,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
857860
.collect::<Vec<String>>()
858861
.join(", "));
859862

860-
check_call("call", llfn, args);
861-
863+
let args = self.check_call("call", llfn, args);
862864
let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut());
863865

864866
unsafe {
@@ -1100,10 +1102,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
11001102
llvm::LLVMRustBuildAtomicFence(self.llbuilder, order, scope);
11011103
}
11021104
}
1103-
}
11041105

1105-
fn check_call(typ: &str, llfn: ValueRef, args: &[ValueRef]) {
1106-
if cfg!(debug_assertions) {
1106+
/// Returns the ptr value that should be used for storing `val`.
1107+
fn check_store<'b>(&self,
1108+
val: ValueRef,
1109+
ptr: ValueRef) -> ValueRef {
1110+
let dest_ptr_ty = val_ty(ptr);
1111+
let stored_ty = val_ty(val);
1112+
let stored_ptr_ty = stored_ty.ptr_to();
1113+
1114+
assert_eq!(dest_ptr_ty.kind(), llvm::TypeKind::Pointer);
1115+
1116+
if dest_ptr_ty == stored_ptr_ty {
1117+
ptr
1118+
} else {
1119+
debug!("Type mismatch in store. \
1120+
Expected {:?}, got {:?}; inserting bitcast",
1121+
dest_ptr_ty, stored_ptr_ty);
1122+
self.bitcast(ptr, stored_ptr_ty)
1123+
}
1124+
}
1125+
1126+
/// Returns the args that should be used for a call to `llfn`.
1127+
fn check_call<'b>(&self,
1128+
typ: &str,
1129+
llfn: ValueRef,
1130+
args: &'b [ValueRef]) -> Cow<'b, [ValueRef]> {
11071131
let mut fn_ty = val_ty(llfn);
11081132
// Strip off pointers
11091133
while fn_ty.kind() == llvm::TypeKind::Pointer {
@@ -1115,16 +1139,31 @@ fn check_call(typ: &str, llfn: ValueRef, args: &[ValueRef]) {
11151139

11161140
let param_tys = fn_ty.func_params();
11171141

1118-
let iter = param_tys.into_iter()
1119-
.zip(args.iter().map(|&v| val_ty(v)));
1120-
for (i, (expected_ty, actual_ty)) in iter.enumerate() {
1121-
if expected_ty != actual_ty {
1122-
bug!("Type mismatch in function call of {:?}. \
1123-
Expected {:?} for param {}, got {:?}",
1124-
Value(llfn),
1125-
expected_ty, i, actual_ty);
1142+
let all_args_match = param_tys.iter()
1143+
.zip(args.iter().map(|&v| val_ty(v)))
1144+
.all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);
1145+
1146+
if all_args_match {
1147+
return Cow::Borrowed(args);
1148+
}
1149+
1150+
let casted_args: Vec<_> = param_tys.into_iter()
1151+
.zip(args.iter())
1152+
.enumerate()
1153+
.map(|(i, (expected_ty, &actual_val))| {
1154+
let actual_ty = val_ty(actual_val);
1155+
if expected_ty != actual_ty {
1156+
debug!("Type mismatch in function call of {:?}. \
1157+
Expected {:?} for param {}, got {:?}; injecting bitcast",
1158+
Value(llfn),
1159+
expected_ty, i, actual_ty);
1160+
self.bitcast(actual_val, expected_ty)
1161+
} else {
1162+
actual_val
1163+
}
1164+
})
1165+
.collect();
11261166

1127-
}
1128-
}
1167+
return Cow::Owned(casted_args);
11291168
}
11301169
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This tests for an ICE (and, if ignored, subsequent LLVM abort) when
12+
// a lifetime-parametric fn is passed into a context whose expected
13+
// type has a differing lifetime parameterization.
14+
15+
struct A<'a> {
16+
_a: &'a i32,
17+
}
18+
19+
fn call<T>(s: T, functions: &Vec<for <'n> fn(&'n T)>) {
20+
for function in functions {
21+
function(&s);
22+
}
23+
}
24+
25+
fn f(a: &A) { println!("a holds {}", a._a); }
26+
27+
fn main() {
28+
let a = A { _a: &10 };
29+
30+
let vec: Vec<for <'u,'v> fn(&'u A<'v>)> = vec![f];
31+
call(a, &vec);
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Tests for an LLVM abort when storing a lifetime-parametric fn into
12+
// context that is expecting one that is not lifetime-parametric
13+
// (i.e. has no `for <'_>`).
14+
15+
pub struct A<'a>(&'a ());
16+
pub struct S<T>(T);
17+
18+
pub fn bad<'s>(v: &mut S<fn(A<'s>)>, y: S<for<'b> fn(A<'b>)>) {
19+
*v = y;
20+
}
21+
22+
fn main() {}

0 commit comments

Comments
 (0)