diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 39fc50666a8ce..4f74e765bd08b 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -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(self, value: &ty::Binder) + -> 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(self, value: &T) -> T where T: TransNormalize<'tcx> { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index d80ed5e27cc6d..a2f2e9dd8dd2b 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -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); diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 90f96af549691..8556e95903c18 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::>() .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::>() .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/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 8822287a0e754..05e22896c4006 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -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, diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs index c87497384ad6a..a1d645fb993b0 100644 --- a/src/librustc_trans/closure.rs +++ b/src/librustc_trans/closure.rs @@ -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 { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index a441800795b96..ffca5d324472b 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -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 ¶meter_type in &sig.inputs { let parameter_type_id = diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 7f021bee37199..956402edc1166 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -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 ¶meter_type in &sig.inputs { push_debuginfo_type_name(cx, parameter_type, true, output); diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 0c1156a98743e..1ec5ca4a563a0 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -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, &[]); diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 4cacbc0f35eff..b1b09d3ca20de 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -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 diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index e8dcaf71f2dd2..dac70d4a1de70 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -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); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 003830123ff3b..83b3880c383ee 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -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) { diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 5c7cbbbd88d46..131df50217ed9 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -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 ¶meter_type in &sig.inputs { push_unique_type_name(tcx, parameter_type, output); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 8183639ae2210..132b0a910b9c1 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -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), 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 0000000000000..1859cc9ca00b5 --- /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 or the MIT license +// , 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(s: T, functions: &Vec 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 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 0000000000000..1766edb06b481 --- /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 or the MIT license +// , 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); + +pub fn bad<'s>(v: &mut S)>, y: S fn(A<'b>)>) { + *v = y; +} + +fn main() {} diff --git a/src/test/run-pass/issue-37109.rs b/src/test/run-pass/issue-37109.rs new file mode 100644 index 0000000000000..1c893071d5589 --- /dev/null +++ b/src/test/run-pass/issue-37109.rs @@ -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 or the MIT license +// , 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) -> (>::Ref, u32) { + (value, 0) +} + +fn main() { + example(&0); +}