From c2c4dc1cbbba13acaedef625c6a5236a3d7ddb23 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 28 Oct 2019 21:16:41 +0200 Subject: [PATCH 01/24] rustc: combine Instance::fn_sig_noadjust and Instance::fn_sig. --- src/librustc/ty/instance.rs | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 777db38850fec..856be6f3c7791 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -62,12 +62,24 @@ impl<'tcx> Instance<'tcx> { ) } - fn fn_sig_noadjust(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { + pub fn fn_sig(&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::FnPtr(_) => { + let mut sig = ty.fn_sig(tcx); + if let 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); @@ -108,22 +120,8 @@ impl<'tcx> Instance<'tcx> { ) }) } - _ => 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 - }); + _ => bug!("unexpected type {:?} in Instance::fn_sig", ty) } - fn_sig } } From 61595055bfbff4b75e38d50f021f43a340c25bd3 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 28 Oct 2019 22:08:30 +0200 Subject: [PATCH 02/24] rustc_mir: don't hardcode InstanceDef::VtableShim behavior to Adjustment::DerefMove. --- src/librustc_mir/shim.rs | 42 +++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 17f5e3d4e47a9..7e9ae68c1c7ad 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,7 +60,7 @@ 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) @@ -74,13 +74,13 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx 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 @@ -689,7 +689,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 +697,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 +735,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( From 4e15e2ef098bf9d2de57031ab0febf81c6a2930a Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Oct 2019 16:24:25 +0200 Subject: [PATCH 03/24] rustc_codegen_ssa: use &'tcx mir::Body<'tcx> instead of &'a ... for the MIR body. --- src/librustc_codegen_ssa/mir/block.rs | 43 ++++++++++++++------------- src/librustc_codegen_ssa/mir/mod.rs | 8 ++--- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 14be0e80fb482..67fbe1f4b9c9f 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -24,13 +24,14 @@ 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> { +// FIXME(eddyb) clean up the lifetimes in this impl. +impl<'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>>( @@ -132,7 +133,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 +152,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<'b, Bx: BuilderMethods<'b, 'tcx>>( &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 +174,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 +202,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 +317,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, @@ -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>, @@ -446,9 +447,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 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>, @@ -813,14 +814,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..754070f5c260e 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>, @@ -120,7 +120,7 @@ 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>, + mir: &'tcx mir::Body<'tcx>, instance: Instance<'tcx>, sig: ty::FnSig<'tcx>, ) { @@ -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, From 473f908f2737fdd87e763ce2208c544f47e25fb9 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Oct 2019 16:26:25 +0200 Subject: [PATCH 04/24] rustc_codegen_ssa: make codegen_instance a simple wrapper for codegen_mir. --- src/librustc_codegen_ssa/base.rs | 8 +------- src/librustc_codegen_ssa/mir/mod.rs | 9 ++++++--- 2 files changed, 7 insertions(+), 10 deletions(-) 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/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 754070f5c260e..a4408db4777b9 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -119,13 +119,16 @@ 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: &'tcx mir::Body<'tcx>, instance: Instance<'tcx>, - sig: ty::FnSig<'tcx>, ) { assert!(!instance.substs.needs_infer()); + let llfn = cx.get_fn(instance); + + let mir = cx.tcx().instance_mir(instance.def); + + let sig = instance.fn_sig(cx.tcx()); + let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); let fn_abi = FnAbi::new(cx, sig, &[]); debug!("fn_abi: {:?}", fn_abi); From 45e7c94cc33614a9ecb5f582ed31d2734ba631dd Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Oct 2019 18:11:11 +0200 Subject: [PATCH 05/24] rustc_codegen_ssa: clean up lifetimes on TerminatorCodegenHelper's methods. --- src/librustc_codegen_ssa/mir/block.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 67fbe1f4b9c9f..411fc84213079 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -30,23 +30,22 @@ struct TerminatorCodegenHelper<'tcx> { funclet_bb: Option, } -// FIXME(eddyb) clean up the lifetimes in this impl. -impl<'tcx> TerminatorCodegenHelper<'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; @@ -64,9 +63,9 @@ impl<'tcx> TerminatorCodegenHelper<'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); @@ -84,9 +83,9 @@ impl<'tcx> TerminatorCodegenHelper<'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, ) { @@ -102,9 +101,9 @@ impl<'tcx> TerminatorCodegenHelper<'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, @@ -152,7 +151,7 @@ impl<'tcx> TerminatorCodegenHelper<'tcx> { // Generate sideeffect intrinsic if jumping to any of the targets can form // a loop. - fn maybe_sideeffect<'b, Bx: BuilderMethods<'b, 'tcx>>( + fn maybe_sideeffect>( &self, mir: &'tcx mir::Body<'tcx>, bx: &mut Bx, From 6c8fb6ea9c27e7467b5c7801460af0453bc8f6d2 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Oct 2019 18:39:54 +0200 Subject: [PATCH 06/24] rustc_codegen_ssa: remove define_fn and define_internal_fn. --- src/librustc_codegen_llvm/declare.rs | 22 ---------------------- src/librustc_codegen_llvm/intrinsic.rs | 4 +++- src/librustc_codegen_ssa/traits/declare.rs | 14 -------------- 3 files changed, 3 insertions(+), 37 deletions(-) diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs index 46cdd2aaa9614..61c1e0dffe677 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/src/librustc_codegen_llvm/declare.rs @@ -130,28 +130,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..26f3b4bbe2910 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -1013,7 +1013,9 @@ fn gen_fn<'ll, 'tcx>( hir::Unsafety::Unsafe, Abi::Rust )); - let llfn = cx.define_internal_fn(name, rust_fn_sig); + let llfn = cx.declare_fn(name, rust_fn_sig); + // FIXME(eddyb) find a nicer way to do this. + unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) }; attributes::from_fn_attrs(cx, llfn, None, rust_fn_sig); let bx = Builder::new_block(cx, llfn, "entry-block"); codegen(bx); diff --git a/src/librustc_codegen_ssa/traits/declare.rs b/src/librustc_codegen_ssa/traits/declare.rs index cd42044e48df8..e6cb82c8229f3 100644 --- a/src/librustc_codegen_ssa/traits/declare.rs +++ b/src/librustc_codegen_ssa/traits/declare.rs @@ -38,20 +38,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; From e37075312b5b52399f31265a457086bc0a36af97 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Oct 2019 18:34:50 +0200 Subject: [PATCH 07/24] rustc_codegen_ssa: take a FnAbi instead of a FnSig in declare_fn. --- src/librustc_codegen_llvm/attributes.rs | 7 +++---- src/librustc_codegen_llvm/callee.rs | 22 ++++++++++++---------- src/librustc_codegen_llvm/context.rs | 10 ++++++---- src/librustc_codegen_llvm/declare.rs | 13 +++++-------- src/librustc_codegen_llvm/intrinsic.rs | 11 +++++------ src/librustc_codegen_llvm/mono_item.rs | 16 +++++++++++----- src/librustc_codegen_ssa/traits/declare.rs | 5 +++-- 7 files changed, 45 insertions(+), 39 deletions(-) diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 6f4e7d0f0caf5..a295f2b240291 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -6,7 +6,7 @@ use rustc::hir::{CodegenFnAttrFlags, CodegenFnAttrs}; 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::TyCtxt; use rustc::ty::layout::HasTyCtxt; use rustc::ty::query::Providers; use rustc_data_structures::small_c_str::SmallCStr; @@ -203,7 +203,7 @@ pub fn from_fn_attrs( cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, id: Option, - sig: PolyFnSig<'tcx>, + abi: Abi, ) { let codegen_fn_attrs = id.map(|id| cx.tcx.codegen_fn_attrs(id)) .unwrap_or_else(|| CodegenFnAttrs::new()); @@ -276,8 +276,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 abi == Abi::Rust || abi == Abi::RustCall { // 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). diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index 08fa23f2a7c9e..b8e41b1f3dbfb 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -4,14 +4,15 @@ //! and methods are represented as just a fn ptr and not a full //! closure. +use crate::abi::FnAbi; use crate::attributes; use crate::llvm; use crate::context::CodegenCx; use crate::value::Value; use rustc_codegen_ssa::traits::*; -use rustc::ty::{TypeFoldable, Instance}; -use rustc::ty::layout::{LayoutOf, HasTyCtxt}; +use rustc::ty::{self, TypeFoldable, Instance}; +use rustc::ty::layout::{FnAbiExt, LayoutOf, 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 sig = instance.fn_sig(cx.tcx()); let sym = tcx.symbol_name(instance).name.as_str(); debug!("get_fn({:?}: {:?}) => {}", instance, sig, 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 llfn = if let Some(llfn) = cx.get_declared_value(&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)); + // 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,15 @@ pub fn get_fn( llfn } } else { - let llfn = cx.declare_fn(&sym, sig); - assert_eq!(cx.val_ty(llfn), llptrty); + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let fn_abi = FnAbi::new(cx, sig, &[]); + 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, Some(instance.def.def_id()), sig.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..89e3195342ce8 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; @@ -412,15 +413,16 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { return llfn; } - let sig = ty::Binder::bind(tcx.mk_fn_sig( + let sig = tcx.mk_fn_sig( iter::once(tcx.mk_mut_ptr(tcx.types.u8)), tcx.types.never, false, hir::Unsafety::Unsafe, Abi::C - )); + ); - let llfn = self.declare_fn("rust_eh_unwind_resume", sig); + let fn_abi = FnAbi::new(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/declare.rs b/src/librustc_codegen_llvm/declare.rs index 61c1e0dffe677..772377617e2e1 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,16 +93,14 @@ 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() { + // FIXME(eddyb) move into `FnAbi::apply_attrs_llfn`. + if fn_abi.ret.layout.abi.is_uninhabited() { llvm::Attribute::NoReturn.apply_llfn(Function, llfn); } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 26f3b4bbe2910..999fc857c15a2 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; @@ -1006,17 +1005,17 @@ fn gen_fn<'ll, 'tcx>( output: Ty<'tcx>, codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>), ) -> &'ll Value { - let rust_fn_sig = ty::Binder::bind(cx.tcx.mk_fn_sig( + let rust_fn_sig = cx.tcx.mk_fn_sig( inputs.into_iter(), output, false, hir::Unsafety::Unsafe, Abi::Rust - )); - let llfn = cx.declare_fn(name, rust_fn_sig); + ); + let fn_abi = FnAbi::new(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) }; - attributes::from_fn_attrs(cx, llfn, None, rust_fn_sig); 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..f9df0a00475d0 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; @@ -5,8 +6,8 @@ use crate::llvm; 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::{self, TypeFoldable, Instance}; +use rustc::ty::layout::{FnAbiExt, LayoutOf, HasTyCtxt}; use rustc_codegen_ssa::traits::*; pub use rustc::mir::mono::MonoItem; @@ -43,9 +44,14 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { !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 mono_sig = self.tcx().normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &mono_sig, + ); + let fn_abi = FnAbi::new(self, mono_sig, &[]); + 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 { @@ -75,7 +81,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { self, lldecl, Some(instance.def.def_id()), - mono_sig, + mono_sig.abi, ); self.instances.borrow_mut().insert(instance, lldecl); diff --git a/src/librustc_codegen_ssa/traits/declare.rs b/src/librustc_codegen_ssa/traits/declare.rs index e6cb82c8229f3..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. /// From 6de254d6f76d9b5959c8b5b681378d5463ed3d05 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Oct 2019 19:46:18 +0200 Subject: [PATCH 08/24] rustc_codegen_llvm: move NoReturn attribute to apply_attrs_llfn. --- src/librustc_codegen_llvm/abi.rs | 5 +++++ src/librustc_codegen_llvm/declare.rs | 7 ------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 804a7af41f39a..4ad58b9a9f7a6 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -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/declare.rs b/src/librustc_codegen_llvm/declare.rs index 772377617e2e1..8b6fedc87db96 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/src/librustc_codegen_llvm/declare.rs @@ -98,14 +98,7 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi); let llfn = declare_raw_fn(self, name, fn_abi.llvm_cconv(), fn_abi.llvm_type(self)); - - // FIXME(eddyb) move into `FnAbi::apply_attrs_llfn`. - if fn_abi.ret.layout.abi.is_uninhabited() { - llvm::Attribute::NoReturn.apply_llfn(Function, llfn); - } - fn_abi.apply_attrs_llfn(self, llfn); - llfn } From d57c15fda95f0a3bb898e307643c92aa173ec74a Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Oct 2019 20:01:31 +0200 Subject: [PATCH 09/24] rustc_codegen_ssa: use FnAbi::of_instance wherever possible. --- src/librustc_codegen_llvm/callee.rs | 23 ++++++++++---------- src/librustc_codegen_llvm/debuginfo/mod.rs | 13 ++++++++--- src/librustc_codegen_llvm/mono_item.rs | 16 ++++++-------- src/librustc_codegen_ssa/mir/mod.rs | 7 ++---- src/librustc_codegen_ssa/traits/debuginfo.rs | 5 +++-- 5 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index b8e41b1f3dbfb..b6a3bf2f8789e 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -4,15 +4,15 @@ //! and methods are represented as just a fn ptr and not a full //! closure. -use crate::abi::FnAbi; +use crate::abi::{FnAbi, FnAbiLlvmExt}; use crate::attributes; use crate::llvm; use crate::context::CodegenCx; use crate::value::Value; use rustc_codegen_ssa::traits::*; -use rustc::ty::{self, TypeFoldable, Instance}; -use rustc::ty::layout::{FnAbiExt, LayoutOf, HasTyCtxt}; +use rustc::ty::{TypeFoldable, Instance}; +use rustc::ty::layout::{FnAbiExt, HasTyCtxt}; /// Codegens a reference to a fn/method item, monomorphizing and /// inlining as it goes. @@ -37,14 +37,14 @@ pub fn get_fn( return llfn; } - let sig = instance.fn_sig(cx.tcx()); let sym = tcx.symbol_name(instance).name.as_str(); - debug!("get_fn({:?}: {:?}) => {}", instance, sig, sym); + debug!("get_fn({:?}: {:?}) => {}", instance, instance.ty(cx.tcx()), sym); + + 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 substituted signature. - let fn_ptr_ty = tcx.mk_fn_ptr(sig); - let llptrty = cx.backend_type(cx.layout_of(fn_ptr_ty)); + // 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 @@ -77,15 +77,16 @@ pub fn get_fn( llfn } } else { - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - let fn_abi = FnAbi::new(cx, sig, &[]); 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.abi); + // FIXME(eddyb) avoid this `Instance::fn_sig` call. + // Perhaps store the relevant information in `FnAbi`? + let sig_abi = instance.fn_sig(cx.tcx()).abi(); + attributes::from_fn_attrs(cx, llfn, Some(instance.def.def_id()), sig_abi); let instance_def_id = instance.def_id(); diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 7713fe47004b9..f8aeaa20475d1 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::{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,6 +308,12 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let file_metadata = file_metadata(self, &loc.file.name, def_id.krate); let function_type_metadata = unsafe { + // FIXME(eddyb) avoid this `Instance::fn_sig` call, by + // rewriting `get_function_signature` to use `fn_abi` instead. + let sig = self.tcx().normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &instance.fn_sig(self.tcx()), + ); let fn_signature = get_function_signature(self, sig); llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), file_metadata, fn_signature) }; @@ -338,7 +344,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; } @@ -390,6 +396,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { return Some(fn_debug_context); + // FIXME(eddyb) rewrite this to be based on `FnAbi` instead of `FnSig`. fn get_function_signature<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, sig: ty::FnSig<'tcx>, diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs index f9df0a00475d0..3d2f6efb072ee 100644 --- a/src/librustc_codegen_llvm/mono_item.rs +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -6,7 +6,7 @@ use crate::llvm; use crate::type_of::LayoutLlvmExt; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::mir::mono::{Linkage, Visibility}; -use rustc::ty::{self, TypeFoldable, Instance}; +use rustc::ty::{TypeFoldable, Instance}; use rustc::ty::layout::{FnAbiExt, LayoutOf, HasTyCtxt}; use rustc_codegen_ssa::traits::*; @@ -43,12 +43,7 @@ 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 mono_sig = self.tcx().normalize_erasing_late_bound_regions( - ty::ParamEnv::reveal_all(), - &mono_sig, - ); - let fn_abi = FnAbi::new(self, 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()); @@ -73,15 +68,18 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - debug!("predefine_fn: mono_sig = {:?} instance = {:?}", mono_sig, instance); + debug!("predefine_fn: instance = {:?}", instance); if instance.def.is_inline(self.tcx) { attributes::inline(self, lldecl, attributes::InlineAttr::Hint); } + // FIXME(eddyb) avoid this `Instance::fn_sig` call. + // Perhaps store the relevant information in `FnAbi`? + let mono_sig_abi = instance.fn_sig(self.tcx()).abi(); attributes::from_fn_attrs( self, lldecl, Some(instance.def.def_id()), - mono_sig.abi, + mono_sig_abi, ); self.instances.borrow_mut().insert(instance, lldecl); diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index a4408db4777b9..30c3d73434389 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -127,13 +127,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mir = cx.tcx().instance_mir(instance.def); - let sig = instance.fn_sig(cx.tcx()); - let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - let fn_abi = FnAbi::new(cx, sig, &[]); + 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"); 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>; From 6862a84835798711610591a9bfd7abe4b6b12283 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Oct 2019 20:56:21 +0200 Subject: [PATCH 10/24] rustc: use ReifyShim for reifying Virtual call instances. --- src/librustc/ty/instance.rs | 32 ++++++++++++++-------- src/librustc_mir/monomorphize/collector.rs | 16 +++++------ src/librustc_mir/shim.rs | 11 +++++--- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 856be6f3c7791..06fc168bd5740 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -29,10 +29,15 @@ 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_*` @@ -194,7 +199,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) @@ -309,20 +314,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_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 7e9ae68c1c7ad..a2b0f85fdac1a 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -67,10 +67,10 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx ) } // 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, @@ -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) } From 880f9058d2b30dd4f32b9a1b86499a258ee4e188 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Oct 2019 21:46:25 +0200 Subject: [PATCH 11/24] rustc: compute FnAbi's for virtual calls through FnAbi::of_instance. --- src/librustc/ty/layout.rs | 20 +++++------ src/librustc_codegen_llvm/callee.rs | 2 +- src/librustc_codegen_llvm/mono_item.rs | 2 +- src/librustc_codegen_ssa/mir/block.rs | 46 ++++++++++++++------------ src/librustc_codegen_ssa/mir/mod.rs | 2 +- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index b6050a5caf13e..b53a1e0f8e52c 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2347,9 +2347,8 @@ 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; + fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; fn new_internal( cx: &C, sig: ty::FnSig<'tcx>, @@ -2367,25 +2366,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 { + call::FnAbi::new_internal(cx, sig, extra_args, |ty, _| ArgAbi::new(cx.layout_of(ty))) + } + + fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'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 { - 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| { + 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 diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index b6a3bf2f8789e..74f4970333c86 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -40,7 +40,7 @@ pub fn get_fn( let sym = tcx.symbol_name(instance).name.as_str(); debug!("get_fn({:?}: {:?}) => {}", instance, instance.ty(cx.tcx()), sym); - let fn_abi = FnAbi::of_instance(cx, instance); + 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. diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs index 3d2f6efb072ee..75a4a96669483 100644 --- a/src/librustc_codegen_llvm/mono_item.rs +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -43,7 +43,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { assert!(!instance.substs.needs_infer() && !instance.substs.has_param_types()); - let fn_abi = FnAbi::of_instance(self, instance); + 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()); diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 411fc84213079..9555bce4c21ad 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -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]); @@ -439,7 +440,7 @@ 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. @@ -474,6 +475,18 @@ 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(), @@ -514,18 +527,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 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) + let fn_abi = match instance { + Some(instance) => FnAbi::of_instance(&bx, instance, &extra_args), + None => FnAbi::new(&bx, sig, &extra_args) }; // This should never be reachable at runtime: @@ -556,7 +560,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() { diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 30c3d73434389..32af151d313c0 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -127,7 +127,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mir = cx.tcx().instance_mir(instance.def); - let fn_abi = FnAbi::of_instance(cx, instance); + let fn_abi = FnAbi::of_instance(cx, instance, &[]); debug!("fn_abi: {:?}", fn_abi); let debug_context = cx.create_function_debug_context(instance, &fn_abi, llfn, mir); From 49bed20fafdab24c1d29340049065859dcc86221 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Oct 2019 21:57:45 +0200 Subject: [PATCH 12/24] rustc: rename FnAbi::new to FnAbi::of_fn_ptr. --- src/librustc/ty/layout.rs | 4 ++-- src/librustc_codegen_llvm/context.rs | 2 +- src/librustc_codegen_llvm/intrinsic.rs | 2 +- src/librustc_codegen_llvm/type_of.rs | 2 +- src/librustc_codegen_ssa/mir/block.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index b53a1e0f8e52c..301f7d0147896 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2347,7 +2347,7 @@ where + HasTyCtxt<'tcx> + HasParamEnv<'tcx>, { - fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; + fn of_fn_ptr(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; fn new_internal( cx: &C, @@ -2366,7 +2366,7 @@ where + HasTyCtxt<'tcx> + HasParamEnv<'tcx>, { - fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { + fn of_fn_ptr(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { call::FnAbi::new_internal(cx, sig, extra_args, |ty, _| ArgAbi::new(cx.layout_of(ty))) } diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 89e3195342ce8..223aa7595d8fe 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -421,7 +421,7 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { Abi::C ); - let fn_abi = FnAbi::new(self, 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)); diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 999fc857c15a2..c26b1ed8793cc 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -1012,7 +1012,7 @@ fn gen_fn<'ll, 'tcx>( hir::Unsafety::Unsafe, Abi::Rust ); - let fn_abi = FnAbi::new(cx, 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) }; diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index c21e62e7562e3..aa060e474fa5b 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -239,7 +239,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { 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/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 9555bce4c21ad..b077d2b1b470b 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -529,7 +529,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let fn_abi = match instance { Some(instance) => FnAbi::of_instance(&bx, instance, &extra_args), - None => FnAbi::new(&bx, sig, &extra_args) + None => FnAbi::of_fn_ptr(&bx, sig, &extra_args) }; // This should never be reachable at runtime: From 0e70c4d0558c3d573bd0500ebebbce8cc13cf860 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Oct 2019 22:08:50 +0200 Subject: [PATCH 13/24] rustc: take a PolyFnSig instead of an FnSig in FnAbi::of_fn_ptr. --- src/librustc/ty/layout.rs | 15 +++++++------ src/librustc_codegen_llvm/context.rs | 4 ++-- src/librustc_codegen_llvm/intrinsic.rs | 4 ++-- src/librustc_codegen_llvm/type_of.rs | 4 ---- src/librustc_codegen_ssa/mir/block.rs | 30 +++++++++++--------------- 5 files changed, 25 insertions(+), 32 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 301f7d0147896..f3419b309095b 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2347,11 +2347,11 @@ where + HasTyCtxt<'tcx> + HasParamEnv<'tcx>, { - fn of_fn_ptr(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; 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; @@ -2366,15 +2366,12 @@ where + HasTyCtxt<'tcx> + HasParamEnv<'tcx>, { - fn of_fn_ptr(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 of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'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_internal(cx, sig, extra_args, |ty, arg_idx| { let mut layout = cx.layout_of(ty); @@ -2432,12 +2429,16 @@ 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, diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 223aa7595d8fe..39ea1f6f5dccf 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -413,13 +413,13 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { return llfn; } - let sig = tcx.mk_fn_sig( + let sig = ty::Binder::bind(tcx.mk_fn_sig( iter::once(tcx.mk_mut_ptr(tcx.types.u8)), tcx.types.never, false, hir::Unsafety::Unsafe, Abi::C - ); + )); let fn_abi = FnAbi::of_fn_ptr(self, sig, &[]); let llfn = self.declare_fn("rust_eh_unwind_resume", &fn_abi); diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index c26b1ed8793cc..3201767c86015 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -1005,13 +1005,13 @@ fn gen_fn<'ll, 'tcx>( output: Ty<'tcx>, codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>), ) -> &'ll Value { - let rust_fn_sig = cx.tcx.mk_fn_sig( + let rust_fn_sig = ty::Binder::bind(cx.tcx.mk_fn_sig( inputs.into_iter(), output, false, hir::Unsafety::Unsafe, Abi::Rust - ); + )); 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. diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index aa060e474fa5b..d77bbb279216a 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -235,10 +235,6 @@ 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::of_fn_ptr(cx, sig, &[])) } _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO) diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index b077d2b1b470b..6ac26bfc68eef 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -488,11 +488,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // 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 { @@ -502,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; @@ -515,23 +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 instance { - Some(instance) => FnAbi::of_instance(&bx, instance, &extra_args), - None => FnAbi::of_fn_ptr(&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 From 8be241f101156d879504d4e8c908fe5d3e66601f Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Oct 2019 20:01:31 +0200 Subject: [PATCH 14/24] rustc_codegen_llvm: rewrite debuginfo::get_function_signature to use FnAbi. --- src/librustc_codegen_llvm/debuginfo/mod.rs | 45 ++++++---------------- 1 file changed, 12 insertions(+), 33 deletions(-) diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index f8aeaa20475d1..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, FnAbi}; +use crate::abi::FnAbi; use crate::common::CodegenCx; use crate::builder::Builder; use crate::value::Value; @@ -308,13 +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 { - // FIXME(eddyb) avoid this `Instance::fn_sig` call, by - // rewriting `get_function_signature` to use `fn_abi` instead. - let sig = self.tcx().normalize_erasing_late_bound_regions( - ty::ParamEnv::reveal_all(), - &instance.fn_sig(self.tcx()), - ); - 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) }; @@ -396,28 +390,22 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { return Some(fn_debug_context); - // FIXME(eddyb) rewrite this to be based on `FnAbi` instead of `FnSig`. 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 { @@ -431,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() => { @@ -442,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[..]) } From 30edd332d158b937cf1d20ec01023cd7c27f292a Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 27 Nov 2019 12:53:19 +0200 Subject: [PATCH 15/24] rustc_codegen_llvm: take an Instance in attributes::from_fn_attrs. --- src/librustc_codegen_llvm/attributes.rs | 36 ++++++++++++++----------- src/librustc_codegen_llvm/callee.rs | 8 +----- src/librustc_codegen_llvm/mono_item.rs | 16 +++-------- 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index a295f2b240291..cee2e56ef7590 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -2,11 +2,11 @@ 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::TyCtxt; +use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::HasTyCtxt; use rustc::ty::query::Providers; use rustc_data_structures::small_c_str::SmallCStr; @@ -202,11 +202,9 @@ 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, - abi: Abi, + instance: ty::Instance<'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 +222,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,6 +279,9 @@ pub fn from_fn_attrs( // Special attribute for allocator functions, which can't unwind. false } else { + // FIXME(eddyb) avoid this `Instance::fn_sig` call. + // Perhaps store the relevant information in `FnAbi`? + let abi = instance.fn_sig(cx.tcx()).abi(); if abi == Abi::Rust || abi == Abi::RustCall { // Any Rust method (or `extern "Rust" fn` or `extern // "rust-call" fn`) is explicitly allowed to unwind @@ -330,16 +336,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 74f4970333c86..727cbbb8c1433 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -80,13 +80,7 @@ pub fn get_fn( 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); - } - // FIXME(eddyb) avoid this `Instance::fn_sig` call. - // Perhaps store the relevant information in `FnAbi`? - let sig_abi = instance.fn_sig(cx.tcx()).abi(); - attributes::from_fn_attrs(cx, llfn, Some(instance.def.def_id()), sig_abi); + attributes::from_fn_attrs(cx, llfn, instance); let instance_def_id = instance.def_id(); diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs index 75a4a96669483..2270b59b6822c 100644 --- a/src/librustc_codegen_llvm/mono_item.rs +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -7,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::{FnAbiExt, LayoutOf, HasTyCtxt}; +use rustc::ty::layout::{FnAbiExt, LayoutOf}; use rustc_codegen_ssa::traits::*; pub use rustc::mir::mono::MonoItem; @@ -69,18 +69,8 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { } debug!("predefine_fn: instance = {:?}", instance); - if instance.def.is_inline(self.tcx) { - attributes::inline(self, lldecl, attributes::InlineAttr::Hint); - } - // FIXME(eddyb) avoid this `Instance::fn_sig` call. - // Perhaps store the relevant information in `FnAbi`? - let mono_sig_abi = instance.fn_sig(self.tcx()).abi(); - attributes::from_fn_attrs( - self, - lldecl, - Some(instance.def.def_id()), - mono_sig_abi, - ); + + attributes::from_fn_attrs(self, lldecl, instance); self.instances.borrow_mut().insert(instance, lldecl); } From 5bdcde20fc1f581341e689e9fe1cd6c422ffd4d5 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 27 Nov 2019 12:55:33 +0200 Subject: [PATCH 16/24] rustc_codegen_llvm: privatize as much of attributes::* as possible. --- src/librustc_codegen_llvm/attributes.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index cee2e56ef7590..22ff0379624dc 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -26,7 +26,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 +58,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 +72,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 +88,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 { From 41407204bd8d19c5524d1916e54d743da335cfc0 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 27 Nov 2019 13:23:30 +0200 Subject: [PATCH 17/24] rustc_target: add abi::call::Conv::Rust distinct from Conv::C. --- src/librustc/ty/layout.rs | 2 +- src/librustc_codegen_llvm/abi.rs | 2 +- src/librustc_codegen_llvm/attributes.rs | 11 +++++------ src/librustc_codegen_llvm/callee.rs | 2 +- src/librustc_codegen_llvm/mono_item.rs | 2 +- src/librustc_target/abi/call/mod.rs | 5 +++++ 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index f3419b309095b..16f9a1deef539 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2441,7 +2441,7 @@ where 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 4ad58b9a9f7a6..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, diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 22ff0379624dc..33dc2513de584 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -6,15 +6,16 @@ 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}; +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; @@ -203,6 +204,7 @@ pub fn from_fn_attrs( cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, ) { let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); @@ -279,10 +281,7 @@ pub fn from_fn_attrs( // Special attribute for allocator functions, which can't unwind. false } else { - // FIXME(eddyb) avoid this `Instance::fn_sig` call. - // Perhaps store the relevant information in `FnAbi`? - let abi = instance.fn_sig(cx.tcx()).abi(); - if abi == Abi::Rust || 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). diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index 727cbbb8c1433..e0db7cae99e1a 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -80,7 +80,7 @@ pub fn get_fn( let llfn = cx.declare_fn(&sym, &fn_abi); debug!("get_fn: not casting pointer!"); - attributes::from_fn_attrs(cx, llfn, instance); + attributes::from_fn_attrs(cx, llfn, instance, &fn_abi); let instance_def_id = instance.def_id(); diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs index 2270b59b6822c..cbc8af4fd2710 100644 --- a/src/librustc_codegen_llvm/mono_item.rs +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -70,7 +70,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { debug!("predefine_fn: instance = {:?}", instance); - attributes::from_fn_attrs(self, lldecl, instance); + attributes::from_fn_attrs(self, lldecl, instance, &fn_abi); self.instances.borrow_mut().insert(instance, lldecl); } diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index aced12aa32acb..30adaa99b1f9d 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -490,7 +490,12 @@ impl<'a, Ty> ArgAbi<'a, Ty> { #[derive(Copy, Clone, PartialEq, Debug)] 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, From 3315d70dfbbc69a49d84005eefc7965aab801a8c Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 27 Nov 2019 13:44:20 +0200 Subject: [PATCH 18/24] rustc: move Instance::fn_sig to ty::layout and privatize it. --- src/librustc/ty/instance.rs | 66 +--------------------------------- src/librustc/ty/layout.rs | 72 ++++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 66 deletions(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 06fc168bd5740..f270d3d3a2a59 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)] @@ -66,68 +64,6 @@ impl<'tcx> Instance<'tcx> { &ty, ) } - - pub fn fn_sig(&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(_) => { - let mut sig = ty.fn_sig(tcx); - if let 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, - Unsafety::Normal, - Abi::Rust - ) - }) - } - _ => bug!("unexpected type {:?} in Instance::fn_sig", ty) - } - } } impl<'tcx> InstanceDef<'tcx> { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 16f9a1deef539..b50392d063cb9 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>> @@ -2371,7 +2441,7 @@ where } fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { - let sig = instance.fn_sig(cx.tcx()); + 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); From 0232114848ed87dfcda67695a644a1d455e2d9e6 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 27 Nov 2019 13:59:59 +0200 Subject: [PATCH 19/24] rustc: add docs to FnAbi::{of_fn_ptr,of_instance} and InstanceDef::Virtual. --- src/librustc/ty/instance.rs | 6 +++++- src/librustc/ty/layout.rs | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index f270d3d3a2a59..801dfa81ef178 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -42,7 +42,11 @@ pub enum InstanceDef<'tcx> { /// `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` diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index b50392d063cb9..0a1480664639f 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2417,8 +2417,19 @@ where + HasTyCtxt<'tcx> + HasParamEnv<'tcx>, { + /// 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::PolyFnSig<'tcx>, From 3e7a5a4e0bdf13f504922c9e9b5c539cd57b576f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Nov 2019 23:19:03 +0100 Subject: [PATCH 20/24] handle diverging functions forwarding their return place --- src/librustc_mir/interpret/place.rs | 31 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 5b263f7680131..c03d1da677758 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -651,20 +651,21 @@ where use rustc::mir::PlaceBase; let mut place_ty = match &place.base { - PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place { - Some(return_place) => { - // We use our layout to verify our assumption; caller will validate - // their layout on return. - PlaceTy { - place: *return_place, - layout: self.layout_of( - self.subst_from_frame_and_normalize_erasing_regions( - self.frame().body.return_ty() - ) - )?, - } + PlaceBase::Local(mir::RETURN_PLACE) => { + // `return_place` has the *caller* layout, but we want to use our + // `layout to verify our assumption. The caller will validate + // their layout on return. + PlaceTy { + place: match self.frame().return_place { + Some(p) => *p, + None => Place::null(&*self), + }, + layout: self.layout_of( + self.subst_from_frame_and_normalize_erasing_regions( + self.frame().body.return_ty() + ) + )?, } - None => throw_unsup!(InvalidNullPointerUsage), }, PlaceBase::Local(local) => PlaceTy { // This works even for dead/uninitialized locals; we check further when writing @@ -791,8 +792,8 @@ where // to handle padding properly, which is only correct if we never look at this data with the // wrong type. - let ptr = match self.check_mplace_access(dest, None) - .expect("places should be checked on creation") + // Invalid places are a thing: the return place of a diverging function + let ptr = match self.check_mplace_access(dest, None)? { Some(ptr) => ptr, None => return Ok(()), // zero-sized access From 2869abacfa12ce3946234e5554d160fc932d933d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Nov 2019 23:36:39 +0100 Subject: [PATCH 21/24] comment --- src/librustc_mir/interpret/place.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index c03d1da677758..70d9836b6ff0f 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -658,6 +658,13 @@ where PlaceTy { place: match self.frame().return_place { Some(p) => *p, + // Even if we don't have a return place, we sometimes need to + // create this place, but any attempt to read from / write to it + // (even a ZST read/write) needs to error, so let us make this + // a NULL place. + // + // FIXME: Ideally we'd make sure that the place projections also + // bail out. None => Place::null(&*self), }, layout: self.layout_of( From a9dca3b243022a320b53543a975ff4774986ba5f Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Thu, 28 Nov 2019 10:11:48 +0000 Subject: [PATCH 22/24] rustbuild: fix cross-compile install although, not sure why this works - it wasn't needed before --- src/bootstrap/install.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 384219c38fd04..f8734ebdf4254 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -260,7 +260,7 @@ install!((self, builder, _config), }; Rustc, "src/librustc", true, only_hosts: true, { builder.ensure(dist::Rustc { - compiler: self.compiler, + compiler: builder.compiler(builder.top_stage, self.target), }); install_rustc(builder, self.compiler.stage, self.target); }; From 0533249fd7950a34a8046956c5bb1737e620198f Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Thu, 28 Nov 2019 10:11:02 +0000 Subject: [PATCH 23/24] rustbuild: don't clobber RUSTFLAGS, append to it --- src/bootstrap/bootstrap.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 730e8cf05d41d..bb169414886de 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -643,7 +643,9 @@ def build_bootstrap(self): env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ (os.pathsep + env["LIBRARY_PATH"]) \ if "LIBRARY_PATH" in env else "" - env["RUSTFLAGS"] = "-Cdebuginfo=2 " + # preserve existing RUSTFLAGS + env.setdefault("RUSTFLAGS", "") + env["RUSTFLAGS"] += " -Cdebuginfo=2" build_section = "target.{}".format(self.build_triple()) target_features = [] @@ -652,13 +654,13 @@ def build_bootstrap(self): elif self.get_toml("crt-static", build_section) == "false": target_features += ["-crt-static"] if target_features: - env["RUSTFLAGS"] += "-C target-feature=" + (",".join(target_features)) + " " + env["RUSTFLAGS"] += " -C target-feature=" + (",".join(target_features)) target_linker = self.get_toml("linker", build_section) if target_linker is not None: - env["RUSTFLAGS"] += "-C linker=" + target_linker + " " - env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes " + env["RUSTFLAGS"] += " -C linker=" + target_linker + env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes" if self.get_toml("deny-warnings", "rust") != "false": - env["RUSTFLAGS"] += "-Dwarnings " + env["RUSTFLAGS"] += " -Dwarnings" env["PATH"] = os.path.join(self.bin_root(), "bin") + \ os.pathsep + env["PATH"] From c703ff26555bc25739384b2104dfb538ec7435c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 22 Oct 2019 00:00:00 +0000 Subject: [PATCH 24/24] Conditional compilation for sanitizers Configure sanitize option when compiling with a sanitizer to make it possible to execute different code depending on whether given sanitizer is enabled or not. --- .../src/language-features/cfg-sanitize.md | 36 +++++++++++++++++++ src/librustc/session/config.rs | 15 ++++++++ src/librustc_feature/active.rs | 3 ++ src/librustc_feature/builtin_attrs.rs | 1 + src/libsyntax_pos/symbol.rs | 2 ++ .../feature-gate-cfg_sanitize.rs | 3 ++ .../feature-gate-cfg_sanitize.stderr | 12 +++++++ src/test/ui/sanitize-cfg.rs | 26 ++++++++++++++ 8 files changed, 98 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/cfg-sanitize.md create mode 100644 src/test/ui/feature-gates/feature-gate-cfg_sanitize.rs create mode 100644 src/test/ui/feature-gates/feature-gate-cfg_sanitize.stderr create mode 100644 src/test/ui/sanitize-cfg.rs diff --git a/src/doc/unstable-book/src/language-features/cfg-sanitize.md b/src/doc/unstable-book/src/language-features/cfg-sanitize.md new file mode 100644 index 0000000000000..949f24ab9c11e --- /dev/null +++ b/src/doc/unstable-book/src/language-features/cfg-sanitize.md @@ -0,0 +1,36 @@ +# `cfg_sanitize` + +The tracking issue for this feature is: [#39699] + +[#39699]: https://github.com/rust-lang/rust/issues/39699 + +------------------------ + +The `cfg_sanitize` feature makes it possible to execute different code +depending on whether a particular sanitizer is enabled or not. + +## Examples + +``` rust +#![feature(cfg_sanitize)] + +#[cfg(sanitize = "thread")] +fn a() { + // ... +} + +#[cfg(not(sanitize = "thread"))] +fn a() { + // ... +} + +fn b() { + if cfg!(sanitize = "leak") { + // ... + } else { + // ... + } +} + +``` + diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index fbfae721bbe91..245a4ac86cd1e 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -47,6 +47,17 @@ pub enum Sanitizer { Thread, } +impl fmt::Display for Sanitizer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Sanitizer::Address => "address".fmt(f), + Sanitizer::Leak => "leak".fmt(f), + Sanitizer::Memory => "memory".fmt(f), + Sanitizer::Thread => "thread".fmt(f), + } + } +} + impl FromStr for Sanitizer { type Err = (); fn from_str(s: &str) -> Result { @@ -1582,6 +1593,10 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { } } } + if let Some(s) = &sess.opts.debugging_opts.sanitizer { + let symbol = Symbol::intern(&s.to_string()); + ret.insert((sym::sanitize, Some(symbol))); + } if sess.opts.debug_assertions { ret.insert((Symbol::intern("debug_assertions"), None)); } diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 7c0d39965fc00..16d8ada9f24c0 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -524,6 +524,9 @@ declare_features! ( /// Allows the use of `if` and `match` in constants. (active, const_if_match, "1.41.0", Some(49146), None), + /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. + (active, cfg_sanitize, "1.41.0", Some(39699), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs index f72df00a8e821..fa8e3e189edef 100644 --- a/src/librustc_feature/builtin_attrs.rs +++ b/src/librustc_feature/builtin_attrs.rs @@ -25,6 +25,7 @@ const GATED_CFGS: &[GatedCfg] = &[ (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), + (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), ]; /// Find a gated cfg determined by the `pred`icate which is given the cfg's name. diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 7d43c3c8d076e..3059b05969106 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -177,6 +177,7 @@ symbols! { cfg_attr, cfg_attr_multi, cfg_doctest, + cfg_sanitize, cfg_target_feature, cfg_target_has_atomic, cfg_target_thread_local, @@ -634,6 +635,7 @@ symbols! { rust_eh_unwind_resume, rust_oom, rvalue_static_promotion, + sanitize, sanitizer_runtime, _Self, self_in_typedefs, diff --git a/src/test/ui/feature-gates/feature-gate-cfg_sanitize.rs b/src/test/ui/feature-gates/feature-gate-cfg_sanitize.rs new file mode 100644 index 0000000000000..c3e7cc9ed8a9b --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg_sanitize.rs @@ -0,0 +1,3 @@ +#[cfg(not(sanitize = "thread"))] +//~^ `cfg(sanitize)` is experimental +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-cfg_sanitize.stderr b/src/test/ui/feature-gates/feature-gate-cfg_sanitize.stderr new file mode 100644 index 0000000000000..f67a0d83bdd3a --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg_sanitize.stderr @@ -0,0 +1,12 @@ +error[E0658]: `cfg(sanitize)` is experimental and subject to change + --> $DIR/feature-gate-cfg_sanitize.rs:1:11 + | +LL | #[cfg(not(sanitize = "thread"))] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/39699 + = help: add `#![feature(cfg_sanitize)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/sanitize-cfg.rs b/src/test/ui/sanitize-cfg.rs new file mode 100644 index 0000000000000..9c198543a8664 --- /dev/null +++ b/src/test/ui/sanitize-cfg.rs @@ -0,0 +1,26 @@ +// Verifies that when compiling with -Zsanitizer=option, +// the `#[cfg(sanitize = "option")]` attribute is configured. + +// needs-sanitizer-support +// only-linux +// only-x86_64 +// check-pass +// revisions: address leak memory thread +//[address]compile-flags: -Zsanitizer=address --cfg address +//[leak]compile-flags: -Zsanitizer=leak --cfg leak +//[memory]compile-flags: -Zsanitizer=memory --cfg memory +//[thread]compile-flags: -Zsanitizer=thread --cfg thread + +#![feature(cfg_sanitize)] + +#[cfg(all(sanitize = "address", address))] +fn main() {} + +#[cfg(all(sanitize = "leak", leak))] +fn main() {} + +#[cfg(all(sanitize = "memory", memory))] +fn main() {} + +#[cfg(all(sanitize = "thread", thread))] +fn main() {}