diff options
Diffstat (limited to 'src/librustc_codegen_ssa/mir')
| -rw-r--r-- | src/librustc_codegen_ssa/mir/block.rs | 44 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/mir/mod.rs | 68 |
2 files changed, 39 insertions, 73 deletions
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 3069199a212..7ebdfbdcdeb 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -1,9 +1,10 @@ +use rustc_data_structures::indexed_vec::Idx; use rustc::middle::lang_items; use rustc::ty::{self, Ty, TypeFoldable, Instance}; use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt}; use rustc::mir::{self, Place, PlaceBase, Static, StaticKind}; use rustc::mir::interpret::PanicInfo; -use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode}; +use rustc_target::abi::call::{ArgType, FnType, PassMode}; use rustc_target::spec::abi::Abi; use crate::base; use crate::MemFlags; @@ -224,14 +225,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } fn codegen_return_terminator(&mut self, mut bx: Bx) { + // Call `va_end` if this is the definition of a C-variadic function. if self.fn_ty.c_variadic { - match self.va_list_ref { - Some(va_list) => { + // The `VaList` "spoofed" argument is just after all the real arguments. + let va_list_arg_idx = self.fn_ty.args.len(); + match self.locals[mir::Local::new(1 + va_list_arg_idx)] { + LocalRef::Place(va_list) => { bx.va_end(va_list.llval); } - None => { - bug!("C-variadic function must have a `va_list_ref`"); - } + _ => bug!("C-variadic function must have a `VaList` place"), } } if self.fn_ty.ret.layout.abi.is_uninhabited() { @@ -242,15 +244,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } let llval = match self.fn_ty.ret.mode { - PassMode::Ignore(IgnoreMode::Zst) | PassMode::Indirect(..) => { + PassMode::Ignore | PassMode::Indirect(..) => { bx.ret_void(); return; } - PassMode::Ignore(IgnoreMode::CVarArgs) => { - bug!("C-variadic arguments should never be the return type"); - } - PassMode::Direct(_) | PassMode::Pair(..) => { let op = self.codegen_consume(&mut bx, &mir::Place::return_place().as_ref()); @@ -502,10 +500,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - // The "spoofed" `VaListImpl` added to a C-variadic functions signature - // should not be included in the `extra_args` calculation. - let extra_args_start_idx = sig.inputs().len() - if sig.c_variadic { 1 } else { 0 }; - let extra_args = &args[extra_args_start_idx..]; + 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) @@ -691,26 +686,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (&args[..], None) }; - // Useful determining if the current argument is the "spoofed" `VaListImpl` - let last_arg_idx = if sig.inputs().is_empty() { - None - } else { - Some(sig.inputs().len() - 1) - }; 'make_args: for (i, arg) in first_args.iter().enumerate() { - // If this is a C-variadic function the function signature contains - // an "spoofed" `VaListImpl`. This argument is ignored, but we need to - // populate it with a dummy operand so that the users real arguments - // are not overwritten. - let i = if sig.c_variadic && last_arg_idx.map(|x| i >= x).unwrap_or(false) { - if i + 1 < fn_ty.args.len() { - i + 1 - } else { - break 'make_args - } - } else { - i - }; let mut op = self.codegen_operand(&mut bx, arg); if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) { diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index c341c0685c6..4f3a8bdb540 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -2,7 +2,7 @@ use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts, Instance}; use rustc::ty::layout::{TyLayout, HasTyCtxt, FnTypeExt}; use rustc::mir::{self, Body}; use rustc::session::config::DebugInfo; -use rustc_target::abi::call::{FnType, PassMode, IgnoreMode}; +use rustc_target::abi::call::{FnType, PassMode}; use rustc_target::abi::{Variants, VariantIdx}; use crate::base; use crate::debuginfo::{self, VariableAccess, VariableKind, FunctionDebugContext}; @@ -81,10 +81,6 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// Debug information for MIR scopes. scopes: IndexVec<mir::SourceScope, debuginfo::MirDebugScope<Bx::DIScope>>, - - /// If this function is a C-variadic function, this contains the `PlaceRef` of the - /// "spoofed" `VaListImpl`. - va_list_ref: Option<PlaceRef<'tcx, Bx::Value>>, } impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { @@ -236,18 +232,13 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( scopes, locals: IndexVec::new(), debug_context, - va_list_ref: None, }; let memory_locals = analyze::non_ssa_locals(&fx); // Allocate variable and temp allocas fx.locals = { - // FIXME(dlrobertson): This is ugly. Find a better way of getting the `PlaceRef` or - // `LocalRef` from `arg_local_refs` - let mut va_list_ref = None; - let args = arg_local_refs(&mut bx, &fx, &memory_locals, &mut va_list_ref); - fx.va_list_ref = va_list_ref; + let args = arg_local_refs(&mut bx, &fx, &memory_locals); let mut allocate_local = |local| { let decl = &mir.local_decls[local]; @@ -426,7 +417,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, fx: &FunctionCx<'a, 'tcx, Bx>, memory_locals: &BitSet<mir::Local>, - va_list_ref: &mut Option<PlaceRef<'tcx, Bx::Value>>, ) -> Vec<LocalRef<'tcx, Bx::Value>> { let mir = fx.mir; let tcx = fx.cx.tcx(); @@ -441,15 +431,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( None }; - // Store the index of the last argument. This is used to - // call va_start on the va_list instead of attempting - // to store_fn_arg. - let last_arg_idx = if fx.fn_ty.args.is_empty() { - None - } else { - Some(fx.fn_ty.args.len() - 1) - }; - mir.args_iter().enumerate().map(|(arg_index, local)| { let arg_decl = &mir.local_decls[local]; @@ -503,6 +484,31 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( return LocalRef::Place(place); } + if fx.fn_ty.c_variadic && arg_index == fx.fn_ty.args.len() { + let arg_ty = fx.monomorphize(&arg_decl.ty); + + let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty)); + bx.set_var_name(va_list.llval, name); + bx.va_start(va_list.llval); + + arg_scope.map(|scope| { + let variable_access = VariableAccess::DirectVariable { + alloca: va_list.llval + }; + bx.declare_local( + &fx.debug_context, + arg_decl.name.unwrap_or(kw::Invalid), + va_list.layout.ty, + scope, + variable_access, + VariableKind::ArgumentVariable(arg_index + 1), + DUMMY_SP + ); + }); + + return LocalRef::Place(va_list); + } + let arg = &fx.fn_ty.args[idx]; idx += 1; if arg.pad.is_some() { @@ -515,10 +521,9 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // of putting everything in allocas just so we can use llvm.dbg.declare. let local = |op| LocalRef::Operand(Some(op)); match arg.mode { - PassMode::Ignore(IgnoreMode::Zst) => { + PassMode::Ignore => { return local(OperandRef::new_zst(bx, arg.layout)); } - PassMode::Ignore(IgnoreMode::CVarArgs) => {} PassMode::Direct(_) => { let llarg = bx.get_param(llarg_idx); bx.set_var_name(llarg, &name); @@ -568,22 +573,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } else { let tmp = PlaceRef::alloca(bx, arg.layout); bx.set_var_name(tmp.llval, name); - if fx.fn_ty.c_variadic && last_arg_idx.map(|idx| arg_index == idx).unwrap_or(false) { - let va_list_did = match tcx.lang_items().va_list() { - Some(did) => did, - None => bug!("`va_list` lang item required for C-variadic functions"), - }; - match arg_decl.ty.kind { - ty::Adt(def, _) if def.did == va_list_did => { - // Call `va_start` on the spoofed `VaListImpl`. - bx.va_start(tmp.llval); - *va_list_ref = Some(tmp); - }, - _ => bug!("last argument of variadic function is not a `va_list`") - } - } else { - bx.store_fn_arg(arg, &mut llarg_idx, tmp); - } + bx.store_fn_arg(arg, &mut llarg_idx, tmp); tmp }; let upvar_debuginfo = &mir.__upvar_debuginfo_codegen_only_do_not_use; |
