Comments (23)
It seems entirely reasonable to want to iterate over two va_list
values in parallel. That wasn't a use case anticipated in the original safe VaList::copy
implementation, but it does seem entirely acceptable to do so.
The easiest safe solution would be a copy2
that takes a mutable reference and gives the containing closure two mutable references (including the one passed in). On the other hand, that seems like a niche use case to define a function for. (And I'd want to know that there aren't mor va_copy
use cases that we haven't anticipated yet that this wouldn't address.)
Another alternative: we could expose a raw copy function as an unsafe function.
I'm currently looking over the RFC thread to remember why we ended on a closure-taking function rather than a reference-returning function (e.g. VaList::copy
taking &self
and returning a &mut
with the same lifetime so that it can't outlive the VaList
).
from c2rust.
If we added VaList::raw_copy
and VaList::raw_end
then we wouldn't have to expose the raw intrinsic which would mean users wouln't need to write ugly cfg
s like this and we wouldn't need to export the VaListImpl
. We'd have to make sure documentation for the functions was clear that VaList
s created with raw_copy
must be destroyed with raw_end
and other VaList
s must not use raw_end
. Alternatively, raw_copy
could return a wrapper type like VaListCopy
that implements raw_end
so that a "normal" VaList
can't call raw_end
from c2rust.
Sample code in the Playground here: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=1deb2470984d60fe6ecf4ea10dac17da
pub unsafe extern "C" fn bar(mut ap1: VaList) {
ap1.copy(|mut ap2| {
println!("{}=={}", ap1.arg::<u32>(), ap2.arg::<u32>()); // Doesn't compile
});
}
In this snippet, the closure body cannot call ap1.arg()
since the latter mutably borrows ap1
, which is already immutably borrowed by ap1.copy()
.
from c2rust.
ap1.arg::<u32>()
can be called before the closure with the closure capturing the result.
pub unsafe extern "C" fn bar(mut ap1: VaList) {
let x = ap1.arg::<u32>();
ap1.copy(|mut ap2| {
let y = ap2.arg::<u32>();
println!("{}=={}", x, y);
});
}
from c2rust.
Would a valid workaround be something like the following:
- examine the closure and find all the times
VaList::arg
is called on the copied list. - create a variable for each of these
- replace the calls with the variables
Note that VaList::copy
uses an immutable reference, so you can use VaList::copy
on the copied VaList
in the closure.
from c2rust.
In general, it is not possible to know how many times VaList::arg
will be called in a function at translation time, i.e., a call to VaList::arg
can be guarded by a variable whose value is only known at run time.
from c2rust.
I can also see problems in cases where ap1.arg()
isn't called directly from the current function, but from some of its callees, e.g., if the current function passes ap1
to vprintf
. If the callees have other side-effects, it might not be sound to move them.
from c2rust.
Another alternative: we could expose a raw copy function as an unsafe function.
I can't speak to all use cases here, but in the C translation case, an unsafe copy function that returns a new va_list
that have to be va_end
'ed manually would work well. Since our translation is driven by the original C code, i.e., we'd translate calls to va_copy
and va_end
more or less one to one.
from c2rust.
@dlrobertson raw_copy
and raw_end
sound good to me.
Remind me why we couldn't just have copy
return a VaList with a lifetime that was a subset of the copied VaList's lifetime?
from c2rust.
Remind me why we couldn't just have copy return a VaList with a lifetime that was a subset of the copied VaList's lifetime?
The user would have to use va_end
right? Note: The interface was already defined by the time I started working on VaList
, so I may not be the best person to ask.
from c2rust.
@dlrobertson No, the Drop implementation would call va_end
.
from c2rust.
No, the Drop implementation would call va_end.
- I wonder if adding
Drop
toVaList
could complicate the current implementation of C-variadic functions since we "spoof" one in the function signature. - I wonder if the current
VaList::copy
should be be renamedVaList::with_copy
. - Is there a timeline when this work should be done by (do I need to suspend work on other issues and do this now)?
from c2rust.
I wonder if the current
VaList::copy
should be renamedVaList::with_copy
.
Sounds like a good idea to me.
Is there a timeline when this work should be done by
We are certainly not in a position to make demands on your time. That said, we are very interested in this change since it is the one remaining feature that prevents us from translating large C99 projects. Let us know if we can help.
from c2rust.
I'm currently looking over the RFC thread to remember why we ended on a closure-taking function rather than a reference-returning function (e.g. VaList::copy taking &self and returning a &mut with the same lifetime so that it can't outlive the VaList).
I remembered a reason why this wasn't done. You'd be returning a reference to data owned by the copy
function. For pointer variants, I think you'd be okay, but for structure variants you have to alloc the structure.
from c2rust.
from c2rust.
from c2rust.
It could still be a
VaList<'a>
though, right? (An owned structure that nonetheless has a lifetime?)
I don't think so. For the pointer variants it is fine, but for architectures like Aarch64 and x86_64 the reference contained by the VaList
structure would point to a value on the stack of copy
.
from c2rust.
Is there a timeline when this work should be done by (do I need to suspend work on other issues and do this now)?
@dlrobertson If you're busy with other things, we could implement this ourselves (@thedataking & myself) once we all agree on what the API is. This would also help accelerate testing with C2Rust for this feature, since we'd be doing it concurrently with development.
from c2rust.
- I wonder if adding
Drop
toVaList
could complicate the current implementation of C-variadic functions since we "spoof" one in the function signature.
I ran some tests and implementing Drop
for VaList
doesn't cause any issues with "pure" C-variadic functions.
we could implement this ourselves
@ahomescu @thedataking awesome! I'm on the rustc discussion threads at dlrobertson
. Ping me and I have some thoughts on experiments that could be run.
from c2rust.
from c2rust.
I haven't read the old discussions in their entirety so I'm not aware if this has already been discussed: on all of LLVM's current in-tree architectures, va_end
is a no-op, which would explain why the extra Drop
hasn't caused any issues.
from c2rust.
all of LLVM's current in-tree architectures, va_end is a no-op
Yes
which would explain why the extra Drop hasn't caused any issues.
Sorry, by "hasn't caused any issues" I also mean "generates the correct LLVM IR". With the Drop
implementation for VaList
+ some other changes you still only end up with one call to va_end
.
from c2rust.
Closing since rust-lang/rust#59625 was merged.
from c2rust.
Related Issues (20)
- Missing semicolon after volatile pointer cast.
- Aggregate libc functions into one file. HOT 1
- FYI: fatal runtime error: Rust cannot catch foreign exceptions
- Readme example of transpile for main.c doesn't work HOT 1
- Transpile `#include` as `include!()` HOT 4
- C2Rust transpiler emits features removed in recent nightlies HOT 1
- Switch case with ranges HOT 2
- rust-toolchain.toml is too old for 1.75 rust HOT 4
- cargo install c2rust failed: Could not find a configuration file for package "LLVM" that exactly matches requested version "16.0.6". HOT 2
- Build not matching clang version (Fedora 39, Clang 17.0.6) HOT 3
- cargo install c2rust failed: Error 2 HOT 2
- In the while loop body using a volatile variable, the generated code will lack a semicolon.
- why do you not support windows HOT 1
- Build fails with LLVM 18 and tip-of-tree HOT 1
- fail build on archlinux HOT 2
- Casting bool to pointer type results in invalid Rust
- Fatal error: 'stddef.h' file not found HOT 4
- ast_exporter can't convert a c code to ast HOT 2
- (Question) Do you plan to support C++ ? HOT 1
- Missing parentheses on reference applied to a cast
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from c2rust.