https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94770
--- Comment #7 from Jakub Jelinek <jakub at gcc dot gnu.org> --- So, does: struct empty_base {}; struct S : public empty_base { struct{}a[1]; }; S s, a[5]; __attribute__((noipa)) void foo (int x, ...) { __builtin_va_list ap; __builtin_va_start (ap, x); if (x != 1 && x != 2) __builtin_abort (); if (__builtin_va_arg (ap, double) != 1.0) __builtin_abort (); if (x == 1) __builtin_va_arg (ap, S); if (__builtin_va_arg (ap, long long) != 2LL) __builtin_abort (); if (x == 1) { __builtin_va_arg (ap, S); __builtin_va_arg (ap, S); } __builtin_va_end (ap); } int main () { foo (1, 1.0, s, 2LL, a[2], a[2]); foo (2, 1.0, 2LL); } FAIL too? Seems the va_arg (sp, S); don't do anything, i.e. not to expect the empty class with empty base to be passed at all, but on the caller side it makes a change: The first arg is passed in %ecx, second in both %xmm1 and %rdx it seems, and 2LL is passed in %r9 in the first call to foo and in $r8 in the second one. Now, the question is what MSCV or other compilers do (e.g. clang), if they match what GCC does on the caller side, or on the va_arg side (guess one needs to sed -i -e 's/__builtin_//g;s/__attribute__((noipa)) //' in the testcase, and add #include <cstdarg> and #include <cstdlib>. Seems even empty bases aren't needed, as struct S { struct{}a[1]; }; is treated the same, or even just struct S {};