https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89592
--- Comment #6 from Richard Biener <rguenth at gcc dot gnu.org> --- I think it only makes sense to pass aggregates with a flexarray member by reference and pass the return slot by reference as well. Only the caller can know the complete type used here. This means passing by value needs to do a copy at the caller side. OTOH struct S { int i; char c[]; }; struct S foo (struct S val) { return val; } is compiled to foo: .LFB0: .cfi_startproc movl %edi, %eax ret and the C FE warns: t.c: In function ‘foo’: t.c:2:22: note: the ABI of passing struct with a flexible array member has changed in GCC 4.4 struct S foo (struct S val) { return val; } before that ABI change we had foo: .LFB2: movl 8(%rsp), %eax movl %eax, (%rdi) movq %rdi, %rax ret so it was passed on the stack and there was a return slot? The C++ compiler still produces the above with GCC 8, even when marking foo extern "C", so that's another inconsistency / bug.