https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110000

--- Comment #6 from Nikolas Klauser <nikolasklauser at berlin dot de> ---
(In reply to Florian Weimer from comment #5)
> How hard is this to use in practice? With current Clang, this:
> 
> “
> template <class T>
> class S {
>   __attribute__ ((visibility ("hidden"),
> exclude_from_explicit_instantiation))
>   int f1 ();
>   int f2 ();
> };
> 
> template <class T> int
> S<T>::f1 ()
> {
>   return 1;
> }
> 
> template <class T> int
> S<T>::f2 ()
> {
>   return f1 ();
> }
> 
> template class S<int>;
> ”
> 
> still inlines S<int>::f1 into S<int>::f2. This may not threaten future
> evolution of the implementation in this particular case, but it would
> certainly be helpful to have some guides similar to
> <https://community.kde.org/Policies/
> Binary_Compatibility_Issues_With_C%2B%2B>. Clang's attribute documentation
> describes what happens, but it doesn't comment on the actual implications
> for ABI compatibility.

It doesn't have any inherent implications on ABI compatibility. Without other
tricks you still have to stay ABI compatible between versions of your function.
Some of the options are
- always inlining (this doesn't require the new attribute, but has numerous
drawbacks)
- making the functions have internal linkage (this would require the new
attribute, but note that clang's `internal_linkage` attribute seems to do this
implicitly)
- changing the mangling of the function whenever you change the ABI (this is
what libc++ currently does, through `abi_tag`s which change with every release)
I'm sure there are other ways to achieve this. These are the ways libc++
achieved this throughout it's history (that I know of). There might be better
ways, but the only problem with the current approach I am aware of is that the
ABI tag adds a few extra bytes per symbol. Compared to always inlining or
having one instance of a function per translation unit, that solution seems
pretty good to me. 

Essentially, to be able to do anything with a function you want, you have to
add `__attribute__((visibility("hidden"), exclude_from_explicit_instantiation,
abi_tag("some-versioning-scheme")))`, where 
- `visibility("hidden")` is to avoid exporting the symbol from any libraries
- `exclude_from_explicit_instantiation` is to avoid problems when users try to
explicitly instantiate a class template (or you want to provide an explicit
instantiation, but only some functions should be part of the ABI) and
- `abi_tag` is to avoid problems when users compile their code with different
versions of the library (essentially duplicating functions which may not be ABI
compatible)

Does that make sense?

Reply via email to