<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/66117>66117</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            The combination of -fno-rtti -fexceptions is very brittle
        </td>
    </tr>

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

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

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

<pre>
    The combination of `-fno-rtti` and `-fexceptions` is not supported very well, and we've seen several issues related to that internally at Apple. This bug report captures an analysis of this issue I did years ago to try to make it visible to the larger community.

Current behaviour
================
When both these options are specified, we don't generate RTTI for types, except when a type is thrown, at which point we generate some minimal RTTI in the TU where it is thrown (I am not sure whether the "minimal RTTI is exactly the same as "normal RTTI"). Also note that we don't generate RTTI even in the place where a key function exists, and similarly we don't assume that other TUs have a definition of the RTTI when a key function exists.

Problem with the current approach
=================================
Let's say some TU `a.cpp` built with `-fno-rtti -fexceptions` calls a function (defined in some other TU) that can throw a type `E`, and tries to catch `E`. Then, let's say that function is defined in some other TU `b.cpp` built with `-frtti -fexceptions` throws a type `E`. Let's also assume that another TU `c.cpp` built with `-frtti -fexceptions` defines the RTTI for E (through a key function, for example). The problem here is that in `a.cpp`, we'll generate minimal RTTI for E, and in `b.cpp` we'll use the normal RTTI assumed to be in `c.cpp` (because there's a key function). Since the two RTTIs don't get de-duplicated, we get a type identity mismatch in `a.cpp` and `b.cpp`, and the exception isn't caught.

Here's a minimal working example:

```
#/usr/bin/env bash

cat <<EOF > a.cpp
struct E { virtual ~E(); };
extern void f();
int main() {
    try {
        f();
    } catch (E const&) { // tries catching E with RTTI from a.o

    }
}
EOF

cat <<EOF > b.cpp
struct E { virtual ~E(); };
extern void f() { throw E{}; } // throws E with RTTI from c.o
EOF

cat <<EOF > c.cpp
struct E { virtual ~E(); };
E::~E() { } // key function
EOF

clang++ a.cpp -fno-rtti -fexceptions -std=c++11 -c -o a.o
clang++ b.cpp -frtti -fexceptions -std=c++11 -c -o b.o
clang++ c.cpp -frtti -fexceptions -std=c++11 -c -o c.o
clang++ b.o c.o -shared -o b.dylib
clang++ a.o b.dylib -o a.exe
nm a.o b.o c.o a.exe b.dylib | c++filt
./a.exe
```

To map this example to reality, imagine that `E` is something like `std::exception` (or a derived class), that `b.dylib` is `libc++.dylib`, and that `a.exe` is a user program built with `-fno-rtti -fexceptions`. It becomes clear why people are having problems with the feature.

I once discussed this issue with @dexonsmith and we had discussed this potential solution:
* Add an attribute __generate_rtti__ (name TBD)
* When you’d normally generate RTTI for a type and currently suppress the RTTI generation based on whether -fno-rtti is present, instead check whether the type has the attribute and still generate full RTTI if it has it.
* When you try to throw a type with `-fno-rtti -fexceptions`, you get:
    * a warning if the type doesn’t have the attribute, and minimal RTTI gets generated (like today, for backwards compatibility)
    * the normal behaviour (like when -fno-rtti is not specified) if the type has the attribute. In particular, this means that no RTTI is generated if we can tell it’s somewhere else (e.g. when there’s a key function), and full RTTI (that the linker can dedupe) is generated when we can’t tell for sure.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJysWFtv47oR_jX0yyCGTce3Bz_kYqMBCpyizaKPwUgaW2woUiApO3rpby-GlGQ5m-3ZXZyFkWxIzu2bu9F7dTJEO7F8FMvnCTahtG6nC2WNoUlmi3b3WhLktsqUwaCsAXsEsZrdHY29cyEosZoBmiKd0UdONb_yfKw8GBvAN3VtXaACzuRauJDWQj5FogsJuT4TeCIDns7kUIPyviEPjjQyUbAQSgygTCBnUOsWMMBDXWuawmupPGTNCRyxDMixDo0jD2gADerWK88aB34XGcMLFKqAltB5wJON_F3Lvyp8J1ABzsqrTFOSTKDRncgxBlVjVGinYvYsZg_p51PjHJkAGZV4VrZx3eXi-dc-kerfJRnIbChZriewCUtAR-BrytVRUcHYXQgKa4RcBziRIYeB4J-vry9wtA5CW5PnV8kbcGGuGI_ZJaF09mKiB_hO5SXUVpnATAdm3lYElTKqQp04KxPBeP3G_FzEaWAGQm5eAKvO3Y74TSjJRRIh5S0nD_SBedBtvPZYEaDnZ8a6_pWQUsjtFB60t8yWUhD80HA6k-l1rDXm1KmJ8E4tHBuTx-ClD-WD78PPq0ppdLod80Xvm6oTZ6MRr988lHhmZgUdlVF9HrCwKL2D-AtRN8HyD2czTRVcVHIx5F30YF07i3n5m8HzG58o6O8UhFx78Ngmj79-4zzGaV7XnMBZo3RI2o5THj4neo5ae8Cr7UJuIlJUsE8i6x5KIbcJ2xxNCp8-NsVqtherWe-c4BR5zsEcQ172t5zyFKNXj5SPDAfpysOPpDOb7EfmfWlbVNF_0nEKPXTI8TkOGTRjWfkvyUpa-2tccTrvGU3WojmVn2KMYeAn9IFVrSkmDJfruouzlKi-r59j36YqIuRa62sm3aRplN07IxEPyPWUjaeo7ChxOzBi3c6oIxxgEHKTUY4dnaOE4SejtlP4lzJ5Yh0uNvL1o8QPUNBd0dRa5dwiuorI532ZK8gEFVqolK9i-Nxa33esbIRGjLmSYHAJKJ8E5ticynCTyX-76t6DdrHuXZnT4IzFw5iAhaRP-lMuhDw03gl5yJQR8kDmDBn6ckyUYwCxeBKLp_0fBxCLPSQD4qUPrskDh8f6Ec7KhQY1_Hcv5EbIrVg8glg_i8Vjekwf3DzhbFUBx-FJuuPaXyErwcfMLp0DQOyMNwf87zMDPhPr5z5R5WYPuTU-CLnqGIKQByEPXU7HdwzVPiVECjdnK8CpHdvfMe6O-v_s_zj8f5Cyvw6kSJeq1J5xiK-jsb1FqTx8Z0neW_Kn2ua_qe2eI2zx0F8nmK-K3aTUl5poNCchH4V8TGEFXxd4uPOhEIvnPL2dz-Euhzt79dWYUdYx-mku2Vdc8l_lkn-tS7yAO1-ioyJJK1qtsq8AGC6TbfRB6ZWpusvELN4MT8X6CTpdjkqHRDEV8jBi8Dnz489XnjbrNJZ2BYMLpiPUKrRcjlSFJ2W6ptK1Ha7l3M5CzB6t3mNDipBwKAw4dZXWujixOHWmAnKN3nMYyaeBZw9H4ixWM62yzpzh5loaE02yLFEgNwDH7ebksPrZcWEKLzwv57biWqAJHVzKFmqyjALPujxKm1Pfxvx1XjoS8nh_U4pfwHKvKJTPG--58Vxn_aTL_aygD2t8xX-ltQNKLD6T1DZw10AN3uom4jjUcPkAD0URt4oQnMqaQPD21jfONzbz7Y0xNzzNvj4-M9IDaZzrW9uIvRSbmdhui65j6vaL-b3rYaxoNx_qNi5RjvxoNugIuVFlyEZYM4zdV-zZLkeeTIhBZXwgLCAvKX-_GdKjyBIT_6uNcUoOajwkHBvdD_JH3gKYSA3dcWRtv1bdDHl_Gh2sJhOfKAzwxz4gHwDhgs5waKjjVevCkjcDtCGN6jdm9DF8M9-cKPjBqoJ9FxMq2ALbfrDKMH-_oCs8b381BpWplJ_bW8VGM9CwCA4c43Jw45G4Jl33ue2NOd85YQovBmp0QeWNRpcSWHmoCE032xk7rFZXi9SRAz2O2aQ1qDBglKpIWpBIe17RNjQ9TZOqaTC7vv1uPOvhvEZCnFAxpHVZmXdel9FAQUVTUzRwrFiUklQbuS0qyaDzAjmdFLtFsV1scUK7-Wp7v7yfbebLSbmbZcvF_Xq-WmSL43w7y2bb2X2Gx9WKjpncLLYTtZMzuZht53K-vl8tl1Oabxbr7H67LDaIuFyJ-xlVqPRU63M1te40icVit1rN5-uJxoy0j1-ISNm1CCnkE6-ndEl1hU-WzxO3Yw53WXPy4n6m47o38AwqaPrqy5MfdFnl09cjmVMhaJo0Tu_KEGrPWRBb-kmFssmmua2EPLCc7tdd7ex_KA9CHtJXJ0Ieoi3_CwAA__9uYqd1">