diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 4fe82f03b036e..0b9dd4f6a78d0 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -10,7 +10,7 @@ use crate::ty::query::TyCtxtAt; use backtrace::Backtrace; use errors::DiagnosticBuilder; use rustc_macros::HashStable; -use rustc_target::spec::abi::Abi; +use rustc_target::abi; use syntax_pos::{Pos, Span}; use syntax::symbol::Symbol; @@ -396,7 +396,7 @@ pub enum UnsupportedOpInfo<'tcx> { Unsupported(String), // -- Everything below is not categorized yet -- - FunctionAbiMismatch(Abi, Abi), + FunctionAbiMismatch(abi::call::Conv, abi::call::Conv), FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>), FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>), FunctionArgCountMismatch, @@ -460,9 +460,9 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { write!(f, "type validation failed: {}", err) } NoMirFor(ref func) => write!(f, "no MIR for `{}`", func), - FunctionAbiMismatch(caller_abi, callee_abi) => + FunctionAbiMismatch(caller_conv, callee_conv) => write!(f, "tried to call a function with ABI {:?} using caller ABI {:?}", - callee_abi, caller_abi), + callee_conv, caller_conv), FunctionArgMismatch(caller_ty, callee_ty) => write!(f, "tried to call a function with argument of type {:?} \ passing data of type {:?}", diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 777db38850fec..801dfa81ef178 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -1,8 +1,7 @@ use crate::hir::CodegenFnAttrFlags; -use crate::hir::Unsafety; use crate::hir::def::Namespace; use crate::hir::def_id::DefId; -use crate::ty::{self, Ty, PolyFnSig, TypeFoldable, SubstsRef, TyCtxt}; +use crate::ty::{self, Ty, TypeFoldable, SubstsRef, TyCtxt}; use crate::ty::print::{FmtPrinter, Printer}; use crate::traits; use crate::middle::lang_items::DropInPlaceFnLangItem; @@ -10,7 +9,6 @@ use rustc_target::spec::abi::Abi; use rustc_macros::HashStable; use std::fmt; -use std::iter; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] #[derive(HashStable, Lift)] @@ -29,17 +27,26 @@ pub enum InstanceDef<'tcx> { /// `fn()` pointer where the function itself cannot be turned into a pointer. /// - /// One example in the compiler today is functions annotated with `#[track_caller]`, which - /// must have their implicit caller location argument populated for a call. Because this is a - /// required part of the function's ABI but can't be tracked as a property of the function - /// pointer, we create a single "caller location" at the site where the function is reified. + /// One example is `::fn`, where the shim contains + /// a virtual call, which codegen supports only via a direct call to the + /// `::fn` instance (an `InstanceDef::Virtual`). + /// + /// Another example is functions annotated with `#[track_caller]`, which + /// must have their implicit caller location argument populated for a call. + /// Because this is a required part of the function's ABI but can't be tracked + /// as a property of the function pointer, we use a single "caller location" + /// (the definition of the function itself). ReifyShim(DefId), /// `::call_*` /// `DefId` is `FnTrait::call_*`. FnPtrShim(DefId, Ty<'tcx>), - /// `::fn` + /// `::fn`, "direct calls" of which are implicitly + /// codegen'd as virtual calls. + /// + /// NB: if this is reified to a `fn` pointer, a `ReifyShim` is used + /// (see `ReifyShim` above for more details on that). Virtual(DefId, usize), /// `<[mut closure] as FnOnce>::call_once` @@ -61,70 +68,6 @@ impl<'tcx> Instance<'tcx> { &ty, ) } - - fn fn_sig_noadjust(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { - let ty = self.ty(tcx); - match ty.kind { - ty::FnDef(..) | - // Shims currently have type FnPtr. Not sure this should remain. - ty::FnPtr(_) => ty.fn_sig(tcx), - ty::Closure(def_id, substs) => { - let sig = substs.as_closure().sig(def_id, tcx); - - let env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); - sig.map_bound(|sig| tcx.mk_fn_sig( - iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), - sig.output(), - sig.c_variadic, - sig.unsafety, - sig.abi - )) - } - ty::Generator(def_id, substs, _) => { - let sig = substs.as_generator().poly_sig(def_id, tcx); - - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); - let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); - - let pin_did = tcx.lang_items().pin_type().unwrap(); - let pin_adt_ref = tcx.adt_def(pin_did); - let pin_substs = tcx.intern_substs(&[env_ty.into()]); - let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs); - - sig.map_bound(|sig| { - let state_did = tcx.lang_items().gen_state().unwrap(); - let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.intern_substs(&[ - sig.yield_ty.into(), - sig.return_ty.into(), - ]); - let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); - - tcx.mk_fn_sig(iter::once(env_ty), - ret_ty, - false, - Unsafety::Normal, - Abi::Rust - ) - }) - } - _ => bug!("unexpected type {:?} in Instance::fn_sig_noadjust", ty) - } - } - - pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { - let mut fn_sig = self.fn_sig_noadjust(tcx); - if let InstanceDef::VtableShim(..) = self.def { - // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. - fn_sig = fn_sig.map_bound(|mut fn_sig| { - let mut inputs_and_output = fn_sig.inputs_and_output.to_vec(); - inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]); - fn_sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output); - fn_sig - }); - } - fn_sig - } } impl<'tcx> InstanceDef<'tcx> { @@ -196,7 +139,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> { write!(f, " - intrinsic") } InstanceDef::Virtual(_, num) => { - write!(f, " - shim(#{})", num) + write!(f, " - virtual#{}", num) } InstanceDef::FnPtrShim(_, ty) => { write!(f, " - shim({:?})", ty) @@ -311,20 +254,23 @@ impl<'tcx> Instance<'tcx> { substs: SubstsRef<'tcx>, ) -> Option> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); - Instance::resolve(tcx, param_env, def_id, substs).map(|resolved| { + Instance::resolve(tcx, param_env, def_id, substs).map(|mut resolved| { let has_track_caller = |def| tcx.codegen_fn_attrs(def).flags .contains(CodegenFnAttrFlags::TRACK_CALLER); match resolved.def { InstanceDef::Item(def_id) if has_track_caller(def_id) => { debug!(" => fn pointer created for function with #[track_caller]"); - Instance { - def: InstanceDef::ReifyShim(def_id), - substs, - } - }, - _ => resolved, + resolved.def = InstanceDef::ReifyShim(def_id); + } + InstanceDef::Virtual(def_id, _) => { + debug!(" => fn pointer created for virtual call"); + resolved.def = InstanceDef::ReifyShim(def_id); + } + _ => {} } + + resolved }) } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index b6050a5caf13e..0a1480664639f 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2339,6 +2339,76 @@ impl<'a, 'tcx> HashStable> for LayoutError<'tcx> { } } + +impl<'tcx> ty::Instance<'tcx> { + // NOTE(eddyb) this is private to avoid using it from outside of + // `FnAbi::of_instance` - any other uses are either too high-level + // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead), + // or should go through `FnAbi` instead, to avoid losing any + // adjustments `FnAbi::of_instance` might be performing. + fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { + let ty = self.ty(tcx); + match ty.kind { + ty::FnDef(..) | + // Shims currently have type FnPtr. Not sure this should remain. + ty::FnPtr(_) => { + let mut sig = ty.fn_sig(tcx); + if let ty::InstanceDef::VtableShim(..) = self.def { + // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. + sig = sig.map_bound(|mut sig| { + let mut inputs_and_output = sig.inputs_and_output.to_vec(); + inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]); + sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output); + sig + }); + } + sig + } + ty::Closure(def_id, substs) => { + let sig = substs.as_closure().sig(def_id, tcx); + + let env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); + sig.map_bound(|sig| tcx.mk_fn_sig( + iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), + sig.output(), + sig.c_variadic, + sig.unsafety, + sig.abi + )) + } + ty::Generator(def_id, substs, _) => { + let sig = substs.as_generator().poly_sig(def_id, tcx); + + let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); + let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); + + let pin_did = tcx.lang_items().pin_type().unwrap(); + let pin_adt_ref = tcx.adt_def(pin_did); + let pin_substs = tcx.intern_substs(&[env_ty.into()]); + let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs); + + sig.map_bound(|sig| { + let state_did = tcx.lang_items().gen_state().unwrap(); + let state_adt_ref = tcx.adt_def(state_did); + let state_substs = tcx.intern_substs(&[ + sig.yield_ty.into(), + sig.return_ty.into(), + ]); + let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); + + tcx.mk_fn_sig(iter::once(env_ty), + ret_ty, + false, + hir::Unsafety::Normal, + rustc_target::spec::abi::Abi::Rust + ) + }) + } + _ => bug!("unexpected type {:?} in Instance::fn_sig", ty) + } + } +} + pub trait FnAbiExt<'tcx, C> where C: LayoutOf, TyLayout = TyLayout<'tcx>> @@ -2347,12 +2417,22 @@ where + HasTyCtxt<'tcx> + HasParamEnv<'tcx>, { - fn of_instance(cx: &C, instance: ty::Instance<'tcx>) -> Self; - fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; - fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; + /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. + /// + /// NB: this doesn't handle virtual calls - those should use `FnAbi::of_instance` + /// instead, where the instance is a `InstanceDef::Virtual`. + fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; + + /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for + /// direct calls to an `fn`. + /// + /// NB: that includes virtual calls, which are represented by "direct calls" + /// to a `InstanceDef::Virtual` instance (of `::fn`). + fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; + fn new_internal( cx: &C, - sig: ty::FnSig<'tcx>, + sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>], mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgAbi<'tcx, Ty<'tcx>>, ) -> Self; @@ -2367,25 +2447,19 @@ where + HasTyCtxt<'tcx> + HasParamEnv<'tcx>, { - fn of_instance(cx: &C, instance: ty::Instance<'tcx>) -> Self { - let sig = instance.fn_sig(cx.tcx()); - let sig = cx - .tcx() - .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - call::FnAbi::new(cx, sig, &[]) - } - - fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { + fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { call::FnAbi::new_internal(cx, sig, extra_args, |ty, _| ArgAbi::new(cx.layout_of(ty))) } - fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { - FnAbiExt::new_internal(cx, sig, extra_args, |ty, arg_idx| { + fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { + let sig = instance.fn_sig_for_fn_abi(cx.tcx()); + + call::FnAbi::new_internal(cx, sig, extra_args, |ty, arg_idx| { let mut layout = cx.layout_of(ty); // Don't pass the vtable, it's not an argument of the virtual fn. // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen - if arg_idx == Some(0) { + if let (ty::InstanceDef::Virtual(..), Some(0)) = (&instance.def, arg_idx) { let fat_pointer_ty = if layout.is_unsized() { // unsized `self` is passed as a pointer to `self` // FIXME (mikeyhew) change this to use &own if it is ever added to the language @@ -2436,15 +2510,19 @@ where fn new_internal( cx: &C, - sig: ty::FnSig<'tcx>, + sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>], mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgAbi<'tcx, Ty<'tcx>>, ) -> Self { debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args); + let sig = cx + .tcx() + .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + use rustc_target::spec::abi::Abi::*; let conv = match cx.tcx().sess.target.target.adjust_abi(sig.abi) { - RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::C, + RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust, // It's the ABI's job to select this, not ours. System => bug!("system abi should be selected elsewhere"), diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 804a7af41f39a..1f3c8e1953e4f 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -372,7 +372,7 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { fn llvm_cconv(&self) -> llvm::CallConv { match self.conv { - Conv::C => llvm::CCallConv, + Conv::C | Conv::Rust => llvm::CCallConv, Conv::AmdGpuKernel => llvm::AmdGpuKernel, Conv::ArmAapcs => llvm::ArmAapcsCallConv, Conv::Msp430Intr => llvm::Msp430Intr, @@ -388,6 +388,11 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { } fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) { + // FIXME(eddyb) can this also be applied to callsites? + if self.ret.layout.abi.is_uninhabited() { + llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn); + } + let mut i = 0; let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| { attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn, ty); diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 6f4e7d0f0caf5..33dc2513de584 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -2,19 +2,20 @@ use std::ffi::CString; -use rustc::hir::{CodegenFnAttrFlags, CodegenFnAttrs}; +use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::session::Session; use rustc::session::config::{Sanitizer, OptLevel}; -use rustc::ty::{self, TyCtxt, PolyFnSig}; +use rustc::ty::{self, TyCtxt, Ty}; use rustc::ty::layout::HasTyCtxt; use rustc::ty::query::Providers; use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::fx::FxHashMap; +use rustc_target::abi::call::Conv; use rustc_target::spec::PanicStrategy; use rustc_codegen_ssa::traits::*; -use crate::abi::Abi; +use crate::abi::FnAbi; use crate::attributes; use crate::llvm::{self, Attribute}; use crate::llvm::AttributePlace::Function; @@ -26,7 +27,7 @@ use crate::value::Value; /// Mark LLVM function to use provided inline heuristic. #[inline] -pub fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) { +fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) { use self::InlineAttr::*; match inline { Hint => Attribute::InlineHint.apply_llfn(Function, val), @@ -58,7 +59,7 @@ fn unwind(val: &'ll Value, can_unwind: bool) { /// Tell LLVM if this function should be 'naked', i.e., skip the epilogue and prologue. #[inline] -pub fn naked(val: &'ll Value, is_naked: bool) { +fn naked(val: &'ll Value, is_naked: bool) { Attribute::Naked.toggle_llfn(Function, val, is_naked); } @@ -72,7 +73,7 @@ pub fn set_frame_pointer_elimination(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) /// Tell LLVM what instrument function to insert. #[inline] -pub fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { +fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { if cx.sess().instrument_mcount() { // Similar to `clang -pg` behavior. Handled by the // `post-inline-ee-instrument` LLVM pass. @@ -88,7 +89,7 @@ pub fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { } } -pub fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { +fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { // Only use stack probes if the target specification indicates that we // should be using stack probes if !cx.sess().target.target.options.stack_probes { @@ -202,11 +203,10 @@ pub(crate) fn default_optimisation_attrs(sess: &Session, llfn: &'ll Value) { pub fn from_fn_attrs( cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, - id: Option, - sig: PolyFnSig<'tcx>, + instance: ty::Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, ) { - let codegen_fn_attrs = id.map(|id| cx.tcx.codegen_fn_attrs(id)) - .unwrap_or_else(|| CodegenFnAttrs::new()); + let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); match codegen_fn_attrs.optimize { OptimizeAttr::None => { @@ -224,6 +224,11 @@ pub fn from_fn_attrs( } } + // FIXME(eddyb) consolidate these two `inline` calls (and avoid overwrites). + if instance.def.is_inline(cx.tcx) { + inline(cx, llfn, attributes::InlineAttr::Hint); + } + inline(cx, llfn, codegen_fn_attrs.inline); // The `uwtable` attribute according to LLVM is: @@ -276,8 +281,7 @@ pub fn from_fn_attrs( // Special attribute for allocator functions, which can't unwind. false } else { - let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - if sig.abi == Abi::Rust || sig.abi == Abi::RustCall { + if fn_abi.conv == Conv::Rust { // Any Rust method (or `extern "Rust" fn` or `extern // "rust-call" fn`) is explicitly allowed to unwind // (unless it has no-unwind attribute, handled above). @@ -331,16 +335,14 @@ pub fn from_fn_attrs( // Note that currently the `wasm-import-module` doesn't do anything, but // eventually LLVM 7 should read this and ferry the appropriate import // module to the output file. - if let Some(id) = id { - if cx.tcx.sess.target.target.arch == "wasm32" { - if let Some(module) = wasm_import_module(cx.tcx, id) { - llvm::AddFunctionAttrStringValue( - llfn, - llvm::AttributePlace::Function, - const_cstr!("wasm-import-module"), - &module, - ); - } + if cx.tcx.sess.target.target.arch == "wasm32" { + if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) { + llvm::AddFunctionAttrStringValue( + llfn, + llvm::AttributePlace::Function, + const_cstr!("wasm-import-module"), + &module, + ); } } } diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index 08fa23f2a7c9e..e0db7cae99e1a 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -4,6 +4,7 @@ //! and methods are represented as just a fn ptr and not a full //! closure. +use crate::abi::{FnAbi, FnAbiLlvmExt}; use crate::attributes; use crate::llvm; use crate::context::CodegenCx; @@ -11,7 +12,7 @@ use crate::value::Value; use rustc_codegen_ssa::traits::*; use rustc::ty::{TypeFoldable, Instance}; -use rustc::ty::layout::{LayoutOf, HasTyCtxt}; +use rustc::ty::layout::{FnAbiExt, HasTyCtxt}; /// Codegens a reference to a fn/method item, monomorphizing and /// inlining as it goes. @@ -32,19 +33,19 @@ pub fn get_fn( assert!(!instance.substs.has_escaping_bound_vars()); assert!(!instance.substs.has_param_types()); - let sig = instance.fn_sig(cx.tcx()); if let Some(&llfn) = cx.instances.borrow().get(&instance) { return llfn; } let sym = tcx.symbol_name(instance).name.as_str(); - debug!("get_fn({:?}: {:?}) => {}", instance, sig, sym); + debug!("get_fn({:?}: {:?}) => {}", instance, instance.ty(cx.tcx()), sym); - // Create a fn pointer with the substituted signature. - let fn_ptr_ty = tcx.mk_fn_ptr(sig); - let llptrty = cx.backend_type(cx.layout_of(fn_ptr_ty)); + let fn_abi = FnAbi::of_instance(cx, instance, &[]); let llfn = if let Some(llfn) = cx.get_declared_value(&sym) { + // Create a fn pointer with the new signature. + let llptrty = fn_abi.ptr_to_llvm_type(cx); + // This is subtle and surprising, but sometimes we have to bitcast // the resulting fn pointer. The reason has to do with external // functions. If you have two crates that both bind the same C @@ -76,14 +77,10 @@ pub fn get_fn( llfn } } else { - let llfn = cx.declare_fn(&sym, sig); - assert_eq!(cx.val_ty(llfn), llptrty); + let llfn = cx.declare_fn(&sym, &fn_abi); debug!("get_fn: not casting pointer!"); - if instance.def.is_inline(tcx) { - attributes::inline(cx, llfn, attributes::InlineAttr::Hint); - } - attributes::from_fn_attrs(cx, llfn, Some(instance.def.def_id()), sig); + attributes::from_fn_attrs(cx, llfn, instance, &fn_abi); let instance_def_id = instance.def_id(); diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 4a40349cb73e8..39ea1f6f5dccf 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -1,3 +1,4 @@ +use crate::abi::FnAbi; use crate::attributes; use crate::llvm; use crate::llvm_util; @@ -15,7 +16,7 @@ use rustc::mir::mono::CodegenUnit; use rustc::session::config::{self, DebugInfo}; use rustc::session::Session; use rustc::ty::layout::{ - LayoutError, LayoutOf, PointeeInfo, Size, TyLayout, VariantIdx, HasParamEnv + FnAbiExt, LayoutError, LayoutOf, PointeeInfo, Size, TyLayout, VariantIdx, HasParamEnv }; use rustc::ty::{self, Ty, TyCtxt, Instance}; use rustc::util::nodemap::FxHashMap; @@ -420,7 +421,8 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { Abi::C )); - let llfn = self.declare_fn("rust_eh_unwind_resume", sig); + let fn_abi = FnAbi::of_fn_ptr(self, sig, &[]); + let llfn = self.declare_fn("rust_eh_unwind_resume", &fn_abi); attributes::apply_target_cpu_attr(self, llfn); unwresume.set(Some(llfn)); llfn diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 7713fe47004b9..c2359a2fe6d94 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -16,7 +16,7 @@ use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; use rustc::ty::subst::{SubstsRef, GenericArgKind}; -use crate::abi::Abi; +use crate::abi::FnAbi; use crate::common::CodegenCx; use crate::builder::Builder; use crate::value::Value; @@ -280,7 +280,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn create_function_debug_context( &self, instance: Instance<'tcx>, - sig: ty::FnSig<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: &'ll Value, mir: &mir::Body<'_>, ) -> Option> { @@ -308,7 +308,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let file_metadata = file_metadata(self, &loc.file.name, def_id.krate); let function_type_metadata = unsafe { - let fn_signature = get_function_signature(self, sig); + let fn_signature = get_function_signature(self, fn_abi); llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), file_metadata, fn_signature) }; @@ -338,7 +338,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let mut flags = DIFlags::FlagPrototyped; - if self.layout_of(sig.output()).abi.is_uninhabited() { + if fn_abi.ret.layout.abi.is_uninhabited() { flags |= DIFlags::FlagNoReturn; } @@ -392,25 +392,20 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn get_function_signature<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, ) -> &'ll DIArray { if cx.sess().opts.debuginfo == DebugInfo::Limited { return create_DIArray(DIB(cx), &[]); } - let mut signature = Vec::with_capacity(sig.inputs().len() + 1); + let mut signature = Vec::with_capacity(fn_abi.args.len() + 1); // Return type -- llvm::DIBuilder wants this at index 0 - signature.push(match sig.output().kind { - ty::Tuple(ref tys) if tys.is_empty() => None, - _ => Some(type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP)) - }); - - let inputs = if sig.abi == Abi::RustCall { - &sig.inputs()[..sig.inputs().len() - 1] + signature.push(if fn_abi.ret.is_ignore() { + None } else { - sig.inputs() - }; + Some(type_metadata(cx, fn_abi.ret.layout.ty, syntax_pos::DUMMY_SP)) + }); // Arguments types if cx.sess().target.target.options.is_like_msvc { @@ -424,7 +419,8 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`. // This transformed type is wrong, but these function types are // already inaccurate due to ABI adjustments (see #42800). - signature.extend(inputs.iter().map(|&t| { + signature.extend(fn_abi.args.iter().map(|arg| { + let t = arg.layout.ty; let t = match t.kind { ty::Array(ct, _) if (ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => { @@ -435,21 +431,11 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { Some(type_metadata(cx, t, syntax_pos::DUMMY_SP)) })); } else { - signature.extend(inputs.iter().map(|t| { - Some(type_metadata(cx, t, syntax_pos::DUMMY_SP)) + signature.extend(fn_abi.args.iter().map(|arg| { + Some(type_metadata(cx, arg.layout.ty, syntax_pos::DUMMY_SP)) })); } - if sig.abi == Abi::RustCall && !sig.inputs().is_empty() { - if let ty::Tuple(args) = sig.inputs()[sig.inputs().len() - 1].kind { - signature.extend( - args.iter().map(|argument_type| { - Some(type_metadata(cx, argument_type.expect_ty(), syntax_pos::DUMMY_SP)) - }) - ); - } - } - create_DIArray(DIB(cx), &signature[..]) } diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs index 46cdd2aaa9614..8b6fedc87db96 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/src/librustc_codegen_llvm/declare.rs @@ -18,8 +18,7 @@ use crate::attributes; use crate::context::CodegenCx; use crate::type_::Type; use crate::value::Value; -use rustc::ty::{self, PolyFnSig}; -use rustc::ty::layout::{FnAbiExt, LayoutOf}; +use rustc::ty::Ty; use rustc::session::config::Sanitizer; use rustc_data_structures::small_c_str::SmallCStr; use rustc_codegen_ssa::traits::*; @@ -94,21 +93,12 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn declare_fn( &self, name: &str, - sig: PolyFnSig<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, ) -> &'ll Value { - debug!("declare_rust_fn(name={:?}, sig={:?})", name, sig); - let sig = self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - debug!("declare_rust_fn (after region erasure) sig={:?}", sig); + debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi); - let fn_abi = FnAbi::new(self, sig, &[]); let llfn = declare_raw_fn(self, name, fn_abi.llvm_cconv(), fn_abi.llvm_type(self)); - - if self.layout_of(sig.output()).abi.is_uninhabited() { - llvm::Attribute::NoReturn.apply_llfn(Function, llfn); - } - fn_abi.apply_attrs_llfn(self, llfn); - llfn } @@ -130,28 +120,6 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn define_fn( - &self, - name: &str, - fn_sig: PolyFnSig<'tcx>, - ) -> &'ll Value { - if self.get_defined_value(name).is_some() { - self.sess().fatal(&format!("symbol `{}` already defined", name)) - } else { - self.declare_fn(name, fn_sig) - } - } - - fn define_internal_fn( - &self, - name: &str, - fn_sig: PolyFnSig<'tcx>, - ) -> &'ll Value { - let llfn = self.define_fn(name, fn_sig); - unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) }; - llfn - } - fn get_declared_value(&self, name: &str) -> Option<&'ll Value> { debug!("get_declared_value(name={:?})", name); let namebuf = SmallCStr::new(name); diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index aa55f3a19e2be..3201767c86015 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -1,4 +1,3 @@ -use crate::attributes; use crate::llvm; use crate::llvm_util; use crate::abi::{Abi, FnAbi, LlvmType, PassMode}; @@ -14,7 +13,7 @@ use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::glue; use rustc_codegen_ssa::base::{to_immediate, wants_msvc_seh, compare_simd_types}; use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive}; +use rustc::ty::layout::{self, FnAbiExt, LayoutOf, HasTyCtxt, Primitive}; use rustc::mir::interpret::GlobalId; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc::hir; @@ -1013,8 +1012,10 @@ fn gen_fn<'ll, 'tcx>( hir::Unsafety::Unsafe, Abi::Rust )); - let llfn = cx.define_internal_fn(name, rust_fn_sig); - attributes::from_fn_attrs(cx, llfn, None, rust_fn_sig); + let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]); + let llfn = cx.declare_fn(name, &fn_abi); + // FIXME(eddyb) find a nicer way to do this. + unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) }; let bx = Builder::new_block(cx, llfn, "entry-block"); codegen(bx); llfn diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs index c1703ffd0c753..cbc8af4fd2710 100644 --- a/src/librustc_codegen_llvm/mono_item.rs +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -1,3 +1,4 @@ +use crate::abi::FnAbi; use crate::attributes; use crate::base; use crate::context::CodegenCx; @@ -6,7 +7,7 @@ use crate::type_of::LayoutLlvmExt; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::mir::mono::{Linkage, Visibility}; use rustc::ty::{TypeFoldable, Instance}; -use rustc::ty::layout::{LayoutOf, HasTyCtxt}; +use rustc::ty::layout::{FnAbiExt, LayoutOf}; use rustc_codegen_ssa::traits::*; pub use rustc::mir::mono::MonoItem; @@ -42,10 +43,10 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { assert!(!instance.substs.needs_infer() && !instance.substs.has_param_types()); - let mono_sig = instance.fn_sig(self.tcx()); - let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); - let lldecl = self.declare_fn(symbol_name, mono_sig); + let fn_abi = FnAbi::of_instance(self, instance, &[]); + let lldecl = self.declare_fn(symbol_name, &fn_abi); unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) }; + let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); base::set_link_section(lldecl, &attrs); if linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR { @@ -67,16 +68,9 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - debug!("predefine_fn: mono_sig = {:?} instance = {:?}", mono_sig, instance); - if instance.def.is_inline(self.tcx) { - attributes::inline(self, lldecl, attributes::InlineAttr::Hint); - } - attributes::from_fn_attrs( - self, - lldecl, - Some(instance.def.def_id()), - mono_sig, - ); + debug!("predefine_fn: instance = {:?}", instance); + + attributes::from_fn_attrs(self, lldecl, instance, &fn_abi); self.instances.borrow_mut().insert(instance, lldecl); } diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index c21e62e7562e3..d77bbb279216a 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -235,11 +235,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx)) } ty::FnPtr(sig) => { - let sig = cx.tcx.normalize_erasing_late_bound_regions( - ty::ParamEnv::reveal_all(), - &sig, - ); - cx.fn_ptr_backend_type(&FnAbi::new(cx, sig, &[])) + cx.fn_ptr_backend_type(&FnAbi::of_fn_ptr(cx, sig, &[])) } _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO) }; diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 22693beb855d2..af340008cd9c6 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -368,13 +368,7 @@ pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( // release builds. info!("codegen_instance({})", instance); - let sig = instance.fn_sig(cx.tcx()); - let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - - let lldecl = cx.get_fn(instance); - - let mir = cx.tcx().instance_mir(instance.def); - mir::codegen_mir::(cx, lldecl, &mir, instance, sig); + mir::codegen_mir::(cx, instance); } /// Creates the `main` function which will initialize the rust runtime and call diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 14be0e80fb482..6ac26bfc68eef 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -24,28 +24,28 @@ use super::operand::OperandValue::{Pair, Ref, Immediate}; /// Used by `FunctionCx::codegen_terminator` for emitting common patterns /// e.g., creating a basic block, calling a function, etc. -struct TerminatorCodegenHelper<'a, 'tcx> { - bb: &'a mir::BasicBlock, - terminator: &'a mir::Terminator<'tcx>, +struct TerminatorCodegenHelper<'tcx> { + bb: mir::BasicBlock, + terminator: &'tcx mir::Terminator<'tcx>, funclet_bb: Option, } -impl<'a, 'tcx> TerminatorCodegenHelper<'a, 'tcx> { +impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { /// Returns the associated funclet from `FunctionCx::funclets` for the /// `funclet_bb` member if it is not `None`. - fn funclet<'c, 'b, Bx: BuilderMethods<'b, 'tcx>>( + fn funclet<'b, Bx: BuilderMethods<'a, 'tcx>>( &self, - fx: &'c mut FunctionCx<'b, 'tcx, Bx>, - ) -> Option<&'c Bx::Funclet> { + fx: &'b mut FunctionCx<'a, 'tcx, Bx>, + ) -> Option<&'b Bx::Funclet> { match self.funclet_bb { Some(funcl) => fx.funclets[funcl].as_ref(), None => None, } } - fn lltarget<'b, 'c, Bx: BuilderMethods<'b, 'tcx>>( + fn lltarget>( &self, - fx: &'c mut FunctionCx<'b, 'tcx, Bx>, + fx: &mut FunctionCx<'a, 'tcx, Bx>, target: mir::BasicBlock, ) -> (Bx::BasicBlock, bool) { let span = self.terminator.source_info.span; @@ -63,9 +63,9 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'a, 'tcx> { } /// Create a basic block. - fn llblock<'c, 'b, Bx: BuilderMethods<'b, 'tcx>>( + fn llblock>( &self, - fx: &'c mut FunctionCx<'b, 'tcx, Bx>, + fx: &mut FunctionCx<'a, 'tcx, Bx>, target: mir::BasicBlock, ) -> Bx::BasicBlock { let (lltarget, is_cleanupret) = self.lltarget(fx, target); @@ -83,9 +83,9 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'a, 'tcx> { } } - fn funclet_br<'c, 'b, Bx: BuilderMethods<'b, 'tcx>>( + fn funclet_br>( &self, - fx: &'c mut FunctionCx<'b, 'tcx, Bx>, + fx: &mut FunctionCx<'a, 'tcx, Bx>, bx: &mut Bx, target: mir::BasicBlock, ) { @@ -101,9 +101,9 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'a, 'tcx> { /// Call `fn_ptr` of `fn_abi` with the arguments `llargs`, the optional /// return destination `destination` and the cleanup function `cleanup`. - fn do_call<'c, 'b, Bx: BuilderMethods<'b, 'tcx>>( + fn do_call>( &self, - fx: &'c mut FunctionCx<'b, 'tcx, Bx>, + fx: &mut FunctionCx<'a, 'tcx, Bx>, bx: &mut Bx, fn_abi: FnAbi<'tcx, Ty<'tcx>>, fn_ptr: Bx::Value, @@ -132,7 +132,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'a, 'tcx> { } else { let llret = bx.call(fn_ptr, &llargs, self.funclet(fx)); bx.apply_attrs_callsite(&fn_abi, llret); - if fx.mir[*self.bb].is_cleanup { + if fx.mir[self.bb].is_cleanup { // Cleanup is always the cold path. Don't inline // drop glue. Also, when there is a deeply-nested // struct, there are "symmetry" issues that cause @@ -151,15 +151,15 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'a, 'tcx> { // Generate sideeffect intrinsic if jumping to any of the targets can form // a loop. - fn maybe_sideeffect<'b, 'tcx2: 'b, Bx: BuilderMethods<'b, 'tcx2>>( + fn maybe_sideeffect>( &self, - mir: &'b mir::Body<'tcx>, + mir: &'tcx mir::Body<'tcx>, bx: &mut Bx, targets: &[mir::BasicBlock], ) { if bx.tcx().sess.opts.debugging_opts.insert_sideeffect { - if targets.iter().any(|target| { - *target <= *self.bb + if targets.iter().any(|&target| { + target <= self.bb && target .start_location() .is_predecessor_of(self.bb.start_location(), mir) @@ -173,9 +173,9 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'a, 'tcx> { /// Codegen implementations for some terminator variants. impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// Generates code for a `Resume` terminator. - fn codegen_resume_terminator<'b>( + fn codegen_resume_terminator( &mut self, - helper: TerminatorCodegenHelper<'b, 'tcx>, + helper: TerminatorCodegenHelper<'tcx>, mut bx: Bx, ) { if let Some(funclet) = helper.funclet(self) { @@ -201,9 +201,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - fn codegen_switchint_terminator<'b>( + fn codegen_switchint_terminator( &mut self, - helper: TerminatorCodegenHelper<'b, 'tcx>, + helper: TerminatorCodegenHelper<'tcx>, mut bx: Bx, discr: &mir::Operand<'tcx>, switch_ty: Ty<'tcx>, @@ -316,9 +316,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } - fn codegen_drop_terminator<'b>( + fn codegen_drop_terminator( &mut self, - helper: TerminatorCodegenHelper<'b, 'tcx>, + helper: TerminatorCodegenHelper<'tcx>, mut bx: Bx, location: &mir::Place<'tcx>, target: mir::BasicBlock, @@ -345,20 +345,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &args1[..] }; let (drop_fn, fn_abi) = match ty.kind { + // FIXME(eddyb) perhaps move some of this logic into + // `Instance::resolve_drop_in_place`? ty::Dynamic(..) => { - let sig = drop_fn.fn_sig(self.cx.tcx()); - let sig = self.cx.tcx().normalize_erasing_late_bound_regions( - ty::ParamEnv::reveal_all(), - &sig, - ); - let fn_abi = FnAbi::new_vtable(&bx, sig, &[]); + let virtual_drop = Instance { + def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), + substs: drop_fn.substs, + }; + let fn_abi = FnAbi::of_instance(&bx, virtual_drop, &[]); let vtable = args[1]; args = &args[..1]; (meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_abi), fn_abi) } _ => { (bx.get_fn_addr(drop_fn), - FnAbi::of_instance(&bx, drop_fn)) + FnAbi::of_instance(&bx, drop_fn, &[])) } }; helper.maybe_sideeffect(self.mir, &mut bx, &[target]); @@ -367,9 +368,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { unwind); } - fn codegen_assert_terminator<'b>( + fn codegen_assert_terminator( &mut self, - helper: TerminatorCodegenHelper<'b, 'tcx>, + helper: TerminatorCodegenHelper<'tcx>, mut bx: Bx, terminator: &mir::Terminator<'tcx>, cond: &mir::Operand<'tcx>, @@ -439,16 +440,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Obtain the panic entry point. let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item); let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_abi = FnAbi::of_instance(&bx, instance); + let fn_abi = FnAbi::of_instance(&bx, instance, &[]); let llfn = bx.get_fn_addr(instance); // Codegen the actual panic invoke/call. helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup); } - fn codegen_call_terminator<'b>( + fn codegen_call_terminator( &mut self, - helper: TerminatorCodegenHelper<'b, 'tcx>, + helper: TerminatorCodegenHelper<'tcx>, mut bx: Bx, terminator: &mir::Terminator<'tcx>, func: &mir::Operand<'tcx>, @@ -474,12 +475,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => bug!("{} is not callable", callee.layout.ty), }; let def = instance.map(|i| i.def); + + if let Some(ty::InstanceDef::DropGlue(_, None)) = def { + // Empty drop glue; a no-op. + let &(_, target) = destination.as_ref().unwrap(); + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); + helper.funclet_br(self, &mut bx, target); + return; + } + + // FIXME(eddyb) avoid computing this if possible, when `instance` is + // available - right now `sig` is only needed for getting the `abi` + // and figuring out how many extra args were passed to a C-variadic `fn`. let sig = callee.layout.ty.fn_sig(bx.tcx()); - let sig = bx.tcx().normalize_erasing_late_bound_regions( - ty::ParamEnv::reveal_all(), - &sig, - ); - let abi = sig.abi; + let abi = sig.abi(); // Handle intrinsics old codegen wants Expr's for, ourselves. let intrinsic = match def { @@ -489,6 +498,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let intrinsic = intrinsic.as_ref().map(|s| &s[..]); + let extra_args = &args[sig.inputs().skip_binder().len()..]; + let extra_args = extra_args.iter().map(|op_arg| { + let op_ty = op_arg.ty(self.mir, bx.tcx()); + self.monomorphize(&op_ty) + }).collect::>(); + + let fn_abi = match instance { + Some(instance) => FnAbi::of_instance(&bx, instance, &extra_args), + None => FnAbi::of_fn_ptr(&bx, sig, &extra_args) + }; + if intrinsic == Some("transmute") { if let Some(destination_ref) = destination.as_ref() { let &(ref dest, target) = destination_ref; @@ -502,32 +522,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // we can do what we like. Here, we declare that transmuting // into an uninhabited type is impossible, so anything following // it must be unreachable. - assert_eq!(bx.layout_of(sig.output()).abi, layout::Abi::Uninhabited); + assert_eq!(fn_abi.ret.layout.abi, layout::Abi::Uninhabited); bx.unreachable(); } return; } - let extra_args = &args[sig.inputs().len()..]; - let extra_args = extra_args.iter().map(|op_arg| { - let op_ty = op_arg.ty(self.mir, bx.tcx()); - self.monomorphize(&op_ty) - }).collect::>(); - - let fn_abi = match def { - Some(ty::InstanceDef::Virtual(..)) => { - FnAbi::new_vtable(&bx, sig, &extra_args) - } - Some(ty::InstanceDef::DropGlue(_, None)) => { - // Empty drop glue; a no-op. - let &(_, target) = destination.as_ref().unwrap(); - helper.maybe_sideeffect(self.mir, &mut bx, &[target]); - helper.funclet_br(self, &mut bx, target); - return; - } - _ => FnAbi::new(&bx, sig, &extra_args) - }; - // This should never be reachable at runtime: // We should only emit a call to this intrinsic in #[cfg(miri)] mode, // which means that we will never actually use the generate object files @@ -556,7 +556,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let def_id = common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_abi = FnAbi::of_instance(&bx, instance); + let fn_abi = FnAbi::of_instance(&bx, instance, &[]); let llfn = bx.get_fn_addr(instance); if let Some((_, target)) = destination.as_ref() { @@ -813,14 +813,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, mut bx: Bx, bb: mir::BasicBlock, - terminator: &mir::Terminator<'tcx> + terminator: &'tcx mir::Terminator<'tcx> ) { debug!("codegen_terminator: {:?}", terminator); // Create the cleanup bundle, if needed. let funclet_bb = self.cleanup_kinds[bb].funclet_bb(bb); let helper = TerminatorCodegenHelper { - bb: &bb, terminator, funclet_bb + bb, terminator, funclet_bb }; self.set_debug_loc(&mut bx, terminator.source_info); diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index fec31f07a349b..32af151d313c0 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -1,6 +1,6 @@ use rustc::ty::{self, Ty, TypeFoldable, Instance}; use rustc::ty::layout::{TyLayout, HasTyCtxt, FnAbiExt}; -use rustc::mir::{self, Body}; +use rustc::mir; use rustc_target::abi::call::{FnAbi, PassMode}; use crate::base; use crate::traits::*; @@ -21,7 +21,7 @@ use self::operand::{OperandRef, OperandValue}; pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { instance: Instance<'tcx>, - mir: &'a mir::Body<'tcx>, + mir: &'tcx mir::Body<'tcx>, debug_context: Option>, @@ -119,18 +119,18 @@ impl<'a, 'tcx, V: CodegenObject> LocalRef<'tcx, V> { pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, - llfn: Bx::Function, - mir: &'a Body<'tcx>, instance: Instance<'tcx>, - sig: ty::FnSig<'tcx>, ) { assert!(!instance.substs.needs_infer()); - let fn_abi = FnAbi::new(cx, sig, &[]); + let llfn = cx.get_fn(instance); + + let mir = cx.tcx().instance_mir(instance.def); + + let fn_abi = FnAbi::of_instance(cx, instance, &[]); debug!("fn_abi: {:?}", fn_abi); - let debug_context = - cx.create_function_debug_context(instance, sig, llfn, mir); + let debug_context = cx.create_function_debug_context(instance, &fn_abi, llfn, mir); let mut bx = Bx::new_block(cx, llfn, "start"); @@ -247,7 +247,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } fn create_funclets<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - mir: &'a Body<'tcx>, + mir: &'tcx mir::Body<'tcx>, bx: &mut Bx, cleanup_kinds: &IndexVec, block_bxs: &IndexVec, diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/src/librustc_codegen_ssa/traits/debuginfo.rs index 802eaaa357ac0..e67201b710698 100644 --- a/src/librustc_codegen_ssa/traits/debuginfo.rs +++ b/src/librustc_codegen_ssa/traits/debuginfo.rs @@ -2,8 +2,9 @@ use super::BackendTypes; use crate::mir::debuginfo::{FunctionDebugContext, VariableKind}; use rustc::hir::def_id::CrateNum; use rustc::mir; -use rustc::ty::{self, Ty, Instance}; +use rustc::ty::{Ty, Instance}; use rustc::ty::layout::Size; +use rustc_target::abi::call::FnAbi; use syntax::ast::Name; use syntax_pos::{SourceFile, Span}; @@ -17,7 +18,7 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes { fn create_function_debug_context( &self, instance: Instance<'tcx>, - sig: ty::FnSig<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: Self::Function, mir: &mir::Body<'_>, ) -> Option>; diff --git a/src/librustc_codegen_ssa/traits/declare.rs b/src/librustc_codegen_ssa/traits/declare.rs index cd42044e48df8..1dd2c74dd4fa2 100644 --- a/src/librustc_codegen_ssa/traits/declare.rs +++ b/src/librustc_codegen_ssa/traits/declare.rs @@ -1,7 +1,8 @@ use super::BackendTypes; use rustc::hir::def_id::DefId; use rustc::mir::mono::{Linkage, Visibility}; -use rustc::ty::{self, Instance}; +use rustc::ty::{Instance, Ty}; +use rustc_target::abi::call::FnAbi; pub trait DeclareMethods<'tcx>: BackendTypes { /// Declare a global value. @@ -23,7 +24,7 @@ pub trait DeclareMethods<'tcx>: BackendTypes { /// /// If there’s a value with the same name already declared, the function will /// update the declaration and return existing Value instead. - fn declare_fn(&self, name: &str, sig: ty::PolyFnSig<'tcx>) -> Self::Function; + fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Function; /// Declare a global with an intention to define it. /// @@ -38,20 +39,6 @@ pub trait DeclareMethods<'tcx>: BackendTypes { /// Use this function when you intend to define a global without a name. fn define_private_global(&self, ty: Self::Type) -> Self::Value; - /// Declare a Rust function with an intention to define it. - /// - /// Use this function when you intend to define a function. This function will - /// return panic if the name already has a definition associated with it. This - /// can happen with #[no_mangle] or #[export_name], for example. - fn define_fn(&self, name: &str, fn_sig: ty::PolyFnSig<'tcx>) -> Self::Value; - - /// Declare a Rust function with an intention to define it. - /// - /// Use this function when you intend to define a function. This function will - /// return panic if the name already has a definition associated with it. This - /// can happen with #[no_mangle] or #[export_name], for example. - fn define_internal_fn(&self, name: &str, fn_sig: ty::PolyFnSig<'tcx>) -> Self::Value; - /// Gets declared value by name. fn get_declared_value(&self, name: &str) -> Option; diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index daa0a5e1bc4dd..eb17fc9a42f54 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -1,9 +1,10 @@ use std::borrow::Cow; -use rustc::{mir, ty}; -use rustc::ty::Instance; -use rustc::ty::layout::{self, TyLayout, LayoutOf}; +use rustc::mir; +use rustc::ty::{self, Instance, Ty}; +use rustc::ty::layout::{self, FnAbiExt, TyLayout, LayoutOf}; use syntax::source_map::Span; +use rustc_target::abi::call::FnAbi; use rustc_target::spec::abi::Abi; use super::{ @@ -60,16 +61,22 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .. } => { let func = self.eval_operand(func, None)?; - let (fn_val, abi) = match func.layout.ty.kind { + let (fn_val, abi, fn_abi) = match func.layout.ty.kind { ty::FnPtr(sig) => { let caller_abi = sig.abi(); let fn_ptr = self.read_scalar(func)?.not_undef()?; let fn_val = self.memory.get_fn(fn_ptr)?; - (fn_val, caller_abi) + // FIXME(eddyb) compute `extra_args` to pass to + // `FnAbi::of_fn_ptr` to support C variadics. + (fn_val, caller_abi, FnAbi::of_fn_ptr(self, sig, &[])) } ty::FnDef(def_id, substs) => { let sig = func.layout.ty.fn_sig(*self.tcx); - (FnVal::Instance(self.resolve(def_id, substs)?), sig.abi()) + let instance = self.resolve(def_id, substs)?; + // FIXME(eddyb) compute `extra_args` to pass to + // `FnAbi::of_instance` to support C variadics. + let fn_abi = FnAbi::of_instance(self, instance, &[]); + (FnVal::Instance(instance), sig.abi(), fn_abi) }, _ => { bug!("invalid callee of type {:?}", func.layout.ty) @@ -84,6 +91,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn_val, terminator.source_info.span, abi, + &fn_abi, &args[..], ret, *cleanup @@ -234,7 +242,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, fn_val: FnVal<'tcx, M::ExtraFnVal>, span: Span, + // FIXME(eddyb) this shouldn't be needed, its main purpose + // right now is special-casing `RustCall` and intrinsics. caller_abi: Abi, + caller_fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx, M::PointerTag>], ret: Option<(PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>, unwind: Option @@ -249,26 +260,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // ABI check + // FIXME(eddyb) check every aspect of `FnAbi` and use it below + // for adjusting various details (such as ignoring ZSTs). { - let callee_abi = { - let instance_ty = instance.ty(*self.tcx); - match instance_ty.kind { - ty::FnDef(..) => - instance_ty.fn_sig(*self.tcx).abi(), - ty::Closure(..) => Abi::RustCall, - ty::Generator(..) => Abi::Rust, - _ => bug!("unexpected callee ty: {:?}", instance_ty), - } - }; - let normalize_abi = |abi| match abi { - Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic => - // These are all the same ABI, really. - Abi::Rust, - abi => - abi, - }; - if normalize_abi(caller_abi) != normalize_abi(callee_abi) { - throw_unsup!(FunctionAbiMismatch(caller_abi, callee_abi)) + // FIXME(eddyb) compute `extra_args` to pass to + // `FnAbi::of_instance` to support C variadics. + let callee_fn_abi = FnAbi::of_instance(self, instance, &[]); + if caller_fn_abi.conv != callee_fn_abi.conv { + throw_unsup!(FunctionAbiMismatch(caller_fn_abi.conv, callee_fn_abi.conv)) } } @@ -444,7 +443,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }); trace!("Patched self operand to {:#?}", args[0]); // recurse with concrete function - self.eval_fn_call(drop_fn, span, caller_abi, &args, ret, unwind) + self.eval_fn_call(drop_fn, span, caller_abi, caller_fn_abi, &args, ret, unwind) } } } @@ -479,10 +478,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let ty = self.tcx.mk_unit(); // return type is () let dest = MPlaceTy::dangling(self.layout_of(ty)?, self); + // FIXME(eddyb) perhaps compute this more like the way it's done in + // `rustc_codegen_ssa::mir::block`? + let fn_abi = FnAbi::of_instance(self, instance, &[]); + self.eval_fn_call( FnVal::Instance(instance), span, Abi::Rust, + &fn_abi, &[arg.into()], Some((dest.into(), target)), unwind diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index a4c4c7ff616d9..1bebac321c259 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -741,23 +741,21 @@ fn visit_instance_use<'tcx>( } match instance.def { - ty::InstanceDef::Intrinsic(def_id) => { + ty::InstanceDef::Virtual(..) | + ty::InstanceDef::Intrinsic(_) => { if !is_direct_call { - bug!("intrinsic {:?} being reified", def_id); + bug!("{:?} being reified", instance); } } - ty::InstanceDef::VtableShim(..) | - ty::InstanceDef::ReifyShim(..) | - ty::InstanceDef::Virtual(..) | ty::InstanceDef::DropGlue(_, None) => { - // Don't need to emit shim if we are calling directly. + // Don't need to emit noop drop glue if we are calling directly. if !is_direct_call { output.push(create_fn_mono_item(instance)); } } - ty::InstanceDef::DropGlue(_, Some(_)) => { - output.push(create_fn_mono_item(instance)); - } + ty::InstanceDef::DropGlue(_, Some(_)) | + ty::InstanceDef::VtableShim(..) | + ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Item(..) | ty::InstanceDef::FnPtrShim(..) | diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 17f5e3d4e47a9..a2b0f85fdac1a 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -35,7 +35,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx ty::InstanceDef::VtableShim(def_id) => { build_call_shim( tcx, - def_id, + instance, Adjustment::DerefMove, CallKind::Direct(def_id), None, @@ -60,27 +60,27 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx build_call_shim( tcx, - def_id, + instance, adjustment, CallKind::Indirect, Some(arg_tys) ) } // We are generating a call back to our def-id, which the - // codegen backend knows to turn to an actual virtual call. - ty::InstanceDef::Virtual(def_id, _) | - // ...or we are generating a direct call to a function for which indirect calls must be - // codegen'd differently than direct ones (example: #[track_caller]) + // codegen backend knows to turn to an actual call, be it + // a virtual call, or a direct call to a function for which + // indirect calls must be codegen'd differently than direct ones + // (such as `#[track_caller]`). ty::InstanceDef::ReifyShim(def_id) => { build_call_shim( tcx, - def_id, + instance, Adjustment::Identity, CallKind::Direct(def_id), None ) } - ty::InstanceDef::ClosureOnceShim { call_once } => { + ty::InstanceDef::ClosureOnceShim { call_once: _ } => { let fn_mut = tcx.lang_items().fn_mut_trait().unwrap(); let call_mut = tcx .associated_items(fn_mut) @@ -89,7 +89,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx build_call_shim( tcx, - call_once, + instance, Adjustment::RefMut, CallKind::Direct(call_mut), None @@ -109,6 +109,9 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx bug!("builtin clone shim {:?} not supported", instance) } } + ty::InstanceDef::Virtual(..) => { + bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance) + } ty::InstanceDef::Intrinsic(_) => { bug!("creating shims from intrinsics ({:?}) is unsupported", instance) } @@ -689,7 +692,7 @@ impl CloneShimBuilder<'tcx> { } } -/// Builds a "call" shim for `def_id`. The shim calls the +/// Builds a "call" shim for `instance`. The shim calls the /// function specified by `call_kind`, first adjusting its first /// argument according to `rcvr_adjustment`. /// @@ -697,17 +700,30 @@ impl CloneShimBuilder<'tcx> { /// function will be untupled as these types. fn build_call_shim<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + instance: ty::InstanceDef<'tcx>, rcvr_adjustment: Adjustment, call_kind: CallKind, untuple_args: Option<&[Ty<'tcx>]>, ) -> Body<'tcx> { - debug!("build_call_shim(def_id={:?}, rcvr_adjustment={:?}, \ + debug!("build_call_shim(instance={:?}, rcvr_adjustment={:?}, \ call_kind={:?}, untuple_args={:?})", - def_id, rcvr_adjustment, call_kind, untuple_args); + instance, rcvr_adjustment, call_kind, untuple_args); + let def_id = instance.def_id(); let sig = tcx.fn_sig(def_id); - let sig = tcx.erase_late_bound_regions(&sig); + let mut sig = tcx.erase_late_bound_regions(&sig); + + // FIXME(eddyb) avoid having this snippet both here and in + // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?). + if let ty::InstanceDef::VtableShim(..) = instance { + // Modify fn(self, ...) to fn(self: *mut Self, ...) + let mut inputs_and_output = sig.inputs_and_output.to_vec(); + let self_arg = &mut inputs_and_output[0]; + debug_assert!(tcx.generics_of(def_id).has_self && *self_arg == tcx.types.self_param); + *self_arg = tcx.mk_mut_ptr(*self_arg); + sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output); + } + let span = tcx.def_span(def_id); debug!("build_call_shim: sig={:?}", sig); @@ -722,14 +738,7 @@ fn build_call_shim<'tcx>( let rcvr = match rcvr_adjustment { Adjustment::Identity => Operand::Move(rcvr_l), Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_l)), - Adjustment::DerefMove => { - // fn(Self, ...) -> fn(*mut Self, ...) - let arg_ty = local_decls[rcvr_arg].ty; - debug_assert!(tcx.generics_of(def_id).has_self && arg_ty == tcx.types.self_param); - local_decls[rcvr_arg].ty = tcx.mk_mut_ptr(arg_ty); - - Operand::Move(tcx.mk_place_deref(rcvr_l)) - } + Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_l)), Adjustment::RefMut => { // let rcvr = &mut rcvr; let ref_rcvr = local_decls.push(temp_decl( diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index aced12aa32acb..f7c55a6fcfe4c 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -2,6 +2,8 @@ use crate::abi::{self, Abi, Align, FieldPlacement, Size}; use crate::abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; use crate::spec::{self, HasTargetSpec}; +use rustc_macros::HashStable_Generic; + mod aarch64; mod amdgpu; mod arm; @@ -488,9 +490,15 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } } -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)] +#[derive(HashStable_Generic)] pub enum Conv { + // General language calling conventions, for which every target + // should have its own backend (e.g. LLVM) support. C, + Rust, + + // Target-specific calling conventions. ArmAapcs,