Skip to content

Commit ca7ee7e

Browse files
lucic71nunoplopes
andauthored
Translate address-of variadic function (#533)
Also needed by variadic lambdas. `&[VaArg]` does not fulfil the `'static` requirement of FnPtrArg so it cannot be used inside FnPtr. That's. because a borrow of an array cannot live for the entire duration of the program. `Box<[VaArg]>` can do that. It's already what we use in refcount for modelling arrays. --------- Co-authored-by: Nuno Lopes <nuno.lopes@tecnico.ulisboa.pt>
1 parent a8ca6ad commit ca7ee7e

54 files changed

Lines changed: 470 additions & 229 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎cpp2rust/converter/converter.cpp‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,9 @@ Converter::ConvertFunctionPointerType(const clang::FunctionProtoType *proto) {
296296
result += ToString(p_ty);
297297
result += ',';
298298
}
299+
if (proto->isVariadic()) {
300+
result += "Box<[VaArg]>,";
301+
}
299302
result += ')';
300303
if (!proto->getReturnType()->isVoidType()) {
301304
result += std::format(" -> {}", ToString(proto->getReturnType()));
@@ -2234,8 +2237,9 @@ void Converter::EmitArgList(const CallInfo &info) {
22342237

22352238
if (info.is_variadic) {
22362239
if (!info.is_libc_passthrough) {
2237-
StrCat(token::kRef);
2240+
StrCat("Box::new");
22382241
}
2242+
PushParen box(*this, !info.is_libc_passthrough);
22392243
PushBracket push(*this, !info.is_libc_passthrough);
22402244
for (auto *arg : info.variadic_args) {
22412245
{
@@ -4069,6 +4073,9 @@ void Converter::ConvertLambdaClosure(const clang::CXXRecordDecl *decl,
40694073
ConvertVarDeclSkipInit(p);
40704074
StrCat(token::kComma);
40714075
}
4076+
if (call_operator->isVariadic()) {
4077+
StrCat("__args: Box<[VaArg]>", token::kComma);
4078+
}
40724079
in_function_formals_ = false;
40734080
StrCat('|');
40744081
ConvertFunctionReturnType(call_operator);
@@ -4626,7 +4633,7 @@ void Converter::ConvertFunctionParameters(clang::FunctionDecl *decl) {
46264633
StrCat(token::kComma);
46274634
}
46284635
if (decl->isVariadic()) {
4629-
StrCat("__args: &[VaArg]", token::kComma);
4636+
StrCat("__args: Box<[VaArg]>", token::kComma);
46304637
}
46314638
in_function_formals_ = false;
46324639
}
@@ -5321,15 +5328,15 @@ Converter::ConvertVariadicTail(clang::Expr *expr,
53215328
unsigned fixed = tgt_ir ? tgt_ir->params.size() : 0;
53225329

53235330
Buffer buf(*this);
5324-
StrCat("&[");
5331+
StrCat("Box::<[VaArg]>::from([");
53255332
for (unsigned i = fixed; i < all_args.size(); ++i) {
53265333
{
53275334
PushParen p(*this);
53285335
ConvertVariadicArg(all_args[i]);
53295336
}
53305337
StrCat(".into()", token::kComma);
53315338
}
5332-
StrCat("]");
5339+
StrCat("])");
53335340
return std::move(buf).str();
53345341
}
53355342

‎docs/src/rules/conventions.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ fails the build; the notes below call out the ones that are not checked.
1111
| Type rule | `t1`, `t2`, ... via `using`/`typedef` | `fn tN() -> RustType` with no arguments |
1212
| Parameters | free-form (`o`, `it`, `key`, `dst`, `n`, ...) | must be `a0`, `a1`, ... consecutive from 0 |
1313
| Generics | `T1`, `T2`, ... (type and non-type params) | `T1`, `T2`, ... consecutive from 1 |
14-
| Variadic pack | `typename... Args` | trailing `va: &[VaArg]` |
14+
| Variadic pack | `typename... Args` | trailing `va: Box<[VaArg]>` |
1515
| Constructing pack | `Init<T, Args> &&...args` | trailing `init: RustType` |
1616
| Locals in Rust bodies | | double-underscore prefix: `__v`, `__fd`, `__e`, ... |
1717

‎docs/src/rules/writing-rules.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ int f1(int a0, int a1, ...) { return fcntl(a0, a1, ...); }
267267

268268
is not expressible. A parameter pack can be forwarded (`args...`), which is
269269
exactly what the rule body needs to do. The Rust side takes a trailing parameter
270-
that must be typed `&[VaArg]` and named `va`:
270+
that must be typed `Box<[VaArg]>` and named `va`:
271271

272272
```cpp
273273
// rules/fcntl/src.cpp
@@ -279,7 +279,7 @@ int f1(int a0, int a1, Args... args) {
279279
280280
```rust
281281
// rules/fcntl/tgt_refcount.rs
282-
fn f1(a0: i32, a1: i32, va: &[VaArg]) -> i32 { ... }
282+
fn f1(a0: i32, a1: i32, va: Box<[VaArg]>) -> i32 { ... }
283283
```
284284

285285
Bodies read the arguments through the va-args API in `libcc2rs` (`VaArg`,

‎docs/src/runtime/va-args.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ sum(3, 10, 20, 30);
3939
```
4040
4141
```rust
42-
pub fn sum_0(count: i32, __args: &[VaArg]) -> i32 {
42+
pub fn sum_0(count: i32, __args: Box<[VaArg]>) -> i32 {
4343
let ap: Value<VaList> = Rc::new(RefCell::new(VaList::default()));
4444
(*ap.borrow_mut()) = VaList::new(__args);
4545
let total: Value<i32> = Rc::new(RefCell::new(0));
@@ -48,7 +48,7 @@ pub fn sum_0(count: i32, __args: &[VaArg]) -> i32 {
4848
// ...
4949
}
5050
51-
sum_0(3, &[10.into(), 20.into(), 30.into()]);
51+
sum_0(3, Box::new([10.into(), 20.into(), 30.into()]));
5252
```
5353

5454
`arg::<T>()` goes through the `VaArgGet` trait, implemented for the integer and
@@ -59,5 +59,5 @@ panics, as does reading past the last argument.
5959

6060
Variadic libc functions such as `printf` and `fcntl` are handled by
6161
[variadic rules](../rules/writing-rules.md#variadic-functions), whose bodies
62-
receive the same `&[VaArg]` slice; `format_c` in the
62+
receive the same `Box<[VaArg]>`; `format_c` in the
6363
[format module](./io.md#formatting) consumes one to evaluate a format string.

‎libcc2rs/src/fn_ptr_arg.rs‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::rc::Rc;
99

1010
use crate::rc::Ptr;
1111
use crate::reinterpret::ByteRepr;
12+
use crate::va_args::VaArg;
1213
use crate::void::{AnyPtr, ErasedPtr};
1314

1415
pub enum ArgRepr {
@@ -126,6 +127,16 @@ impl FnPtrArg for AnyPtr {
126127
}
127128
}
128129

130+
impl FnPtrArg for Box<[VaArg]> {
131+
#[inline]
132+
fn to_repr(self) -> ArgRepr {
133+
ArgRepr::Record(Box::new(self))
134+
}
135+
fn from_repr(r: ArgRepr) -> Self {
136+
record_from_repr(r)
137+
}
138+
}
139+
129140
impl<T: ?Sized + 'static> FnPtrArg for *mut T {
130141
#[inline]
131142
fn to_repr(self) -> ArgRepr {

‎rule-preprocessor/src/syntactic.rs‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use cfg_expr::Expression;
55
use cfg_expr::expr::{Predicate, TargetPredicate};
6-
use ra_ap_syntax::ast::{HasAttrs, HasGenericParams, HasName, HasTypeBounds};
6+
use ra_ap_syntax::ast::{HasAttrs, HasGenericArgs, HasGenericParams, HasName, HasTypeBounds};
77
use ra_ap_syntax::{AstNode, SyntaxKind, ast, match_ast};
88
use std::collections::BTreeMap;
99
use std::path::{Path, PathBuf};
@@ -41,8 +41,13 @@ fn pointer_flags(ty: &ast::Type) -> (bool, bool) {
4141
}
4242

4343
fn is_va_args_type(ty: &ast::Type) -> bool {
44-
if let ast::Type::RefType(r) = ty
45-
&& let Some(ast::Type::SliceType(slice)) = r.ty()
44+
if let ast::Type::PathType(boxed) = ty
45+
&& let Some(segment) = boxed.path().and_then(|p| p.segment())
46+
&& segment.name_ref().is_some_and(|name| name.text() == "Box")
47+
&& let Some(ast::GenericArg::TypeArg(arg)) = segment
48+
.generic_arg_list()
49+
.and_then(|args| args.generic_args().next())
50+
&& let Some(ast::Type::SliceType(slice)) = arg.ty()
4651
{
4752
return matches!(slice.ty(), Some(ast::Type::PathType(path))
4853
if path

‎rules/fcntl/tgt_refcount.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use libcc2rs::*;
55

6-
fn f1(a0: i32, a1: i32, va: &[VaArg]) -> i32 {
6+
fn f1(a0: i32, a1: i32, va: Box<[VaArg]>) -> i32 {
77
let __res = match a1 {
88
::libc::F_GETFL => FdRegistry::with_fd(a0, |__fd| {
99
nix::fcntl::fcntl(__fd, nix::fcntl::FcntlArg::F_GETFL)
@@ -34,7 +34,7 @@ fn f1(a0: i32, a1: i32, va: &[VaArg]) -> i32 {
3434
}
3535
}
3636

37-
fn f2(a0: Ptr<i8>, a1: i32, va: &[VaArg]) -> i32 {
37+
fn f2(a0: Ptr<i8>, a1: i32, va: Box<[VaArg]>) -> i32 {
3838
let __mode = match va.first() {
3939
Some(__m) => nix::sys::stat::Mode::from_bits_truncate(i32::get(__m) as ::libc::mode_t),
4040
None => nix::sys::stat::Mode::empty(),

‎rules/ioctl/tgt_refcount.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use libcc2rs::*;
55

6-
fn f1(a0: i32, a1: u64, va: &[VaArg]) -> i32 {
6+
fn f1(a0: i32, a1: u64, va: Box<[VaArg]>) -> i32 {
77
panic!(
88
"ioctl is not supported in the refcount model (fd={}, request={}, varargs={})",
99
a0,

‎rules/stdio/tgt_refcount.rs‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ fn f20(a0: i32, a1: Ptr<i8>) -> Ptr<CFile> {
161161
Ptr::alloc(CFile::new(a0))
162162
}
163163

164-
fn f21(a0: Ptr<i8>, a1: usize, a2: Ptr<i8>, va: &[VaArg]) -> i32 {
165-
let __s = libcc2rs::format_c(&a2.to_rust_string(), va);
164+
fn f21(a0: Ptr<i8>, a1: usize, a2: Ptr<i8>, va: Box<[VaArg]>) -> i32 {
165+
let __s = libcc2rs::format_c(&a2.to_rust_string(), &va);
166166
let __b = __s.as_bytes();
167167
if a1 > 0 {
168168
let __n = ::std::cmp::min(__b.len(), a1 - 1);
@@ -190,12 +190,12 @@ fn f24(a0: Ptr<CFile>, a1: Ptr<i8>, a2: i32, a3: usize) -> i32 {
190190
0
191191
}
192192

193-
fn f28(a0: Ptr<CFile>, a1: Ptr<i8>, va: &[VaArg]) -> i32 {
194-
let __s = libcc2rs::format_c(&a1.to_rust_string(), va);
193+
fn f28(a0: Ptr<CFile>, a1: Ptr<i8>, va: Box<[VaArg]>) -> i32 {
194+
let __s = libcc2rs::format_c(&a1.to_rust_string(), &va);
195195
a0.with_mut(|__f| __f.write(__s.as_bytes())) as i32
196196
}
197197

198-
fn f29(a0: Ptr<i8>, va: &[VaArg]) -> i32 {
199-
let __s = libcc2rs::format_c(&a0.to_rust_string(), va);
198+
fn f29(a0: Ptr<i8>, va: Box<[VaArg]>) -> i32 {
199+
let __s = libcc2rs::format_c(&a0.to_rust_string(), &va);
200200
libcc2rs::c_stdout().with_mut(|__f| __f.write(__s.as_bytes())) as i32
201201
}

‎tests/ub/out/refcount/fd_double_close.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub fn main() {
1212
}
1313
fn main_0() -> i32 {
1414
let mut fd: i32 = {
15-
let __mode = match &[].first() {
15+
let __mode = match Box::<[VaArg]>::from([]).first() {
1616
Some(__m) => nix::sys::stat::Mode::from_bits_truncate(i32::get(__m) as ::libc::mode_t),
1717
None => nix::sys::stat::Mode::empty(),
1818
};

0 commit comments

Comments
 (0)