https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82693
Bug ID: 82693 Summary: gcc/clang calling convension mismatch Product: gcc Version: 7.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: vanyacpp at gmail dot com Target Milestone: --- Recently I have discovered that empty arguments are passed differently by gcc and by clang. struct empty {}; void f(empty, empty, empty); int main() { f(empty{}, empty{}, empty{}); } GCC pushed 0 to stack for each empty struct while clang does nothing. main(GCC): sub rsp, 16 xor eax, eax push rax push rax push rax call f(empty, empty, empty) xor eax, eax add rsp, 40 ret main(clang): push rax call f(empty, empty, empty) xor eax, eax pop rcx ret I would say that I like the code generated by clang more. As the struct is empty no value needs to be passed. In a case the callee needs to take the address of the argument it can allocate the argument in its own frame as the argument is passed by value. As the code generated differs I wondered if I can construct an example where parameters get wrong values because of this. Turned out it wasn't very difficult. The following program struct empty {}; struct big { int a; int b; int c; int d; int e; }; void print_7th(empty, empty, empty, empty, empty, empty, big seventh) { std::cout << seventh.a << ' ' << seventh.b << ' ' << seventh.c << ' ' << seventh.d << ' ' << seventh.e << std::endl; } int main() { empty e; print_7th(e, e, e, e, e, e, big{1, 2, 3, 4, 5}); } prints different output when print_7th and main are compiled with different compilers: ./gcc-to-gcc 1 2 3 4 5 ./clang-to-gcc 5 32767 0 0 635911936 ./gcc-to-clang 192 0 -1204279016 32765 1 ./clang-to-clang 1 2 3 4 5 Another easy way to see that compilers pass arguments differently is compiling this code: int sum(empty, empty, empty, empty, empty, empty, big seventh) { return seventh.a + seventh.b + seventh.c + seventh.d + seventh.e; } GCC generates: sum: mov eax, DWORD PTR [rsp+60] add eax, DWORD PTR [rsp+56] add eax, DWORD PTR [rsp+64] add eax, DWORD PTR [rsp+68] add eax, DWORD PTR [rsp+72] ret while clang generates: sum: mov eax, dword ptr [rsp + 12] add eax, dword ptr [rsp + 8] add eax, dword ptr [rsp + 16] add eax, dword ptr [rsp + 20] add eax, dword ptr [rsp + 24] ret I don't know which compiler is right in this case and which conform to SysV ABI better. I would prefer GCC to adopt clang behavior as it is more efficient. Because if we have two popular major compilers that both are widely used and are incompatible with each other and we have to break compatibility of one of them it's better to choose the better alternative. Also using empty struct as parameters is common in C++ code, and it's great to make them free.