Skip to content

Commit 6ede792

Browse files
committed
transpile: fix variadics in edition 2024
In edition 2024 (more specifically, in rust-lang/rust#141980), `VaListImpl` was removed, folding the functionality all into a single `VaList` and moving the pass-by-value distinction into the compiler. Thus, we replace `VaListImpl` with `VaList` and `.as_va_list()` with `.clone()`.
1 parent 6f837e0 commit 6ede792

13 files changed

Lines changed: 56 additions & 38 deletions

File tree

c2rust-transpile/src/convert_type.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::translator::variadic::mk_va_list_ty;
66
use crate::TranspilerConfig;
77
use crate::{CrateSet, ExternCrate};
88
use c2rust_ast_builder::{mk, properties::*};
9+
use c2rust_rust_tools::RustEdition;
910
use failure::format_err;
1011
use indexmap::IndexSet;
1112
use std::collections::{HashMap, HashSet};
@@ -19,6 +20,7 @@ enum FieldKey {
1920
}
2021

2122
pub struct TypeConverter {
23+
pub edition: RustEdition,
2224
pub translate_valist: bool,
2325
renamer: Renamer<CDeclId>,
2426
fields: HashMap<CDeclId, Renamer<FieldKey>>,
@@ -136,6 +138,7 @@ pub const RESERVED_NAMES: [&str; 100] = [
136138
impl TypeConverter {
137139
pub fn new(tcfg: &TranspilerConfig) -> TypeConverter {
138140
TypeConverter {
141+
edition: tcfg.edition,
139142
translate_valist: tcfg.translate_valist,
140143
renamer: Renamer::new(&RESERVED_NAMES),
141144
fields: HashMap::new(),
@@ -313,7 +316,7 @@ impl TypeConverter {
313316
ctype: CTypeId,
314317
) -> TranslationResult<Box<Type>> {
315318
if self.translate_valist && ctxt.is_va_list(ctype) {
316-
return Ok(mk_va_list_ty(None));
319+
return Ok(mk_va_list_ty(self.edition, None));
317320
}
318321

319322
match ctxt.index(ctype).kind {

c2rust-transpile/src/translator/builtins.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ impl<'c> Translation<'c> {
360360
"__builtin_va_end" => {
361361
if ctx.is_unused() && args.len() == 1 {
362362
if let Some(_va_id) = self.match_vaend(args[0]) {
363-
// nothing to do since `VaListImpl`s get `Drop`'ed.
363+
// nothing to do since the translated Rust `va_list` values get `Drop`'ed.
364364
return Ok(WithStmts::new_val(self.panic("va_end stub")));
365365
}
366366
}

c2rust-transpile/src/translator/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use crate::rust_ast::item_store::ItemStore;
3232
use crate::rust_ast::set_span::SetSpan;
3333
use crate::rust_ast::{pos_to_span, SpanExt};
3434
use crate::translator::named_references::NamedReference;
35-
use crate::translator::variadic::{mk_va_list_ty, mk_va_list_copy};
35+
use crate::translator::variadic::{mk_va_list_copy, mk_va_list_ty};
3636
use c2rust_ast_builder::{mk, properties::*, Builder};
3737
use c2rust_ast_printer::pprust;
3838

@@ -2944,9 +2944,9 @@ impl<'c> Translation<'c> {
29442944
.unwrap_or_else(|| panic!("Failed to insert variable '{}'", ident));
29452945

29462946
if self.ast_context.is_va_list(typ.ctype) {
2947-
// translate `va_list` variables to `VaListImpl`s and omit the initializer.
2947+
// Translate `va_list` variables to the current Rust `va_list` type and omit the initializer.
29482948
let pat_mut = mk().mutbl().ident_pat(rust_name);
2949-
let ty = mk_va_list_ty(None);
2949+
let ty = mk_va_list_ty(self.tcfg.edition, None);
29502950
let local_mut = mk().local(pat_mut, Some(ty), None);
29512951

29522952
return Ok(cfg::DeclStmtInfo::new(
@@ -4250,7 +4250,7 @@ impl<'c> Translation<'c> {
42504250
{
42514251
// No `override_ty` to avoid unwanted casting.
42524252
val = self.convert_expr(ctx, expr_id, None)?;
4253-
val = val.map(mk_va_list_copy);
4253+
val = val.map(|val| mk_va_list_copy(self.tcfg.edition, val));
42544254
} else {
42554255
val = self.convert_expr(ctx, expr_id, override_ty)?;
42564256
}

c2rust-transpile/src/translator/structs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,7 @@ impl<'a> Translation<'a> {
752752
// TODO: handle or panic on structs with more than one va_list?
753753
let is_va_list = self.ast_context.is_va_list(ctype);
754754
let mut ty = if is_va_list {
755-
mk_va_list_ty(Some("a"))
755+
mk_va_list_ty(self.tcfg.edition, Some("a"))
756756
} else {
757757
self.convert_type(ctype)?
758758
};

c2rust-transpile/src/translator/variadic.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,36 @@ macro_rules! match_or {
2222
};
2323
}
2424

25-
pub fn mk_va_list_ty(lifetime: Option<&str>) -> Box<Type> {
25+
pub fn mk_va_list_ty(edition: RustEdition, lifetime: Option<&str>) -> Box<Type> {
26+
// This was updated in <https://github.com/rust-lang/rust/pull/141980>,
27+
// first changed in `nightly-2025-12-07`.
28+
// `VaListImpl` was removed.
29+
let name = if edition < Edition2024 {
30+
"VaListImpl"
31+
} else {
32+
"VaList"
33+
};
2634
let lifetime_args = match lifetime {
2735
None => vec![],
2836
Some(lifetime) => vec![mk().lifetime(lifetime)],
2937
};
3038
mk().abs_path_ty(vec![
3139
mk().path_segment("core"),
3240
mk().path_segment("ffi"),
33-
mk().path_segment_with_args("VaListImpl", mk().angle_bracketed_args(lifetime_args)),
41+
mk().path_segment_with_args(name, mk().angle_bracketed_args(lifetime_args)),
3442
])
3543
}
3644

37-
pub fn mk_va_list_copy(va_list: Box<Expr>) -> Box<Expr> {
38-
mk().method_call_expr(va_list, "as_va_list", vec![])
45+
pub fn mk_va_list_copy(edition: RustEdition, va_list: Box<Expr>) -> Box<Expr> {
46+
// This was updated in <https://github.com/rust-lang/rust/pull/141980>,
47+
// first changed in `nightly-2025-12-07`.
48+
// `VaListImpl` was removed and `.as_va_list()` was replaced with `.clone()`.
49+
let name = if edition < Edition2024 {
50+
"as_va_list"
51+
} else {
52+
"clone"
53+
};
54+
mk().method_call_expr(va_list, name, vec![])
3955
}
4056

4157
impl<'c> Translation<'c> {
@@ -248,7 +264,7 @@ impl<'c> Translation<'c> {
248264
/// Update the current function context by
249265
/// * enabling the C variadics feature
250266
/// * naming the Rust function argument that corresponds to the ellipsis in the original C function
251-
/// * building a list of variable declarations to be translated into `VaListImpl`s.
267+
/// * building a list of variable declarations to be translated into the current Rust `va_list` type.
252268
///
253269
/// Returns the name of the `VaList` function argument for convenience.
254270
pub fn register_va_decls(&self, body: CStmtId) -> String {

c2rust-transpile/tests/snapshots.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,6 @@ fn test_wide_strings() {
468468
#[test]
469469
fn test_varargs() {
470470
transpile("varargs.c")
471-
.expect_compile_error_edition_2024(cfg!(target_os = "linux"))
472471
.arch_specific(true)
473472
.os_specific(true)
474473
.run();

c2rust-transpile/tests/snapshots/snapshots__transpile@varargs.c.2024.x86_64.linux.snap

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub type size_t = usize;
3333
#[derive()]
3434
#[repr(C)]
3535
pub struct vastruct<'a> {
36-
pub args: ::core::ffi::VaListImpl<'a>,
36+
pub args: ::core::ffi::VaList<'a>,
3737
}
3838
#[unsafe(no_mangle)]
3939
pub unsafe extern "C" fn call_printf() {
@@ -48,20 +48,20 @@ pub unsafe extern "C" fn my_vprintf(
4848
mut format: *const ::core::ffi::c_char,
4949
mut ap: ::core::ffi::VaList,
5050
) {
51-
vprintf(format, ap.as_va_list());
51+
vprintf(format, ap.clone());
5252
}
5353
#[unsafe(no_mangle)]
5454
pub unsafe extern "C" fn call_vprintf(
5555
mut format: *const ::core::ffi::c_char,
5656
mut c2rust_args: ...
5757
) {
58-
let mut ap: ::core::ffi::VaListImpl;
58+
let mut ap: ::core::ffi::VaList;
5959
ap = c2rust_args.clone();
60-
my_vprintf(format, ap.as_va_list());
60+
my_vprintf(format, ap.clone());
6161
}
6262
#[unsafe(no_mangle)]
6363
pub unsafe extern "C" fn my_printf(mut fmt: *const ::core::ffi::c_char, mut c2rust_args: ...) {
64-
let mut ap: ::core::ffi::VaListImpl;
64+
let mut ap: ::core::ffi::VaList;
6565
ap = c2rust_args.clone();
6666
while *fmt != 0 {
6767
match *fmt as ::core::ffi::c_int {
@@ -100,12 +100,12 @@ pub unsafe extern "C" fn my_printf(mut fmt: *const ::core::ffi::c_char, mut c2ru
100100
}
101101
#[unsafe(no_mangle)]
102102
pub unsafe extern "C" fn simple_vacopy(mut fmt: *const ::core::ffi::c_char, mut c2rust_args: ...) {
103-
let mut ap: ::core::ffi::VaListImpl;
104-
let mut aq: ::core::ffi::VaListImpl;
103+
let mut ap: ::core::ffi::VaList;
104+
let mut aq: ::core::ffi::VaList;
105105
ap = c2rust_args.clone();
106106
aq = ap.clone();
107-
vprintf(fmt, ap.as_va_list());
108-
vprintf(fmt, aq.as_va_list());
107+
vprintf(fmt, ap.clone());
108+
vprintf(fmt, aq.clone());
109109
}
110110
#[unsafe(no_mangle)]
111111
pub unsafe extern "C" fn valist_struct_member(
@@ -120,8 +120,8 @@ pub unsafe extern "C" fn valist_struct_member(
120120
};
121121
a.args = c2rust_args.clone();
122122
b.args = a.args.clone();
123-
vprintf(fmt, a.args.as_va_list());
124-
vprintf(fmt, b.args.as_va_list());
123+
vprintf(fmt, a.args.clone());
124+
vprintf(fmt, b.args.clone());
125125
}
126126
#[unsafe(no_mangle)]
127127
pub unsafe extern "C" fn valist_struct_pointer_member(
@@ -138,27 +138,27 @@ pub unsafe extern "C" fn valist_struct_pointer_member(
138138
let mut q: *mut vastruct = &raw mut b;
139139
(*p).args = c2rust_args.clone();
140140
(*q).args = (*p).args.clone();
141-
vprintf(fmt, (*p).args.as_va_list());
142-
vprintf(fmt, (*q).args.as_va_list());
141+
vprintf(fmt, (*p).args.clone());
142+
vprintf(fmt, (*q).args.clone());
143143
}
144144
#[unsafe(no_mangle)]
145145
pub unsafe extern "C" fn restart_valist(mut fmt: *const ::core::ffi::c_char, mut c2rust_args: ...) {
146-
let mut ap: ::core::ffi::VaListImpl;
146+
let mut ap: ::core::ffi::VaList;
147147
ap = c2rust_args.clone();
148-
vprintf(fmt, ap.as_va_list());
148+
vprintf(fmt, ap.clone());
149149
ap = c2rust_args.clone();
150-
vprintf(fmt, ap.as_va_list());
150+
vprintf(fmt, ap.clone());
151151
}
152152
#[unsafe(no_mangle)]
153-
pub unsafe extern "C" fn print_int(mut ap: *mut ::core::ffi::VaListImpl) {
153+
pub unsafe extern "C" fn print_int(mut ap: *mut ::core::ffi::VaList) {
154154
printf(
155155
b"%d\0".as_ptr() as *const ::core::ffi::c_char,
156156
(*ap).arg::<::core::ffi::c_int>(),
157157
);
158158
}
159159
#[unsafe(no_mangle)]
160160
pub unsafe extern "C" fn borrowed_valist(mut count: size_t, mut c2rust_args: ...) {
161-
let mut ap: ::core::ffi::VaListImpl;
161+
let mut ap: ::core::ffi::VaList;
162162
ap = c2rust_args.clone();
163163
while count > 0 as size_t {
164164
print_int(&raw mut ap);

tests/unit/items/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "items-tests"
33
version = "0.1.0"
4-
edition = "2021"
4+
edition = "2024"
55

66
[dependencies]

tests/unit/items/src/test_fn_attrs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ unsafe extern "C" fn rust_gnu_inline_non_canonical_definition_extern
164164
let aliased_fn_syntax = |public| {
165165
format!(
166166
r#"
167-
extern "C" {{
167+
unsafe extern "C" {{
168168
#[link_name = "inline_extern"]
169169
{}fn aliased_fn();
170170
"#,

tests/unit/items/src/test_functions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::functions::rust_coreutils_static_assert;
22

33
#[link(name = "test")]
4-
extern "C" {
4+
unsafe extern "C" {
55
fn coreutils_static_assert();
66
}
77

0 commit comments

Comments
 (0)