Repository navigation
Description
Hi,
General context of this work is in #188, including the AI-disclaimers.
No in-tree codec is affected by this issue; no std public function returns a struct of its package. Claude judges the prospective risk of it as "low": the C compiles, but C++ compilation fails under MSVC and clang with -Werror.
The following is Sol 6.1's writeup of the issue. Includes a repro, the generated declaration order, compiler diagnostics, and compile results from gcc 13.3 as C, clang++ 18 and g++ 13.3 as C++, and MSVC as C and C++. The cause is reasoned from source.
cgen writes public function prototypes inside extern "C", before the struct definitions. A public function without a receiver that returns a struct of its package is therefore declared with C linkage while the struct is incomplete, and in C++ that struct is a class with member functions.
Minimal repro:
pub struct repro?(
v : base.u32,
)
pub func f(x: base.u32) repro {
var t : repro
return t
}
Actual: at b36a81d3, wuffs-c gen -package_name repro plain_arg.wuffs exits 0 with empty stderr. The header declares wuffs_repro__repro wuffs_repro__f(uint32_t a_x); at line 63, inside the extern "C" block on lines 25 to 66, and defines struct wuffs_repro__repro__struct at line 78.
As C, gcc 13.3 -Wall -Werror and MSVC compile it. As C++, with only the base and repro modules enabled, g++ 13.3 accepts it, clang++ 18 warns and fails with -Werror, and MSVC /TP fails with exit code 2:
plain_arg-release.c:7939:1: error: 'wuffs_repro__f' has C-linkage specified, but returns incomplete type 'wuffs_repro__repro' (aka 'wuffs_repro__repro__struct') which could be incompatible with C [-Werror,-Wreturn-type-c-linkage]
plain_arg-release.c(7939): error C2526: 'wuffs_repro__f': C linkage function cannot return C++ class 'wuffs_repro__repro__struct'
plain_arg-release.c(26145): error C2556: 'wuffs_repro__repro wuffs_repro__f(uint32_t)': overloaded function differs only by return type from 'void wuffs_repro__f(uint32_t)'
Expected: declare such functions outside extern "C" for C++, after the struct definitions, or reject struct results of public functions.
Cause: public function prototypes are written inside extern "C", before the struct definitions:
Lines 848 to 866 in b36a81d
| b.writes("// ---------------- Public Function Prototypes\n\n") | |
| if err := g.forEachFunc(b, pubOnly, (*gen).writeFuncPrototype); err != nil { | |
| return err | |
| } | |
| b.writes("#ifdef __cplusplus\n} // extern \"C\"\n#endif\n\n") | |
| b.writes("// ---------------- Struct Definitions\n\n") | |
| b.writes("// These structs' fields, and the sizeof them, are private implementation\n") | |
| b.writes("// details that aren't guaranteed to be stable across Wuffs versions.\n") | |
| b.writes("//\n") | |
| b.writes("// See https://en.wikipedia.org/wiki/Opaque_pointer#C\n\n") | |
| b.writes("#if defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)\n\n") | |
| for _, n := range g.structList { | |
| if err := g.writeStruct(b, n); err != nil { | |
| return err | |
| } | |
| } |
With a refined argument, as in pub func f(x: base.u32[..= 1]) repro, the C itself fails to compile because the failed argument check writes to self (#201).
Activity