Skip to content

[beta] backports #37239

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 18, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
@@ -583,7 +583,8 @@ impl_trans_normalize!('gcx,
ty::FnSig<'gcx>,
&'gcx ty::BareFnTy<'gcx>,
ty::ClosureSubsts<'gcx>,
ty::PolyTraitRef<'gcx>
ty::PolyTraitRef<'gcx>,
ty::ExistentialTraitRef<'gcx>
);

impl<'gcx> TransNormalize<'gcx> for LvalueTy<'gcx> {
@@ -603,6 +604,18 @@ impl<'gcx> TransNormalize<'gcx> for LvalueTy<'gcx> {

// NOTE: Callable from trans only!
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
/// Currently, higher-ranked type bounds inhibit normalization. Therefore,
/// each time we erase them in translation, we need to normalize
/// the contents.
pub fn erase_late_bound_regions_and_normalize<T>(self, value: &ty::Binder<T>)
-> T
where T: TransNormalize<'tcx>
{
assert!(!value.needs_subst());
let value = self.erase_late_bound_regions(value);
self.normalize_associated_type(&value)
}

pub fn normalize_associated_type<T>(self, value: &T) -> T
where T: TransNormalize<'tcx>
{
6 changes: 2 additions & 4 deletions src/librustc_trans/base.rs
Original file line number Diff line number Diff line change
@@ -1133,8 +1133,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
let fn_ty = ccx.tcx().erase_regions(&fn_ty);
let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);

let sig = ccx.tcx().erase_late_bound_regions(fn_ty.fn_sig());
let sig = ccx.tcx().normalize_associated_type(&sig);
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_ty.fn_sig());
let abi = fn_ty.fn_abi();

let lldecl = match ccx.instances().borrow().get(&instance) {
@@ -1156,8 +1155,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let ctor_ty = ccx.tcx().lookup_item_type(def_id).ty;
let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty);

let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig());
let sig = ccx.tcx().normalize_associated_type(&sig);
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig());
let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);

let (arena, fcx): (TypedArena<_>, FunctionContext);
73 changes: 56 additions & 17 deletions src/librustc_trans/builder.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
6 changes: 2 additions & 4 deletions src/librustc_trans/callee.rs
Original file line number Diff line number Diff line change
@@ -184,8 +184,7 @@ impl<'tcx> Callee<'tcx> {
pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
extra_args: &[Ty<'tcx>]) -> FnType {
let abi = self.ty.fn_abi();
let sig = ccx.tcx().erase_late_bound_regions(self.ty.fn_sig());
let sig = ccx.tcx().normalize_associated_type(&sig);
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(self.ty.fn_sig());
let mut fn_ty = FnType::unadjusted(ccx, abi, &sig, extra_args);
if let Virtual(_) = self.data {
// Don't pass the vtable, it's not an argument of the virtual fn.
@@ -327,8 +326,7 @@ fn trans_fn_pointer_shim<'a, 'tcx>(
bare_fn_ty);
}
};
let sig = tcx.erase_late_bound_regions(sig);
let sig = ccx.tcx().normalize_associated_type(&sig);
let sig = tcx.erase_late_bound_regions_and_normalize(sig);
let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec());
let sig = ty::FnSig {
inputs: vec![bare_fn_ty_maybe_ref,
9 changes: 3 additions & 6 deletions src/librustc_trans/closure.rs
Original file line number Diff line number Diff line change
@@ -61,8 +61,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,

// Compute the rust-call form of the closure call method.
let sig = &tcx.closure_type(closure_id, substs).sig;
let sig = tcx.erase_late_bound_regions(sig);
let sig = tcx.normalize_associated_type(&sig);
let sig = tcx.erase_late_bound_regions_and_normalize(sig);
let closure_type = tcx.mk_closure_from_closure_substs(closure_id, substs);
let function_type = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
unsafety: hir::Unsafety::Normal,
@@ -126,8 +125,7 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// of the closure expression.

let sig = &tcx.closure_type(closure_def_id, closure_substs).sig;
let sig = tcx.erase_late_bound_regions(sig);
let sig = tcx.normalize_associated_type(&sig);
let sig = tcx.erase_late_bound_regions_and_normalize(sig);

let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id,
closure_substs);
@@ -249,8 +247,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
assert_eq!(abi, Abi::RustCall);
sig.0.inputs[0] = closure_ty;

let sig = tcx.erase_late_bound_regions(&sig);
let sig = tcx.normalize_associated_type(&sig);
let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
let fn_ty = FnType::new(ccx, abi, &sig, &[]);

let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
6 changes: 3 additions & 3 deletions src/librustc_trans/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
@@ -235,7 +235,8 @@ impl<'tcx> TypeMap<'tcx> {
ty::TyTrait(ref trait_data) => {
unique_type_id.push_str("trait ");

let principal = cx.tcx().erase_late_bound_regions(&trait_data.principal);
let principal = cx.tcx().erase_late_bound_regions_and_normalize(
&trait_data.principal);

from_def_id_and_substs(self,
cx,
@@ -253,8 +254,7 @@ impl<'tcx> TypeMap<'tcx> {

unique_type_id.push_str(" fn(");

let sig = cx.tcx().erase_late_bound_regions(sig);
let sig = cx.tcx().normalize_associated_type(&sig);
let sig = cx.tcx().erase_late_bound_regions_and_normalize(sig);

for &parameter_type in &sig.inputs {
let parameter_type_id =
6 changes: 3 additions & 3 deletions src/librustc_trans/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
@@ -94,7 +94,8 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
output.push(']');
},
ty::TyTrait(ref trait_data) => {
let principal = cx.tcx().erase_late_bound_regions(&trait_data.principal);
let principal = cx.tcx().erase_late_bound_regions_and_normalize(
&trait_data.principal);
push_item_name(cx, principal.def_id, false, output);
push_type_params(cx, principal.substs, output);
},
@@ -112,8 +113,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,

output.push_str("fn(");

let sig = cx.tcx().erase_late_bound_regions(sig);
let sig = cx.tcx().normalize_associated_type(&sig);
let sig = cx.tcx().erase_late_bound_regions_and_normalize(sig);
if !sig.inputs.is_empty() {
for &parameter_type in &sig.inputs {
push_debuginfo_type_name(cx, parameter_type, true, output);
3 changes: 1 addition & 2 deletions src/librustc_trans/declare.rs
Original file line number Diff line number Diff line change
@@ -104,8 +104,7 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> ValueRef {
debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
let abi = fn_type.fn_abi();
let sig = ccx.tcx().erase_late_bound_regions(fn_type.fn_sig());
let sig = ccx.tcx().normalize_associated_type(&sig);
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_type.fn_sig());
debug!("declare_rust_fn (after region erasure) sig={:?}", sig);

let fty = FnType::new(ccx, abi, &sig, &[]);
12 changes: 5 additions & 7 deletions src/librustc_trans/intrinsic.rs
Original file line number Diff line number Diff line change
@@ -99,13 +99,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,

let _icx = push_ctxt("trans_intrinsic_call");

let (def_id, substs, sig) = match callee_ty.sty {
ty::TyFnDef(def_id, substs, fty) => {
let sig = tcx.erase_late_bound_regions(&fty.sig);
(def_id, substs, tcx.normalize_associated_type(&sig))
}
let (def_id, substs, fty) = match callee_ty.sty {
ty::TyFnDef(def_id, substs, ref fty) => (def_id, substs, fty),
_ => bug!("expected fn item type, found {}", callee_ty)
};

let sig = tcx.erase_late_bound_regions_and_normalize(&fty.sig);
let arg_tys = sig.inputs;
let ret_ty = sig.output;
let name = tcx.item_name(def_id).as_str();
@@ -1108,8 +1107,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>


let tcx = bcx.tcx();
let sig = tcx.erase_late_bound_regions(callee_ty.fn_sig());
let sig = tcx.normalize_associated_type(&sig);
let sig = tcx.erase_late_bound_regions_and_normalize(callee_ty.fn_sig());
let arg_tys = sig.inputs;

// every intrinsic takes a SIMD vector as its first argument
3 changes: 1 addition & 2 deletions src/librustc_trans/meth.rs
Original file line number Diff line number Diff line change
@@ -80,8 +80,7 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
_ => bug!()
};

let sig = tcx.erase_late_bound_regions(sig);
let sig = tcx.normalize_associated_type(&sig);
let sig = tcx.erase_late_bound_regions_and_normalize(sig);
let fn_ty = FnType::new(ccx, abi, &sig, &[]);

let llfn = declare::define_internal_fn(ccx, &function_name, callee.ty);
2 changes: 1 addition & 1 deletion src/librustc_trans/mir/block.rs
Original file line number Diff line number Diff line change
@@ -419,7 +419,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
_ => bug!("{} is not callable", callee.ty)
};

let sig = bcx.tcx().erase_late_bound_regions(sig);
let sig = bcx.tcx().erase_late_bound_regions_and_normalize(sig);

// Handle intrinsics old trans wants Expr's for, ourselves.
let intrinsic = match (&callee.ty.sty, &callee.data) {
2 changes: 1 addition & 1 deletion src/librustc_trans/trans_item.rs
Original file line number Diff line number Diff line change
@@ -473,7 +473,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,

output.push_str("fn(");

let sig = tcx.erase_late_bound_regions(sig);
let sig = tcx.erase_late_bound_regions_and_normalize(sig);
if !sig.inputs.is_empty() {
for &parameter_type in &sig.inputs {
push_unique_type_name(tcx, parameter_type, output);
3 changes: 1 addition & 2 deletions src/librustc_trans/type_of.rs
Original file line number Diff line number Diff line change
@@ -264,8 +264,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->

ty::TyFnDef(..) => Type::nil(cx),
ty::TyFnPtr(f) => {
let sig = cx.tcx().erase_late_bound_regions(&f.sig);
let sig = cx.tcx().normalize_associated_type(&sig);
let sig = cx.tcx().erase_late_bound_regions_and_normalize(&f.sig);
FnType::new(cx, f.abi, &sig, &[]).llvm_type(cx).ptr_to()
}
ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),
32 changes: 32 additions & 0 deletions src/test/run-pass/issue-36744-bitcast-args-if-needed.rs
Original file line number Diff line number Diff line change
@@ -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);
}
22 changes: 22 additions & 0 deletions src/test/run-pass/issue-36744-without-calls.rs
Original file line number Diff line number Diff line change
@@ -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() {}
25 changes: 25 additions & 0 deletions src/test/run-pass/issue-37109.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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.

trait ToRef<'a> {
type Ref: 'a;
}

impl<'a, U: 'a> ToRef<'a> for U {
type Ref = &'a U;
}

fn example<'a, T>(value: &'a T) -> (<T as ToRef<'a>>::Ref, u32) {
(value, 0)
}

fn main() {
example(&0);
}