<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=http://email.email.llvm.org/c/eJylVctu4zgQ_Br7QkSQJT8PPiQZGAiwxwEGcwooqmVxliK1JGXH-fqtpiXHySz2sAvoYZPNflRXlypXX_Y_WrKilyFoexRSvJN3wpA9xlaE6AcVZ8WzCINqhQxYqWflIy7s0Gu89MS7ykh7nBVPuISSVqjWuUAiOmFdFL13J12TwIb0x6EjG0XjvIgtCer6eBnjCInLmEx8b3UQHUkbYMOL9nI7GYRsIv3D4bM2RpCtxdALjUii1k1DnoMZp2TUzrI3ewsdZEeiGaxKW2dGQbmu14ZqOEP1R6WyWf5tlj9en99xaHKqKKQoIVBXmUuquoJPghestzH2gYEqDriOrq6ciZnzAOnwjvvnyW7WP3_8evsU4DBl1pPSjVZiAIhK4nFuNfB_Ea08jUESMBw1psQlm-oQBgrckC_xUc1QZaiO_yj10Gnvnb_-wbMyrsKrXq2XclvWi2WxKupNXeWLcrtoNotdnlcbud6Wq802L9nU6ApMwNkVNx2Ph1OJZW2VGWpilzoikUMrQxtlZei1d0arS9bOivKP7TYXoXVn9FIYbYkRu3lMJEI3PInB6r_Asj_pAl_bWbETnuLgQQtCRSDB72wU7m61kSZ8kFSCG5GZFciQApEqimeGUt6xgPvOhvzDDaCeiF5qk0ZjZGAmXhrmRrJLzBeVw7GRPCgmRGmjTpQLwjXXqBFsNTKSQCk6owyr3g3HNjUZRvIj78E6XwOA-jVQ_FTRx04nE83j2d0RPbQSe4yll15fqcCE0hYj4_rElwblCN2MmSsMHDMZo8qGXNYEBh9G7JNWJE7kg-TMa-oxYxzL2THOBfMla5ESm3D-MibaAkHNErH7MlEAhjuiO22kZ8H4F-Yac5peD9CUX8TSdJhIfyjWm8WCE6jQNzhl6fHEkNdiLO851cvNVM6eUMVYpmShYcalY1NHZuuc3gCcReHFM24sCDb7VMMT934Svxslpv9IDiozqthnwdKJG0G_I5gFHz5E5nk8_QIe6aETj08vUKtL4Aa8gLZG04lGVjmWHa5NOe-BSDL2NKI_wSE7DFMYPBZ2DO41_6J4vKkqUrlmh_QD_GJoJvUFLoyldfYhen3S0tw0tB98D6VPx69UYmv-mAB0e0dNSGTjXccs0ZY5k8JQyJDEvN6X9a7cybkcMHV-r5oQCSWY-eDN_r8zYlXm68W83W-qslRFAf1SS1LVernb0oqKxYLfVb2bGwlQw362AuyFpfNVSbnjq2_z_5-B3hd5UeSLfIO7LPOsQehlkW839TqH1C5ny5w6zGXGfvgzMff75LIajgGbRocYPjb5W320RClhZBh1NLSfWMME6HToZMQnY9K4z3p1vv_k35My8FiXhYB8i7ftep4K2acq_gbM1MJD>53061</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            C++ ABI mismatch between gcc and clang when passing empty structs on 32 bit x86
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          cfsteefel
      </td>
    </tr>
</table>

<pre>
    When passing a zero length struct, such as std::true_type, clang++ can choose to not provide an argument for the empty struct at all. This means that any arguments after the empty struct will end up in a different location than for the same function when compiled with gcc.

The differences in assembly can be seen in https://godbolt.org/z/Yvn76YWjx.

For the specific use case which I have seen that can then cause issues, https://github.com/gcc-mirror/gcc/blob/d564a83d14252d7db01381f71900b7a68357803b/libstdc%2B%2B-v3/include/bits/hashtable_policy.h#L880 shows a line in libstdc++ where unique_keys() returns either std::true_type or std::false_type, and this selects between a function with and without a trailing argument. If gcc and clang both compile instantiations of this template (i.e. through use of a std::unordered_set or std::unordered_map in two different shared libraries, the interop can fail if clang calls into the gcc function, or vice versa (dependent on library load order, and differences in inlining).

This is similar to https://github.com/llvm/llvm-project/issues/26711, but is not related to the C calling convention, as there is no use of `extern "C"` here.

Both g++ and clang++ assume that an empty struct is of size one. 
The C++ Itanium ABI says (I believe this to be the correct ABI reference, but am unsure):
"Arguments of empty class types that are not non-trivial for the purposes of calls are passed no differently from ordinary classes."
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJydVctu4zgQ_Br7QsTQw8-DD0kGBgLscYDBnAKKalmcoUgNSdlxvn6raclxsos9LCDJFtnsR3V1qXL1Zf-jJSt6GYK2RyHFO3knDNljbEWIflBxVjyLMKhWyICVelY-4sIOvcZLT7yrjLTHWfGESyhphWqdCySiE9ZF0Xt30jUJbEh_HDqyUTTOi9iSoK6PlzGOkLiMWYjvrQ6iI2kDbHjRXm4ng5BNpH85fNbGCLK1GHqhEUnUumnIczDjlIzaWfZmb6GD7Eg0g1Vp68woKNf12lANZ6j-qNRiln2bZY_X53ccmpwqCilKCNRV5pKqruCT4AXrbYx9YKCKA66jqytn4sJ5gHR4x_3zZDfrnz9-vX0KcJgy60npRisxAEQl8Ti3Gvi_iFaexiAJGI4aU-KSTXUIAwVuyJf4qGaoFqiOX5R66LT3zl9f8KyMq_BTr9ZLuS3rfFmsinpTV1lebvNmk--yrNrI9bZcbbZZyaZGV2ACzq646Xg8nEosa6vMUBO71BGJHFoZ2igrQ6-9M1pdFu2sKP_abjMRWndGL4XRlhixm8dEInTDkxis_gOW_aYLfG1nxU54ioMHLQgVgQT_ZKNwd6uNNOGDpBLciMysQIYUiFRRPDOU8o4F3Hc25D9uAPVE9FKbNBojAxfipWFuJLvEfFE5HBvJg2JClDbqRLkgXHONGsFWIyMJlKIXtMCqd8OxTU2GkfzIe7DO1wCgfg0UP1X0sdPJRPN4dndED63EHmPppddXKjChtMXIuD7xpUE5Qjdj5goDx0zGqLIhlzWBwYcR-6QViRP5IDnzmnrMGMdydoxzwXzJWqTEJpy_jIm2QFCzROy-TBSA4Y7oThvpWTD-g7nGnKafB2jKL2JpOkykPxTrTZ5zAhX6BqcsPZ4Y8lqM5T2nermZytkTqhjLlCw0zLh0bOrIbJ3RG4CzKLx4xo0FwWafanji3k_id6PE9I7koDKjin0WLJ24EfQ7glnw4UNknsfTL-CRHjrx-PQCtboEbsALaGs0nWhklWPZ4dqU8x6IJGNPI_oTHLLDMIXBY2HH4F7zL4rHm6oilWt2SD_AL4ZmUl_gwlhaZx-i1yctzU1D-8H3UPp0_EoltuaPCUC3d9SERDbedcwSbZkzKQyFBZKY1_uy3pU7OY86GtpP5XMlnQ6djNC-aVg_D975_tt1j25gfpaFgA6Jt-16Pniz___UWpXZOp-3-zJfVXm2qde0LJer5bJe5vW6KuWOlqTkupkbie6E_WyFAgpL56skM3VW3-Z6X2RFkcEB7rLMFk2e75ZFtoXDDIq7nC0z6jCeC86DvxZzv08pVcMxYNPoEMPHJpd9tEQpHPzLAZrl96oJkUAAM0_B9yn5vwH31qzw">