On C compilers, the library never defines the va_list type itself, the compiler always provides the full definition.
In D, we already generate the va_list type internally (Target.tvalist), this can be exposed to importC as a `__builtin_valist` keyword to support stdio.h and stdarg.h, which have these definitions:
---
typedef __builtin_va_list va_list;
typedef __builtin_va_list __gnuc_va_list;
---
Comment #1 by ibuclaw — 2021-05-25T17:39:51Z
On a note of hindsight, the original location of tvalist being in Type was in-fact a good thing, and moving the type to Target will result in a bit of manoeuvring to keep the dmd.cparse happily isolated.
Comment #2 by ibuclaw — 2021-07-05T18:15:47Z
Current workaround is to add `typedef` declarations in the "wrapper" sources.
Comment #3 by bugzilla — 2021-07-16T08:47:36Z
What is the typedef you've added to the wrapper sources?
Comment #4 by bugzilla — 2021-07-16T09:14:14Z
As you say, it's problematic to add the __builtin_va_list to cparse, as cparse does not have access to the types.
A simple approach is to have the semantic routines start by adding the declaration for it, rather than cparse.
Comment #5 by ibuclaw — 2021-07-16T09:40:35Z
(In reply to Walter Bright from comment #3)
> What is the typedef you've added to the wrapper sources?
For testing purposes.
---
/* Provide user declarations of the built-in va_list type. */
#if defined(__i386__)
typedef char* __builtin_va_list;
#elif defined(__x86_64__)
typedef struct
{
unsigned gp_offset;
unsigned fp_offset;
void *overflow_arg_area;
void *reg_save_area;
} __builtin_va_list[1];
#else
#error "unsupported"
#endif
---
It's not the only `__builtin_` that I've written something to provide for.
e.g:
---
#define __builtin_bswap16(x) \
((u_int16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)))
#define __builtin_bswap32(x) \
((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) \
| (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24))
#define __builtin_bswap64(x) \
((((x) & 0xff00000000000000ull) >> 56) \
| (((x) & 0x00ff000000000000ull) >> 40) \
| (((x) & 0x0000ff0000000000ull) >> 24) \
| (((x) & 0x000000ff00000000ull) >> 8) \
| (((x) & 0x00000000ff000000ull) << 8) \
| (((x) & 0x0000000000ff0000ull) << 24) \
| (((x) & 0x000000000000ff00ull) << 40) \
| (((x) & 0x00000000000000ffull) << 56))
---
I'm currently on the fence really whether we should open the gates for handling `__builtin_` symbols.
Comment #6 by bugzilla — 2021-07-17T06:47:46Z
Those last three look like they were added before gcc could handle inline functions.
Comment #7 by bugzilla — 2021-07-17T07:09:57Z
One theory is if a declaration can be supplied by the library or some source file, it should *not* be built in to the compiler. This:
1. reduces the complexity of the compiler
2. makes it editable by the user
3. means updates can be done without altering the compiler
4. makes it unnecessary to get it to match every version of every C compiler out there
We do this in D by automatically importing object.d.
I already believe we'll have to supply such a file anyway simply to deal with all the 400 predefines that gcc generates.
Comment #8 by ibuclaw — 2021-07-18T20:42:26Z
(In reply to Walter Bright from comment #6)
> Those last three look like they were added before gcc could handle inline
> functions.
More like, it existed before gcc recognized bswap as an intrinsic.
The original code from bits/byteswap.h:
---
static __inline __uint32_t
__bswap_32 (__uint32_t __bsx)
{
#if __GNUC_PREREQ (4, 3)
return __builtin_bswap32 (__bsx);
#else
return __bswap_constant_32 (__bsx);
#endif
}
---
https://github.com/dlang/dmd/pull/13107 solves the specific __builtin_va_list problem, but not the general problem.
The general problem could be addressed by importing core.stdc.stdarg into the C semantic routines and thereby hijacking the D implementation for use with the C code.