Skip to content

Commit 3f96cef

Browse files
[wasm] Add support for __builtin_va_list type mapping (#84029)
Cover all va_list family of types just aliased by __builtin_va_list, including __isoc_va_list from wasi-libc. This enables proper C interop for variable argument functions on WASI targets. Close #72398
1 parent 6e56c24 commit 3f96cef

File tree

5 files changed

+52
-0
lines changed

5 files changed

+52
-0
lines changed

lib/ClangImporter/MappedTypes.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ MAP_STDLIB_TYPE("u_int64_t", UnsignedInt, 64, "UInt64", false, DoNothing)
129129
MAP_STDLIB_TYPE("va_list", VaList, 0, "CVaListPointer", false, DoNothing)
130130
MAP_STDLIB_TYPE("__gnuc_va_list", VaList, 0, "CVaListPointer", false, DoNothing)
131131
MAP_STDLIB_TYPE("__va_list", VaList, 0, "CVaListPointer", false, DoNothing)
132+
// Cover all va_list family of types just aliased by __builtin_va_list, including
133+
// __isoc_va_list from wasi-libc.
134+
MAP_STDLIB_TYPE("__builtin_va_list", VaList, 0, "CVaListPointer", false, DoNothing)
132135

133136
// libkern/OSTypes.h types.
134137
MAP_STDLIB_TYPE("UInt", UnsignedInt, 32, "CUnsignedInt", false, DoNothing)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <stdarg.h>
2+
extern void takeVaList(va_list args);
3+
4+
extern void takeVaList2(__builtin_va_list args);
5+
6+
typedef __builtin_va_list my_builtin_va_list_alias;
7+
extern void takeVaList3(my_builtin_va_list_alias args);

test/ClangImporter/Inputs/custom-modules/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,8 @@ module Aliases {
283283
module RetroactiveVersioning {
284284
header "versioning.h"
285285
}
286+
287+
module CVarArgs {
288+
header "CVarArgs.h"
289+
export *
290+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %swift-frontend -target wasm32-unknown-wasip1 -parse-stdlib -module-name Swift -I %S/Inputs/custom-modules -typecheck %s
2+
3+
// REQUIRES: CODEGENERATOR=WebAssembly
4+
5+
import CVarArgs
6+
7+
/// ===== Minimal stdlib definitions =====
8+
typealias Void = ()
9+
struct CVaListPointer {}
10+
// Optional definition is required for isOptional check in ClangImporter
11+
enum Optional<T> {}
12+
/// ======================================
13+
14+
func testVaList() {
15+
let _: (CVaListPointer) -> Void = CVarArgs.takeVaList
16+
let _: (CVaListPointer) -> Void = CVarArgs.takeVaList2
17+
let _: (CVaListPointer) -> Void = CVarArgs.takeVaList3
18+
}

test/stdlib/VarArgs.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,25 @@ func test_varArgs7() {
193193
}
194194
test_varArgs7()
195195

196+
func test_varArgs8() {
197+
// Check with vsnprintf as well just in case to make sure it works with C APIs
198+
// imported from actual libc headers. Why checks with vprintf above are not enough?
199+
// ClangImporter respects the vprintf interface re-defined in LibcShims.h but it could
200+
// be slightly different than the one in platform libc on some platforms, including WASI.
201+
// (e.g. wasi-libc defines `int vprintf(const char *__restrict, __isoc_va_list);` where
202+
// `__isoc_va_list` is `typedef __builtin_va_list __isoc_va_list;`, but LibcShims.h aliases
203+
// __builtin_va_list as `va_list`.)
204+
// https://github.com/swiftlang/swift/issues/72398
205+
let string = withUnsafeTemporaryAllocation(of: CChar.self, capacity: 512) { buffer in
206+
withVaList([CInt(123)]) { args in
207+
_ = vsnprintf(buffer.baseAddress!, buffer.count, "%d", args)
208+
}
209+
return String(cString: buffer.baseAddress!)
210+
}
211+
print(string)
212+
// CHECK: 123
213+
}
214+
test_varArgs8()
196215

197216
// CHECK: done.
198217
my_printf("done.")

0 commit comments

Comments
 (0)