https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110000
--- Comment #12 from Nikolas Klauser <nikolasklauser at berlin dot de> --- (In reply to Jonathan Wakely from comment #10) > Using always_inline on everything is simply wrong: GCC will refuse to inline > some functions and the user gets an error that they cannot avoid. There's no > command-line option or pragma that can be used to compile the code anyway, > it's just un-compilable. Yes, that is one of the many problems with `always_inline` which we want to avoid. > I don't really understand the aim here. You're trying to avoid the user's > program ever containing a symbol generated from any libc++ code? So that > they can't ever have a dependency on those symbols, and the definitions can > change? Depends on what you mean by "never have a dependency on those symbols". It's fine to emit the symbol and link against it, as long as every TU that relies on it will also have a weak definition. > Honestly, the cure seems worse than the disease. > > Just because code is inlined, it doesn't mean it's immune from ABI > incompatibilities (it avoids some kinds of problems, but doesn't help with > others). Could you elaborate on the other problems? > And if all libc++ functions have an abi_tag courtesy of the HIDE_FROM_ABI > macro, why does it matter whether explicit instantiations include them > anyway? It becomes a problem when people try to have an explicit instantiation in a shared library, since all the symbols also have visibility("hidden"). The result are linker errors. > Your include/__config says: > > The symbol is given an ABI tag that changes with each version of libc++. > This ensures > that no ODR violation can arise from mixing two TUs compiled with different > versions > of libc++ where we would have changed the definition of a symbol. If the > symbols shared > the same name, the ODR would require that their definitions be > token-by-token equivalent, > which basically prevents us from being able to make any change to any > function in our > headers. > > Again, the cure seems worse than the disease. > > Your compiler and/or linker and/or dynamic loader can define what happens > here, so the ODR violation doesn't lead to nasal demons. If your definitions > are not token-by-token identical then what happens in practice is that you > get two definitions emitted in different TUs and the linker picks one. > There's no actual UB here. Applying this to every single function in the > library just in case you want to change it some day seems like major > overkill. > > But on the topic of this enhancement request, I don't see why functions > should be excluded from explicit instantiation if they're already > abi-tagged. Do you want to be able to change these functions in > ABI-incompatible ways between major revisions of the library? (In reply to Jonathan Wakely from comment #11) > (In reply to Jonathan Wakely from comment #10) > > Do you want to be able to change these functions in > > ABI-incompatible ways between major revisions of the library? > > Sorry, that was unclear, I meant to ask if you want to change them in > ABI-incompatible ways without bumping the version in the abi_tag? No. Being able to change the implementation in ABI-incompatible ways between versions is the whole point of the tag. > e.g. change std::__1::vector<int, std::__1::allocator<int> > >::__clear[abi:v15007]() in an ABI-incompatible way, without changing the > tag to [abi:v15008]? > > Because if the tag is going to change anyway, what does it matter if the > user has instantiations of the old [abi:v15007] symbol in their lib? That's completely fine (and in fact the goal of adding `exclude_from_explicit_instantiation`). The idea is that the library contains the symbols it uses, and we can remove functions, change the ABI of functions, or whatever else. Everything that a TU relies upon will be part of that TU. When linking, the symbols will be deduplicated, and most people will have just one version of a given function in their binary. If you ever have multiple versions for whatever reason, it's fine because the ABI tags + exclude_from_explicit_instantiation make sure the symbol exists somewhere and has it's own name.