-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Tracking issue for RFC 2137: Support defining C-compatible variadic functions in Rust #44930
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 |
presumably the syntax for defining variadic functions would also be a special case. regardless, my point is that it does have precedent, and indeed is already associated with variadics. |
@bjorn3 The layout of typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
void *overflow_arg_area;
void *reg_save_area;
} va_list[1]; in the ABI specification. |
For C-SKY the abi specification doesn't seem to dictate any specific layout for You are right that many other abi specifications do explicitly mention the layout. I wasn't aware of this. References: |
I see what you mean. In the cases of C-SKY and Hexagon, this seems to be a case of the ABI specification under-specifying; as |
I do not believe this should be done. The Rust compiler does not even correctly check passing varargs currently when generic types become involved, see #61275 about that. When combined with accepting these types, this would make it very difficult to reason correctly about the type conversions involved, because we would be adding in our own special rules on top of the already Byzantine rules for C's variable arguments. This would make it much harder to correctly add support for passing e.g. structs over variadic arguments, down the line1. I don't believe our current implementations for variadic arguments are adequately or thoroughly tested. We have had a bad habit of not testing many edge-cases that could potentially get around naive checks. In other words, if you extract a different type from the I have found way too many bugs in how we handle low-level compilation details, including ABI problems, to believe this is a good idea. Footnotes
|
…, r=joboet core: VaArgSafe is an unsafe trait `T: VaArgSafe` is relied on for soundness. Safe impls promise nothing. Therefore this must be an unsafe trait. Slightly pedantic, as only core can impl this, but we *could* choose to unseal the trait. That would allow soundly (but unsafely) implementing this for e.g. a `#[repr(C)] struct` that should be passable by varargs. Relates to rust-lang#44930
…, r=joboet core: VaArgSafe is an unsafe trait `T: VaArgSafe` is relied on for soundness. Safe impls promise nothing. Therefore this must be an unsafe trait. Slightly pedantic, as only core can impl this, but we *could* choose to unseal the trait. That would allow soundly (but unsafely) implementing this for e.g. a `#[repr(C)] struct` that should be passable by varargs. Relates to rust-lang#44930
Rollup merge of rust-lang#126927 - workingjubilee:vaargsafe-is-unsafe, r=joboet core: VaArgSafe is an unsafe trait `T: VaArgSafe` is relied on for soundness. Safe impls promise nothing. Therefore this must be an unsafe trait. Slightly pedantic, as only core can impl this, but we *could* choose to unseal the trait. That would allow soundly (but unsafely) implementing this for e.g. a `#[repr(C)] struct` that should be passable by varargs. Relates to rust-lang#44930
It also seems incoherent to provide a demotion behavior for all of those types and then refuse to demote f32, I would think, as there is an expected lossless translation from f32 to f64 for non-NAN bitpatterns and a lossy translation from f64 to f32 for non-NAN bitpatterns that provides the rounded inverse of that. Importantly, if someone passed an f32, they'd get the same f32 back (except NANs might get weird, but we can attempt to define the promotion/demotion behavior to preserve NAN bitpatterns in the case where there's no optimizations). Or f16, for that matter. I still think we shouldn't do this because it invites confusion and misunderstanding what the Rust compiler is doing (because people don't really understand what the C compilers do, either). |
@programmerjake has informed me we cannot even rely anymore on things like "all C types will get promoted to at least a certain size" (even relative to the C ABI!) casting further doubt on that idea. |
yes, afaict |
Definitely fully agreed. Whether an It follows that the entire discussion about what gets promoted is unnecessary. It's the backends responsibility to handle this correctly. |
I think Rust shouldn't do promotions for |
As an example of the kind of "fun" one can have with this, see #71915. The man page says the argument has type |
maybe a good solution would be to warn when passing or accepting types that are usually subject to promotion since unsafe extern "C" {
unsafe fn f(c_int, ...);
}
pub g(v: f32) {
unsafe {
f(0, #[uncommon_c_types] v)
}
} |
why are you suggesting a special attribute for silencing a warning, we already have |
because iirc a lot of people don't want rustc to emit warnings on code when it's the only valid way to implement something and you can't rewrite it to be warning-free. |
this is still doing that, just providing an alias for |
To be clear, @RalfJung, this is actually part of the issue: in C, you are expected to have memorized the arcane promotion rules, and thus the author of the variadic function has to specify This is because the C promotion rules actually are not about the ABI. As demonstrated by So, I think that in Rust, we should not try to squirm out from under this. We should make apparent the bizarreness of the results. The example you cite, in any case, actually would not compile if you had tried to make the change: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=26aa043833877711d0aba4e26abdebae |
I guess...
I strongly think it should be in rustc because >99.9% of the time the warning is correct and C APIs are almost always documented as you just pass the smaller type, but rust needs the argument to be cast to the promoted type. rustc already has lints that will be incorrect more often than this, e.g.: temporary_cstring_as_ptr
yeah, picking a different name is fine with me. |
Fun!
Ah, neat. I had not seen that as I was just working on the other end -- implementing
which seems to contradict a little your statement that this is not about ABI.
Note that Rust also has a concept called "promotion", and it is entirely unrelated. So we need to be careful with how we use that term in documentation. |
I don't think the expanded error message is correct, no. It was written by someone who had far more SAN remaining than me. |
The missing safety contracts on the documentation for VaList really irk me. |
Then maybe make a PR that adds some? :) |
On another note, there was some recent discussion of varargs on Zulip which should be helpful on writing a spec for the ABI compatibility requirements of this feature. |
Turns out the complaint about a missing "env" module has nothing to do with what the word "env" probably leads you to expect. The next step towards understanding was to turn the wasm into text. There, one can see that the "env" stuff is apparently just a placeholder name this bindgen tooling is generating for when a symbol isn't found provided. Okay. So one "env" ref is getting generated for each of the printf symbols. Which are the things I declined to provide because they need variadics. Which I avoided that's behind a feature flag in rust, so needs nightly (see rust-lang/rust#44930). Okay. Well, aside from the fact the discoverability of this sucks, and the default module name that this bindgen tooling picks for this is actively misleading, and that the suckfulness of this discoverablity really fucking matters because ANY missing symbols would lead a wide variety of people and projects to this exact common sticking point... Options? Not sure. Here, I'm trying to provide the symbols, but incorrectly, and that... actually, it seems to work? And as you'll notice, these stubs were panicking unconditionally if called _anyway_, so they're evidentally not consequential to functioning of our code corpus. So if that is actually working, not hiding-more-trouble-under-a-rug that just hasn't popped out to jumpscare me again yet... okay, then we did a double barrel roll and dodged the need for rust nightly yet again, just barely. Cool. If true. Moving on. So now the browser console is dropping me this: "Uncaught InternalError: too much recursion". And points at a line of wasm that is doing... `call $func65`. Okay. I guess now I would like sourcemaps. I do not currently have sourcemaps. *sigh*
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<'_>
) #125431The text was updated successfully, but these errors were encountered: