about summary refs log tree commit diff
path: root/src/librustc_codegen_ssa
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-06-18 21:50:46 +0000
committerbors <bors@rust-lang.org>2019-06-18 21:50:46 +0000
commit605ea9d05c48957a291eec11eb7339788c3140ed (patch)
tree57b5bcd13ed3c9a67b234200959ca8a454edbebe /src/librustc_codegen_ssa
parent04a3dd8a872633ca1e4c217d11f741cc35cb19a5 (diff)
parentb9ea653aee231114acbe6d4b3c7b1d692772d060 (diff)
downloadrust-605ea9d05c48957a291eec11eb7339788c3140ed.tar.gz
rust-605ea9d05c48957a291eec11eb7339788c3140ed.zip
Auto merge of #59625 - immunant:copy_variadics_typealias, r=eddyb
Refactor C FFI variadics to more closely match their C counterparts, and add Clone implementation

We had to make some changes to expose `va_copy` and `va_end` directly to users (mainly for C2Rust, but not exclusively):
- redefine the Rust variadic structures to more closely correspond to C: `VaList` now matches `va_list`, and `VaListImpl` matches `__va_list_tag`
- add `Clone` for `VaListImpl`
- add explicit `as_va_list()` conversion function from `VaListImpl` to `VaList`
- add deref coercion from `VaList` to `VaListImpl`
- add support for the `asmjs` target

All these changes were needed for use cases like:
```Rust
let mut ap2 = va_copy(ap);
vprintf(fmt, ap2);
va_end(&mut ap2);
```
Diffstat (limited to 'src/librustc_codegen_ssa')
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs6
-rw-r--r--src/librustc_codegen_ssa/mir/mod.rs33
-rw-r--r--src/librustc_codegen_ssa/traits/intrinsic.rs4
3 files changed, 16 insertions, 27 deletions
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index b4acc400546..941166ccfab 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -503,7 +503,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             return;
         }
 
-        // The "spoofed" `VaList` added to a C-variadic functions signature
+        // 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..];
@@ -687,7 +687,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             (&args[..], None)
         };
 
-        // Useful determining if the current argument is the "spoofed" `VaList`
+        // Useful determining if the current argument is the "spoofed" `VaListImpl`
         let last_arg_idx = if sig.inputs().is_empty() {
             None
         } else {
@@ -695,7 +695,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         };
         'make_args: for (i, arg) in first_args.iter().enumerate() {
             // If this is a C-variadic function the function signature contains
-            // an "spoofed" `VaList`. This argument is ignored, but we need to
+            // 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) {
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index c20be56ba0c..e7517d69991 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -83,7 +83,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
     scopes: IndexVec<mir::SourceScope, debuginfo::MirDebugScope<Bx::DIScope>>,
 
     /// If this function is a C-variadic function, this contains the `PlaceRef` of the
-    /// "spoofed" `VaList`.
+    /// "spoofed" `VaListImpl`.
     va_list_ref: Option<PlaceRef<'tcx, Bx::Value>>,
 }
 
@@ -562,35 +562,24 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             indirect_operand.store(bx, tmp);
             tmp
         } else {
+            let tmp = PlaceRef::alloca(bx, arg.layout, &name);
             if fx.fn_ty.c_variadic && last_arg_idx.map(|idx| arg_index == idx).unwrap_or(false) {
-                let va_list_impl = match arg_decl.ty.ty_adt_def() {
-                    Some(adt) => adt.non_enum_variant(),
-                    None => bug!("`va_list` language item improperly constructed")
+                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 tcx.type_of(va_list_impl.fields[0].did).sty {
-                    ty::Ref(_, ty, _) => {
-                        // If the underlying structure the `VaList` contains is a structure,
-                        // we need to allocate it (e.g., X86_64 on Linux).
-                        let tmp = PlaceRef::alloca(bx, arg.layout, &name);
-                        if let ty::Adt(..) = ty.sty {
-                            let layout = bx.layout_of(ty);
-                            // Create an unnamed allocation for the backing structure
-                            // and store it in the the spoofed `VaList`.
-                            let backing = PlaceRef::alloca(bx, layout, "");
-                            bx.store(backing.llval, tmp.llval, layout.align.abi);
-                        }
-                        // Call `va_start` on the spoofed `VaList`.
+                match arg_decl.ty.sty {
+                    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);
-                        tmp
-                    }
-                    _ => bug!("improperly constructed `va_list` lang item"),
+                    },
+                    _ => bug!("last argument of variadic function is not a `va_list`")
                 }
             } else {
-                let tmp = PlaceRef::alloca(bx, arg.layout, &name);
                 bx.store_fn_arg(arg, &mut llarg_idx, tmp);
-                tmp
             }
+            tmp
         };
         let upvar_debuginfo = &mir.__upvar_debuginfo_codegen_only_do_not_use;
         arg_scope.map(|scope| {
diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/src/librustc_codegen_ssa/traits/intrinsic.rs
index cd527898977..ede30a0bed7 100644
--- a/src/librustc_codegen_ssa/traits/intrinsic.rs
+++ b/src/librustc_codegen_ssa/traits/intrinsic.rs
@@ -20,10 +20,10 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes {
     fn abort(&mut self);
     fn assume(&mut self, val: Self::Value);
     fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value;
-    /// Trait method used to inject `va_start` on the "spoofed" `VaList` in
+    /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in
     /// Rust defined C-variadic functions.
     fn va_start(&mut self, val: Self::Value) -> Self::Value;
-    /// Trait method used to inject `va_end` on the "spoofed" `VaList` before
+    /// Trait method used to inject `va_end` on the "spoofed" `VaListImpl` before
     /// Rust defined C-variadic functions return.
     fn va_end(&mut self, val: Self::Value) -> Self::Value;
 }