-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Tracking issue for RFC 2137: Support defining C-compatible variadic functions in Rust #44930
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I'd like to work on this, I already have some prototype |
Awesome @plietar! It'd probably be good to bring this up in the "middle-end" compiler working group channel, which would also be a good place to get any help you might need. |
@plietar How goes the implementation? I remember you showing a mostly complete prototype on IRC. |
@plietar any news to share? This is a blocker for teams working on C to Rust transpilers, so this addition would be very welcome. (I'm part of one such team). |
Hey, |
@plietar Any update on this? Do you have a WIP branch I can check out to try / fiddle with this? |
Looks like I'm a little late to the party 😄 ... sorry about that A few questions:
@plietar if you don't have the time to work on this any more or if there is any way I could help out, I'd be more than happy to do so. I haven't worked on rustc much, but I'd be happy to help however I can with the implementation of this. |
Seems likely that @plietar doesn't have much time, though they can speak for themselves. I've not really looked closely at what would be needed to implement this, but if you need any help, please ping me, or reach out on gitter/IRC. |
I've been working on this for the past two week and have
I'm struggling a bit with understanding how to write something in Also how would you like me to break this up into PRs? My current plan was to submit a PR once I got |
libcore: Add VaList and variadic arg handling intrinsics ## Summary - Add intrinsics for `va_start`, `va_end`, `va_copy`, and `va_arg`. - Add `core::va_list::VaList` to `libcore`. Part 1 of (at least) 3 for #44930 Comments and critiques are very much welcomed 😄
libcore: Add VaList and variadic arg handling intrinsics ## Summary - Add intrinsics for `va_start`, `va_end`, `va_copy`, and `va_arg`. - Add `core::va_list::VaList` to `libcore`. Part 1 of (at least) 3 for #44930 Comments and critiques are very much welcomed 😄
Now that the When any issues with the implementation of |
@dlrobertson That's super. Are you implementing the |
…r=workingjubilee limit impls of `VaArgSafe` to just types that are actually safe tracking issue: rust-lang#44930 Retrieving 8- or 16-bit integer arguments from a `VaList` is not safe, because such types are subject to upcasting. See rust-lang#61275 (comment) for more detail. This PR also makes the instances of `VaArgSafe` visible in the documentation, and uses a private sealed trait to make sure users cannot create additional impls of `VaArgSafe`, which would almost certainly cause UB. r? `@workingjubilee`
Rollup merge of rust-lang#141341 - folkertdev:limit-VaArgSafe-impls, r=workingjubilee limit impls of `VaArgSafe` to just types that are actually safe tracking issue: rust-lang#44930 Retrieving 8- or 16-bit integer arguments from a `VaList` is not safe, because such types are subject to upcasting. See rust-lang#61275 (comment) for more detail. This PR also makes the instances of `VaArgSafe` visible in the documentation, and uses a private sealed trait to make sure users cannot create additional impls of `VaArgSafe`, which would almost certainly cause UB. r? `@workingjubilee`
We need https://gist.github.com/folkertdev/47c79e2f5b03f1138db9d53be5e51ed1 Some highlights
This all relies on a different desugaring of fn foo(placeholder: i32, mut args: ...) {
// stuff
}
// --->
fn foo(placeholder: i32) {
let tag = core::mem::MaybeUninit::<VaListImpl>::uninit();
unsafe { core::instrinsics::va_start(tag.as_mut_ptr()) }
let mut args = VaList(tag.assume_init_mut())
// stuff
} It seems possible to make that work internally. I think this new API is nicer, because it leaks fewer implementation details. But before we start implementation work, does anyone see issues with this direction? pinging specifically the c2rust folks @thedataking @ahomescu, you've probably worked with the existing |
@rustbot labels -I-lang-nominated Let's fork discussion of that proposal out to: We'll take the nomination there. |
…ubilee use `cfg_select!` to select the right `VaListImpl` definition tracking issue: rust-lang#44930 Just a bit of cleanup really. We could use `PhantomInvariantLifetime<'f>` (rust-lang#135806) to make it more precise what that `PhantomData<&'f mut &'f c_void>` marker is doing. I'm not sure how ready that feature is though, `@jhpratt` are these types good to use internally? --- Some research into the lifetimes of `VaList` and `VaListImpl`: It's easy to see why the lifetime of these types should not be extended, a `VaList` or `VaListImpl` escaping its function is a bad idea. I don't currently see why coercing the lifetime to a shorter lifetime is problematic though, but probably I just don't understand variance well enough to see it. The history does not provide much explanation: - immunant@0814087 original implementation - immunant@b9ea653 adds `VaListImpl<'f>`, but it is only covariant in `'f` - rust-lang#62639 makes `VaListImpl<'f>` invariant over `'f` (because `VaList<'a, 'f>` is already invariant over `'f`, but I think that is just an implementation detail?) Beyond that I don't see how the lifetime situation can be simplified significantly, e.g. this function really needs `'copy` to be unconstrained. ```rust /// Copies the `va_list` at the current location. pub unsafe fn with_copy<F, R>(&self, f: F) -> R where F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R, { let mut ap = self.clone(); let ret = f(ap.as_va_list()); // SAFETY: the caller must uphold the safety contract for `va_end`. unsafe { va_end(&mut ap); } ret } ``` `@rustbot` label +F-c_variadic r? `@workingjubilee`
Rollup merge of #141361 - folkertdev:varargs-cfg, r=workingjubilee use `cfg_select!` to select the right `VaListImpl` definition tracking issue: #44930 Just a bit of cleanup really. We could use `PhantomInvariantLifetime<'f>` (#135806) to make it more precise what that `PhantomData<&'f mut &'f c_void>` marker is doing. I'm not sure how ready that feature is though, `@jhpratt` are these types good to use internally? --- Some research into the lifetimes of `VaList` and `VaListImpl`: It's easy to see why the lifetime of these types should not be extended, a `VaList` or `VaListImpl` escaping its function is a bad idea. I don't currently see why coercing the lifetime to a shorter lifetime is problematic though, but probably I just don't understand variance well enough to see it. The history does not provide much explanation: - immunant@0814087 original implementation - immunant@b9ea653 adds `VaListImpl<'f>`, but it is only covariant in `'f` - #62639 makes `VaListImpl<'f>` invariant over `'f` (because `VaList<'a, 'f>` is already invariant over `'f`, but I think that is just an implementation detail?) Beyond that I don't see how the lifetime situation can be simplified significantly, e.g. this function really needs `'copy` to be unconstrained. ```rust /// Copies the `va_list` at the current location. pub unsafe fn with_copy<F, R>(&self, f: F) -> R where F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R, { let mut ap = self.clone(); let ret = f(ap.as_va_list()); // SAFETY: the caller must uphold the safety contract for `va_end`. unsafe { va_end(&mut ap); } ret } ``` `@rustbot` label +F-c_variadic r? `@workingjubilee`
…workingjubilee make teach_help message for cast-before-pass-to-variadic more precise r? `@workingjubilee` based on your comment [here](rust-lang#44930 (comment))
Rollup merge of #141443 - RalfJung:c-variadic-teach-help, r=workingjubilee make teach_help message for cast-before-pass-to-variadic more precise r? `@workingjubilee` based on your comment [here](#44930 (comment))
…r=workingjubilee limit impls of `VaArgSafe` to just types that are actually safe tracking issue: rust-lang#44930 Retrieving 8- or 16-bit integer arguments from a `VaList` is not safe, because such types are subject to upcasting. See rust-lang#61275 (comment) for more detail. This PR also makes the instances of `VaArgSafe` visible in the documentation, and uses a private sealed trait to make sure users cannot create additional impls of `VaArgSafe`, which would almost certainly cause UB. r? `@workingjubilee`
…ubilee use `cfg_select!` to select the right `VaListImpl` definition tracking issue: rust-lang#44930 Just a bit of cleanup really. We could use `PhantomInvariantLifetime<'f>` (rust-lang#135806) to make it more precise what that `PhantomData<&'f mut &'f c_void>` marker is doing. I'm not sure how ready that feature is though, `@jhpratt` are these types good to use internally? --- Some research into the lifetimes of `VaList` and `VaListImpl`: It's easy to see why the lifetime of these types should not be extended, a `VaList` or `VaListImpl` escaping its function is a bad idea. I don't currently see why coercing the lifetime to a shorter lifetime is problematic though, but probably I just don't understand variance well enough to see it. The history does not provide much explanation: - immunant@0814087 original implementation - immunant@b9ea653 adds `VaListImpl<'f>`, but it is only covariant in `'f` - rust-lang#62639 makes `VaListImpl<'f>` invariant over `'f` (because `VaList<'a, 'f>` is already invariant over `'f`, but I think that is just an implementation detail?) Beyond that I don't see how the lifetime situation can be simplified significantly, e.g. this function really needs `'copy` to be unconstrained. ```rust /// Copies the `va_list` at the current location. pub unsafe fn with_copy<F, R>(&self, f: F) -> R where F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R, { let mut ap = self.clone(); let ret = f(ap.as_va_list()); // SAFETY: the caller must uphold the safety contract for `va_end`. unsafe { va_end(&mut ap); } ret } ``` `@rustbot` label +F-c_variadic r? `@workingjubilee`
…r=workingjubilee use custom types to clarify arguments to `emit_ptr_va_arg` tracking issue: rust-lang#44930 split out of rust-lang#141622 r? `@workingjubilee` `@rustbot` label: +F-c_variadic
…r=workingjubilee use custom types to clarify arguments to `emit_ptr_va_arg` tracking issue: rust-lang#44930 split out of rust-lang#141622 r? ``@workingjubilee`` ``@rustbot`` label: +F-c_variadic
implement `va_arg` for x86_64 systemv tracking issue: #44930 Turns out LLVM's `va_arg` is also unreliable for this target. llvm/llvm-project#141361 So, like clang, we implement our own. I used - the spec at https://gitlab.com/x86-psABIs/x86-64-ABI - the clang implementation at https://github.com/llvm/llvm-project/blob/9a440f84773c56d3803f330774acb2b4f471d5b4/clang/lib/CodeGen/Targets/X86.cpp#L3041 We can take a bunch of shortcuts because the return type of `va_list` must implement `VaArgSafe`. I also extended some of the tests, because up to 11 floats can be stored in the `reg_safe_area` for this calling convention. r? `@workingjubilee` `@rustbot` label +F-c_variadic try-job: x86_64-apple-1
…r=workingjubilee implement `va_arg` for x86_64 systemv tracking issue: rust-lang#44930 Turns out LLVM's `va_arg` is also unreliable for this target. llvm/llvm-project#141361 So, like clang, we implement our own. I used - the spec at https://gitlab.com/x86-psABIs/x86-64-ABI - the clang implementation at https://github.com/llvm/llvm-project/blob/9a440f84773c56d3803f330774acb2b4f471d5b4/clang/lib/CodeGen/Targets/X86.cpp#L3041 We can take a bunch of shortcuts because the return type of `va_list` must implement `VaArgSafe`. I also extended some of the tests, because up to 11 floats can be stored in the `reg_safe_area` for this calling convention. r? `@workingjubilee` `@rustbot` label +F-c_variadic try-job: x86_64-apple-1
Rollup merge of #141538 - folkertdev:systemv-x86_64-va_arg, r=workingjubilee implement `va_arg` for x86_64 systemv tracking issue: #44930 Turns out LLVM's `va_arg` is also unreliable for this target. llvm/llvm-project#141361 So, like clang, we implement our own. I used - the spec at https://gitlab.com/x86-psABIs/x86-64-ABI - the clang implementation at https://github.com/llvm/llvm-project/blob/9a440f84773c56d3803f330774acb2b4f471d5b4/clang/lib/CodeGen/Targets/X86.cpp#L3041 We can take a bunch of shortcuts because the return type of `va_list` must implement `VaArgSafe`. I also extended some of the tests, because up to 11 floats can be stored in the `reg_safe_area` for this calling convention. r? `@workingjubilee` `@rustbot` label +F-c_variadic try-job: x86_64-apple-1
…jubilee implement `va_arg` for x86_64 systemv tracking issue: rust-lang/rust#44930 Turns out LLVM's `va_arg` is also unreliable for this target. llvm/llvm-project#141361 So, like clang, we implement our own. I used - the spec at https://gitlab.com/x86-psABIs/x86-64-ABI - the clang implementation at https://github.com/llvm/llvm-project/blob/9a440f84773c56d3803f330774acb2b4f471d5b4/clang/lib/CodeGen/Targets/X86.cpp#L3041 We can take a bunch of shortcuts because the return type of `va_list` must implement `VaArgSafe`. I also extended some of the tests, because up to 11 floats can be stored in the `reg_safe_area` for this calling convention. r? `@workingjubilee` `@rustbot` label +F-c_variadic try-job: x86_64-apple-1
…ngjubilee implement `va_arg` for `powerpc` tracking issue: rust-lang#44930 The llvm `va_arg` implementation is well-known to have serious limitations. Some planned changes to rust's `VaList` make it much more likely that LLVM miscompiles `va_arg`, so this PR adds support for the various powerpc targets. Now at least the targets that `core` has explicit support for will continue to work. For `powerpc` (the 32-bit variant) this implementation also fixes a bug where only up to 20 variadic arguments were supported. Locally (with qemu), these targets now pass the tests in https://github.com/rust-lang/rust/blob/master/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs. That test does not actually run for the powerpc targets in CI though. The implementation is based on clang: - handling of big endian architectures https://github.com/llvm/llvm-project/blob/3c8089d1ea53232d5a7cdc33f0cb43ef7d6f723b/clang/lib/CodeGen/ABIInfoImpl.cpp#L191-L193 - 64-bit https://github.com/llvm/llvm-project/blob/3c8089d1ea53232d5a7cdc33f0cb43ef7d6f723b/clang/lib/CodeGen/Targets/PPC.cpp#L969 - 32-bit https://github.com/llvm/llvm-project/blob/3c8089d1ea53232d5a7cdc33f0cb43ef7d6f723b/clang/lib/CodeGen/Targets/PPC.cpp#L430 cc `@daltenty` (target maintainer) r? `@workingjubilee` `@rustbot` label: +F-c_variadic
Rollup merge of #141622 - folkertdev:powerpc-va_arg, r=workingjubilee implement `va_arg` for `powerpc` tracking issue: #44930 The llvm `va_arg` implementation is well-known to have serious limitations. Some planned changes to rust's `VaList` make it much more likely that LLVM miscompiles `va_arg`, so this PR adds support for the various powerpc targets. Now at least the targets that `core` has explicit support for will continue to work. For `powerpc` (the 32-bit variant) this implementation also fixes a bug where only up to 20 variadic arguments were supported. Locally (with qemu), these targets now pass the tests in https://github.com/rust-lang/rust/blob/master/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs. That test does not actually run for the powerpc targets in CI though. The implementation is based on clang: - handling of big endian architectures https://github.com/llvm/llvm-project/blob/3c8089d1ea53232d5a7cdc33f0cb43ef7d6f723b/clang/lib/CodeGen/ABIInfoImpl.cpp#L191-L193 - 64-bit https://github.com/llvm/llvm-project/blob/3c8089d1ea53232d5a7cdc33f0cb43ef7d6f723b/clang/lib/CodeGen/Targets/PPC.cpp#L969 - 32-bit https://github.com/llvm/llvm-project/blob/3c8089d1ea53232d5a7cdc33f0cb43ef7d6f723b/clang/lib/CodeGen/Targets/PPC.cpp#L430 cc `@daltenty` (target maintainer) r? `@workingjubilee` `@rustbot` label: +F-c_variadic
…y-speed, r=nnethercote C-variadic functions must be unsafe tracking issue: rust-lang#44930 A function that uses `...` is always unsafe to call, because it is UB to provide the wrong number of arguments, or arguments of an unexpected type. Hence, an `unsafe extern "C" { /* ... */ }` block should not be able to declare a `safe fn` that uses `...`. cc `@joshtriplett` `@workingjubilee` I'm not really sure who'd be a good reviewer for the actual parser code. `@rustbot` label: +F-c_variadic
Uh oh!
There was an error while loading. Please reload this page.
This is a tracking issue for the RFC "Support defining C-compatible variadic functions in Rust" (rust-lang/rfcs#2137).
Steps:
Unresolved questions:
can provide an appropriate lifetime that prevents a
VaList
from outliving itscorresponding variadic function."
...
syntax.const fn
....
desugaring (VaListImpl<'_>
) #125431VaList<'_>
does not carry its ABI in its type #141618The text was updated successfully, but these errors were encountered: