Adding a new attribute: no_extern_template

Hi,

This message is related to solving the issue explained at [1], and indirectly, the usage of __always_inline__ in libc++ as explained at [2].

I've been looking to add an attribute (tentatively called no_extern_template) which would prevent member functions in a template from getting available_externally linkage even when there is a matching extern template declaration. In other words, given the following code:

    template <class T>
    struct Foo { void func() { } };
    extern template struct Foo<int>;

    void use() {
      Foo<int> f;
      f.func();
    }

it is possible for Clang to emit a call to the extern function `Foo<int>::func()`, because the extern template declaration promises that it exists somewhere else in the program. Clang could also decide to inline the function and generate no extern call, but it does not _have_ to. What I want is an attribute that inhibits generating an external call, i.e. that makes sure `Foo<int>::func()` is either emitted in this TU despite the extern template declaration, or inlined (in which case a definition is obviously not needed). If the function is emitted, it should be emitted with proper linkage, in this case linkonce_odr (IIUC). The attribute would be applied to the member function that should be opted-out of the extern template declaration, like so:

    template <class T>
    struct Foo { __attribute__((no_extern_template)) void func() { } };
    extern template struct Foo<int>;

I'd like to have some feedback on this idea, specifically:

- What entities does it make sense to apply this attribute to? Currently, I'm thinking only static and non-static member functions of templates, for lack of imagination and other use cases. Does it make sense to apply it to static data members? To the vtable and RTTI somehow?

- What other attributes would be mutually exclusive with this one? Right now I can only think of `internal_linkage`, but is there anything else?

Finally, I'd also welcome any guidance on how to best achieve this in Clang. So far, I've achieved something that "works" by forcing declarations with `GVA_AvailableExternally` linkage to have `GVA_DiscardableODR` linkage (in `adjustGVALinkageForAttributes`). I think this is probably the wrong approach but I’m a Clang beginner, so I’m looking for advice if somebody has some. I'll soon publish an early code review on Phabricator to ease the process of getting feedback on the code itself.

Thanks,
Louis

[1]: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058460.html
[2]: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058419.html

Hi,

This message is related to solving the issue explained at [1], and indirectly, the usage of always_inline in libc++ as explained at [2].

I’ve been looking to add an attribute (tentatively called no_extern_template) which would prevent member functions in a template from getting available_externally linkage even when there is a matching extern template declaration. In other words, given the following code:

template
struct Foo { void func() { } };
extern template struct Foo;

void use() {
Foo f;
f.func();
}

it is possible for Clang to emit a call to the extern function Foo<int>::func(), because the extern template declaration promises that it exists somewhere else in the program. Clang could also decide to inline the function and generate no extern call, but it does not have to. What I want is an attribute that inhibits generating an external call, i.e. that makes sure Foo<int>::func() is either emitted in this TU despite the extern template declaration, or inlined (in which case a definition is obviously not needed). If the function is emitted, it should be emitted with proper linkage, in this case linkonce_odr (IIUC). The attribute would be applied to the member function that should be opted-out of the extern template declaration, like so:

template
struct Foo { attribute((no_extern_template)) void func() { } };
extern template struct Foo;

I’d like to have some feedback on this idea, specifically:

I think I’m following what you’re asking for: the idea is that an explicit instantiation declaration for the class would not be treated as an explicit instantiation declaration for the members of the class that have the attribute, right? So the desired behavior for:

template struct Foo { // non-polymorphic class
void foo() { }
attribute((no_extern_template)) void bar() { }

void baz() { }

};
extern template struct Foo;

would be exactly the same as the standard behavior of:

template struct Foo {
void foo() { }
void bar() { }

void baz() { }

};
extern void Foo::foo();

extern void Foo::baz();

except that this is an opt-out mechanism whereas the standard mechanism is opt-in. (For polymorphic class types, there’s more differences, as explicit instantiations can also affect where vtables are emitted.)

Given that (I’m guessing) the idea is to more precisely control which functions are part of the libc++ DSO’s ABI, have you considered explicitly listing those functions (that is, following the opt-in strategy) rather than adding an opt-out mechanism? That seems to give more direct control over the ABI surface, albeit at the cost of presumably making the header larger. Is there a reason that approach won’t work or is undesirable?

The entire point of extern template declarations is to be able to emit member functions with available_externally linkage, so this seems like a pretty strange feature.

Is the original problem limited to the __init pattern (below), or are is needed for more than that?
template
struct Foo {
inline attribute((visibility(“hidden”)))
int __init(int x) { /* LOTS OF CODE */ }

inline attribute((visibility(“default”)))
int bar(int x) { return __init(x); }
};

My first idea (probably too simple to work and already rejected) is to mark bar noinline. Then it will be available_externally, but not inlineable. After CodeGen, we will have a call to the bar definition provided by the libc++ DSO, and there will not be link errors. If that doesn’t work, read on.

We had a very similar to a problem with dllimport, which also uses available_externally. This is the situation:

#if BUILDING_FOO
#define FOO_EXPORT __declspec(dllexport)
#else
#define FOO_EXPORT __declspec(dllimport)

#endif
struct Foo {
void bar();
void FOO_EXPORT foo() { bar(); }
};

When compiling the code that uses Foo, BUILDING_FOO is not defined, and dllimport is used. However, Foo::foo calls Foo::bar, which is not exported, and so the link will fail if foo() is emitted available_externally and inlined. In this case, we found that we couldn’t actually emit available_externally definitions of foo, we just had to call the out-of-line version provided by the DLL. See the class DLLImportFunctionVisitor in CodeGenModule.cpp that implements this. It’s not bulletproof, but it works well enough.

I think we might want to consider implementing the same kind of traversal to check for visibility conflicts (a default visibility function calls a hidden one) before emitting available_externally functions for an extern template declaration.

I’ve been looking to add an attribute (tentatively called no_extern_template) which would prevent member functions in a template from getting available_externally linkage even when there is a matching extern template declaration. In other words, given the following code:

The entire point of extern template declarations is to be able to emit member functions with available_externally linkage, so this seems like a pretty strange feature.

Indeed.

Is the original problem limited to the __init pattern (below), or are is needed for more than that?
template
struct Foo {
inline attribute((visibility(“hidden”)))
int __init(int x) { /* LOTS OF CODE */ }

inline attribute((visibility(“default”)))
int bar(int x) { return __init(x); }
};

My first idea (probably too simple to work and already rejected) is to mark bar noinline. Then it will be available_externally, but not inlineable. After CodeGen, we will have a call to the bar definition provided by the libc++ DSO, and there will not be link errors. If that doesn’t work, read on.

I don’t think that’s a good solution for the following reason: We’re currently piggy-backing on always_inline to achieve our goals, and this leads to problems because it’s not really the right tool for the job. Similarly, using noinline to achieve our results is just relying on a different (but still wrong) tool. For example, it must be possible to craft cases where using noinline leads to suboptimal code being generated. I think inlining should stay out of any solution since that should be for the optimizer to figure out after we’ve given it the information it needs to generate correct code. I could be wrong, of course, but that’s my gut feeling.

We had a very similar to a problem with dllimport, which also uses available_externally. This is the situation:

#if BUILDING_FOO
#define FOO_EXPORT __declspec(dllexport)
#else
#define FOO_EXPORT __declspec(dllimport)

#endif
struct Foo {
void bar();
void FOO_EXPORT foo() { bar(); }
};

When compiling the code that uses Foo, BUILDING_FOO is not defined, and dllimport is used. However, Foo::foo calls Foo::bar, which is not exported, and so the link will fail if foo() is emitted available_externally and inlined. In this case, we found that we couldn’t actually emit available_externally definitions of foo, we just had to call the out-of-line version provided by the DLL. See the class DLLImportFunctionVisitor in CodeGenModule.cpp that implements this. It’s not bulletproof, but it works well enough.

I think we might want to consider implementing the same kind of traversal to check for visibility conflicts (a default visibility function calls a hidden one) before emitting available_externally functions for an extern template declaration.

That’s really interesting. I think the problem we’re solving is roughly the same. Do you think I could simply augment the DLLImportFunctionVisitor to check for methods that have hidden visibility? Basically, when we’re checking whether foo should be emitted, we check whether it has default visibility and if it calls a function with hidden visibility. If that’s the case, we say foo should not be emitted, which forces an external call (in the dylib) to be emitted. That would be pretty nice and it would require neither an additional attribute nor any source code changes to libc++ — it would just make visibility(“hidden”) work as one would expect.

It still has the downside of preventing inlining of functions that could otherwise be inlined, but at least that’s not hardcoded in the program’s source code. I’ll try to implement this and see what the problems are, if any.

Louis

Hi,

This message is related to solving the issue explained at [1], and indirectly, the usage of always_inline in libc++ as explained at [2].

I’ve been looking to add an attribute (tentatively called no_extern_template) which would prevent member functions in a template from getting available_externally linkage even when there is a matching extern template declaration. In other words, given the following code:

template
struct Foo { void func() { } };
extern template struct Foo;

void use() {
Foo f;
f.func();
}

it is possible for Clang to emit a call to the extern function Foo<int>::func(), because the extern template declaration promises that it exists somewhere else in the program. Clang could also decide to inline the function and generate no extern call, but it does not have to. What I want is an attribute that inhibits generating an external call, i.e. that makes sure Foo<int>::func() is either emitted in this TU despite the extern template declaration, or inlined (in which case a definition is obviously not needed). If the function is emitted, it should be emitted with proper linkage, in this case linkonce_odr (IIUC). The attribute would be applied to the member function that should be opted-out of the extern template declaration, like so:

template
struct Foo { attribute((no_extern_template)) void func() { } };
extern template struct Foo;

I’d like to have some feedback on this idea, specifically:

I think I’m following what you’re asking for: the idea is that an explicit instantiation declaration for the class would not be treated as an explicit instantiation declaration for the members of the class that have the attribute, right? So the desired behavior for:

template struct Foo { // non-polymorphic class
void foo() { }
attribute((no_extern_template)) void bar() { }

void baz() { }

};
extern template struct Foo;

would be exactly the same as the standard behavior of:

template struct Foo {
void foo() { }
void bar() { }

void baz() { }

};
extern void Foo::foo();

extern void Foo::baz();

Yes, this is what I’m asking for.

except that this is an opt-out mechanism whereas the standard mechanism is opt-in. (For polymorphic class types, there’s more differences, as explicit instantiations can also affect where vtables are emitted.)

Given that (I’m guessing) the idea is to more precisely control which functions are part of the libc++ DSO’s ABI, have you considered explicitly listing those functions (that is, following the opt-in strategy) rather than adding an opt-out mechanism? That seems to give more direct control over the ABI surface, albeit at the cost of presumably making the header larger. Is there a reason that approach won’t work or is undesirable?

We’ve talked about it in the thread starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058519.html. I think this is a superior solution because it would create a very clear list of what’s in the ABI. It might be tedious to create (lots of boilerplate declarations), but that’s not a huge concern IMO.

However, the reason why this is not feasible right now is that we lack a way to declare an extern instantiation of a vtable and RTTI, and to explicitly instantiate those. I guess we could either add an extension that allows that and/or try standardizing a feature that allows that. I think standardizing a way of doing this would be useful nonetheless — it would for example remove the need for anchor functions to pick which TU the vtable is emitted in, which is kind of a hack.

Also, it’s not a huge reason not to do it, but that would constitute a very large change in libc++, which does everything opt-out right now. Comparatively, everything is already in place for libc++ to start using an hypothetical no_extern_template attribute, and in fact the patch that does that is like 4 lines. Of course, my search for the right solution is not primarily motivated by that.

I think I will start by exploring Reid’s idea of checking for incompatible visibilities using a visitor, and if that doesn’t take me anywhere, I’ll reconsider your suggestion. Independently, I’ll draft a C++ proposal to control where RTTI/vtables are instantiated and see where that idea goes.

Louis

I’ve been looking to add an attribute (tentatively called no_extern_template) which would prevent member functions in a template from getting available_externally linkage even when there is a matching extern template declaration. In other words, given the following code:

The entire point of extern template declarations is to be able to emit member functions with available_externally linkage, so this seems like a pretty strange feature.

Indeed.

Is the original problem limited to the __init pattern (below), or are is needed for more than that?
template
struct Foo {
inline attribute((visibility(“hidden”)))
int __init(int x) { /* LOTS OF CODE */ }

inline attribute((visibility(“default”)))
int bar(int x) { return __init(x); }
};

My first idea (probably too simple to work and already rejected) is to mark bar noinline. Then it will be available_externally, but not inlineable. After CodeGen, we will have a call to the bar definition provided by the libc++ DSO, and there will not be link errors. If that doesn’t work, read on.

I don’t think that’s a good solution for the following reason: We’re currently piggy-backing on always_inline to achieve our goals, and this leads to problems because it’s not really the right tool for the job. Similarly, using noinline to achieve our results is just relying on a different (but still wrong) tool. For example, it must be possible to craft cases where using noinline leads to suboptimal code being generated. I think inlining should stay out of any solution since that should be for the optimizer to figure out after we’ve given it the information it needs to generate correct code. I could be wrong, of course, but that’s my gut feeling.

We had a very similar to a problem with dllimport, which also uses available_externally. This is the situation:

#if BUILDING_FOO
#define FOO_EXPORT __declspec(dllexport)
#else
#define FOO_EXPORT __declspec(dllimport)

#endif
struct Foo {
void bar();
void FOO_EXPORT foo() { bar(); }
};

When compiling the code that uses Foo, BUILDING_FOO is not defined, and dllimport is used. However, Foo::foo calls Foo::bar, which is not exported, and so the link will fail if foo() is emitted available_externally and inlined. In this case, we found that we couldn’t actually emit available_externally definitions of foo, we just had to call the out-of-line version provided by the DLL. See the class DLLImportFunctionVisitor in CodeGenModule.cpp that implements this. It’s not bulletproof, but it works well enough.

I think we might want to consider implementing the same kind of traversal to check for visibility conflicts (a default visibility function calls a hidden one) before emitting available_externally functions for an extern template declaration.

That’s really interesting. I think the problem we’re solving is roughly the same. Do you think I could simply augment the DLLImportFunctionVisitor to check for methods that have hidden visibility? Basically, when we’re checking whether foo should be emitted, we check whether it has default visibility and if it calls a function with hidden visibility. If that’s the case, we say foo should not be emitted, which forces an external call (in the dylib) to be emitted. That would be pretty nice and it would require neither an additional attribute nor any source code changes to libc++ — it would just make visibility(“hidden”) work as one would expect.

It still has the downside of preventing inlining of functions that could otherwise be inlined, but at least that’s not hardcoded in the program’s source code. I’ll try to implement this and see what the problems are, if any.

I gave some more thought to this approach and implemented a proof of concept, and I think it doesn’t solve my problem. Indeed, if a user calls a function with hidden visibility that happens to be part of an extern template declaration, I still get a link error. IOW, your approach doesn’t work if there’s no function with default visibility somewhere in the chain. This happens for example in std::vector.

In vector.hpp:

namespace std {
template
class __vector_base_common {
public:
attribute((visibility(“hidden”))) __vector_base_common() {}
};

extern template class attribute ((visibility(“default”))) __vector_base_common;

template
class attribute ((type_visibility(“default”))) vector
: private __vector_base_common
{
public:
attribute((visibility(“hidden”))) vector() { }
};
}

In vector.cpp (which becomes part of libc++.dylib):

#include “vector.hpp”
namespace std {
template class __vector_base_common;
}

In main.cpp:

#include “vector.hpp”
int main() {
std::vector v;
}

Then, build as:

$ clang++ -std=c++11 -I . vector.cpp -o libcplusplus.dylib -shared
$ clang++ -std=c++11 -I . main.cpp -o main.exe -lcplusplus -L .

std::__vector_base_common::__vector_base_common()", referenced from:
std::vector::vector() in main-1c9480.o

The problem here is that there’s no function in the dylib that we can call that would itself have access to __vector_base_common::__vector_base_common(), which has hidden visibility.

Also, even disregarding this issue, it turns out that preventing inlining of all methods that are part of the ABI is kind of a big deal – I’m quite concerned about the performance impact this could have. I’d much rather pursue a path that does not require telling the compiler whether to inline something or not, as this is an orthogonal decision IMO. Does that make sense?

Louis

I wonder if you can solve the problem in the dylib by exporting all the symbols. It will make the dylib larger but you can stop worry about missing symbols or losing performance.

The attributes I want (tentatively called extern_template_implementation) works like:

#include “vector.hpp”
namespace std {
template class attribute((extern_template_implementation)) __vector_base_common;

}

It will make all the methods, vtable and RTTI from __vector_base_common default visibility and external linkage (no a weak symbol). Compiler should verify that templated class and all its member can be fully instantiated.

Steven

Hi,

This message is related to solving the issue explained at [1], and indirectly, the usage of always_inline in libc++ as explained at [2].

I’ve been looking to add an attribute (tentatively called no_extern_template) which would prevent member functions in a template from getting available_externally linkage even when there is a matching extern template declaration. In other words, given the following code:

template
struct Foo { void func() { } };
extern template struct Foo;

void use() {
Foo f;
f.func();
}

it is possible for Clang to emit a call to the extern function Foo<int>::func(), because the extern template declaration promises that it exists somewhere else in the program. Clang could also decide to inline the function and generate no extern call, but it does not have to. What I want is an attribute that inhibits generating an external call, i.e. that makes sure Foo<int>::func() is either emitted in this TU despite the extern template declaration, or inlined (in which case a definition is obviously not needed). If the function is emitted, it should be emitted with proper linkage, in this case linkonce_odr (IIUC). The attribute would be applied to the member function that should be opted-out of the extern template declaration, like so:

template
struct Foo { attribute((no_extern_template)) void func() { } };
extern template struct Foo;

I’d like to have some feedback on this idea, specifically:

I think I’m following what you’re asking for: the idea is that an explicit instantiation declaration for the class would not be treated as an explicit instantiation declaration for the members of the class that have the attribute, right? So the desired behavior for:

template struct Foo { // non-polymorphic class
void foo() { }
attribute((no_extern_template)) void bar() { }

void baz() { }

};
extern template struct Foo;

would be exactly the same as the standard behavior of:

template struct Foo {
void foo() { }
void bar() { }

void baz() { }

};
extern void Foo::foo();

extern void Foo::baz();

Yes, this is what I’m asking for.

except that this is an opt-out mechanism whereas the standard mechanism is opt-in. (For polymorphic class types, there’s more differences, as explicit instantiations can also affect where vtables are emitted.)

Given that (I’m guessing) the idea is to more precisely control which functions are part of the libc++ DSO’s ABI, have you considered explicitly listing those functions (that is, following the opt-in strategy) rather than adding an opt-out mechanism? That seems to give more direct control over the ABI surface, albeit at the cost of presumably making the header larger. Is there a reason that approach won’t work or is undesirable?

We’ve talked about it in the thread starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058519.html. I think this is a superior solution because it would create a very clear list of what’s in the ABI. It might be tedious to create (lots of boilerplate declarations), but that’s not a huge concern IMO.

However, the reason why this is not feasible right now is that we lack a way to declare an extern instantiation of a vtable and RTTI, and to explicitly instantiate those. I guess we could either add an extension that allows that and/or try standardizing a feature that allows that. I think standardizing a way of doing this would be useful nonetheless — it would for example remove the need for anchor functions to pick which TU the vtable is emitted in, which is kind of a hack.

GCC for many years had an extension to do this: https://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html (see the bottom of the page).

It’s long been on our list of “potentially useful GCC extensions we never got around to implementing”. I’m not sure that’s quite enough to be really useful, though; while that lets you say “instantiate the vtable here”, there doesn’t seem to be a way to say “do not instantiate the vtable here; it was instantiated elsewhere”.

Hi,

This message is related to solving the issue explained at [1], and indirectly, the usage of always_inline in libc++ as explained at [2].

I’ve been looking to add an attribute (tentatively called no_extern_template) which would prevent member functions in a template from getting available_externally linkage even when there is a matching extern template declaration. In other words, given the following code:

template
struct Foo { void func() { } };
extern template struct Foo;

void use() {
Foo f;
f.func();
}

it is possible for Clang to emit a call to the extern function Foo<int>::func(), because the extern template declaration promises that it exists somewhere else in the program. Clang could also decide to inline the function and generate no extern call, but it does not have to. What I want is an attribute that inhibits generating an external call, i.e. that makes sure Foo<int>::func() is either emitted in this TU despite the extern template declaration, or inlined (in which case a definition is obviously not needed). If the function is emitted, it should be emitted with proper linkage, in this case linkonce_odr (IIUC). The attribute would be applied to the member function that should be opted-out of the extern template declaration, like so:

template
struct Foo { attribute((no_extern_template)) void func() { } };
extern template struct Foo;

I’d like to have some feedback on this idea, specifically:

I think I’m following what you’re asking for: the idea is that an explicit instantiation declaration for the class would not be treated as an explicit instantiation declaration for the members of the class that have the attribute, right? So the desired behavior for:

template struct Foo { // non-polymorphic class
void foo() { }
attribute((no_extern_template)) void bar() { }

void baz() { }

};
extern template struct Foo;

would be exactly the same as the standard behavior of:

template struct Foo {
void foo() { }
void bar() { }

void baz() { }

};
extern void Foo::foo();

extern void Foo::baz();

Yes, this is what I’m asking for.

except that this is an opt-out mechanism whereas the standard mechanism is opt-in. (For polymorphic class types, there’s more differences, as explicit instantiations can also affect where vtables are emitted.)

Given that (I’m guessing) the idea is to more precisely control which functions are part of the libc++ DSO’s ABI, have you considered explicitly listing those functions (that is, following the opt-in strategy) rather than adding an opt-out mechanism? That seems to give more direct control over the ABI surface, albeit at the cost of presumably making the header larger. Is there a reason that approach won’t work or is undesirable?

We’ve talked about it in the thread starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058519.html. I think this is a superior solution because it would create a very clear list of what’s in the ABI. It might be tedious to create (lots of boilerplate declarations), but that’s not a huge concern IMO.

However, the reason why this is not feasible right now is that we lack a way to declare an extern instantiation of a vtable and RTTI, and to explicitly instantiate those. I guess we could either add an extension that allows that and/or try standardizing a feature that allows that. I think standardizing a way of doing this would be useful nonetheless — it would for example remove the need for anchor functions to pick which TU the vtable is emitted in, which is kind of a hack.

GCC for many years had an extension to do this: https://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html (see the bottom of the page).

It’s long been on our list of “potentially useful GCC extensions we never got around to implementing”. I’m not sure that’s quite enough to be really useful, though; while that lets you say “instantiate the vtable here”, there doesn’t seem to be a way to say “do not instantiate the vtable here; it was instantiated elsewhere”.

If we can just quietly let that extension die, I think the world would be a better place. The basic idea isn’t bad, but it obviously only uses static and inline because there’s already parser support for them.

If we’re thinking of adding a vendor-specific attribute, why don’t we just add an attribute to mark an explicit instantiation def/decl as only instantiating the class data? Or even just propose that as a feature to the committee? For the latter, I think the obvious spelling would be (with or without parens):

‘extern’? ‘typeid’ ‘(’ type-id ‘)’

Separating this from explicit instantiations would also let it apply to arbitrary other class types, not just templates, which would be nice for micro-optimizing code that uses RTTI but can’t reasonably use key functions (as well as ABIs that don’t provide key-function-like optimizations). If RTTI is disabled, we’d just emit the v-table, and we’d complain if the class wasn’t polymorphic. I guess emitting v-tables in addition to RTTI would prevent someone from using this just to define the RTTI and not the v-table, but… I can’t imagine why someone would want to do that.

John.

I wonder if you can solve the problem in the dylib by exporting all the symbols. It will make the dylib larger but you can stop worry about missing symbols or losing performance.

We don’t want to do that because we need to keep the ABI stable. As soon as we make a symbol visible from the dylib, we need to keep it visible forever. This means it’s harder to make changes.

The attributes I want (tentatively called extern_template_implementation) works like:

#include “vector.hpp”
namespace std {
template class attribute((extern_template_implementation)) __vector_base_common;

}

It will make all the methods, vtable and RTTI from __vector_base_common default visibility and external linkage (no a weak symbol). Compiler should verify that templated class and all its member can be fully instantiated.

I think we don’t have the same problem. My problem is not that libc++ is not exporting the right set of symbols, it’s that users can sometimes try to “import” symbols they shouldn’t be trying to import. I think a solution to my problem should not require changing what symbols are exported by libc++.

Louis

Hi,

This message is related to solving the issue explained at [1], and indirectly, the usage of always_inline in libc++ as explained at [2].

I’ve been looking to add an attribute (tentatively called no_extern_template) which would prevent member functions in a template from getting available_externally linkage even when there is a matching extern template declaration. In other words, given the following code:

template
struct Foo { void func() { } };
extern template struct Foo;

void use() {
Foo f;
f.func();
}

it is possible for Clang to emit a call to the extern function Foo<int>::func(), because the extern template declaration promises that it exists somewhere else in the program. Clang could also decide to inline the function and generate no extern call, but it does not have to. What I want is an attribute that inhibits generating an external call, i.e. that makes sure Foo<int>::func() is either emitted in this TU despite the extern template declaration, or inlined (in which case a definition is obviously not needed). If the function is emitted, it should be emitted with proper linkage, in this case linkonce_odr (IIUC). The attribute would be applied to the member function that should be opted-out of the extern template declaration, like so:

template
struct Foo { attribute((no_extern_template)) void func() { } };
extern template struct Foo;

I’d like to have some feedback on this idea, specifically:

I think I’m following what you’re asking for: the idea is that an explicit instantiation declaration for the class would not be treated as an explicit instantiation declaration for the members of the class that have the attribute, right? So the desired behavior for:

template struct Foo { // non-polymorphic class
void foo() { }
attribute((no_extern_template)) void bar() { }

void baz() { }

};
extern template struct Foo;

would be exactly the same as the standard behavior of:

template struct Foo {
void foo() { }
void bar() { }

void baz() { }

};
extern void Foo::foo();

extern void Foo::baz();

Yes, this is what I’m asking for.

except that this is an opt-out mechanism whereas the standard mechanism is opt-in. (For polymorphic class types, there’s more differences, as explicit instantiations can also affect where vtables are emitted.)

Given that (I’m guessing) the idea is to more precisely control which functions are part of the libc++ DSO’s ABI, have you considered explicitly listing those functions (that is, following the opt-in strategy) rather than adding an opt-out mechanism? That seems to give more direct control over the ABI surface, albeit at the cost of presumably making the header larger. Is there a reason that approach won’t work or is undesirable?

We’ve talked about it in the thread starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058519.html. I think this is a superior solution because it would create a very clear list of what’s in the ABI. It might be tedious to create (lots of boilerplate declarations), but that’s not a huge concern IMO.

However, the reason why this is not feasible right now is that we lack a way to declare an extern instantiation of a vtable and RTTI, and to explicitly instantiate those. I guess we could either add an extension that allows that and/or try standardizing a feature that allows that. I think standardizing a way of doing this would be useful nonetheless — it would for example remove the need for anchor functions to pick which TU the vtable is emitted in, which is kind of a hack.

GCC for many years had an extension to do this: https://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html (see the bottom of the page).

It’s long been on our list of “potentially useful GCC extensions we never got around to implementing”. I’m not sure that’s quite enough to be really useful, though; while that lets you say “instantiate the vtable here”, there doesn’t seem to be a way to say “do not instantiate the vtable here; it was instantiated elsewhere”.

If we can just quietly let that extension die, I think the world would be a better place. The basic idea isn’t bad, but it obviously only uses static and inline because there’s already parser support for them.

If we’re thinking of adding a vendor-specific attribute, why don’t we just add an attribute to mark an explicit instantiation def/decl as only instantiating the class data? Or even just propose that as a feature to the committee? For the latter, I think the obvious spelling would be (with or without parens):

‘extern’? ‘typeid’ ‘(’ type-id ‘)’

Separating this from explicit instantiations would also let it apply to arbitrary other class types, not just templates, which would be nice for micro-optimizing code that uses RTTI but can’t reasonably use key functions (as well as ABIs that don’t provide key-function-like optimizations). If RTTI is disabled, we’d just emit the v-table, and we’d complain if the class wasn’t polymorphic. I guess emitting v-tables in addition to RTTI would prevent someone from using this just to define the RTTI and not the v-table, but… I can’t imagine why someone would want to do that.

John.

I’ve given more thought to Richard’s suggestion. I’m fully on-board with having a way to externally declare and explicitly instantiate typeids and vtables for arbitrary classes (templates or not). I think that’s a great idea that fills a need and I’m willing to pursue a standard proposal that does that.

However, I’m concerned about making libc++’s ability to drop always_inline contingent on such a feature or compiler extension for the following reasons:

  • We have to make sure libc++ still works with GCC. If we wanted to use this hypothetical compiler extension in libc++, we’d have to keep the same annotations as today, but also add the explicit declarations of what’s in the ABI. This increases the complexity of libc++’s visibility system significantly, and that complexity is already too high.
  • libc++ has been opt-out since the beginning. It would arguably be nicer if we had what Richard suggests, and we may get there someday, but it’s just not the way things have been designed in libc++ and doing otherwise is a huge change. There’s no telling what subtle problems we may find or even create down that road, and I’d like to avoid such a big unknown.

So, in a perfect world, I’d have a standardized way of explicitly declaring what is part of my ABI, and I wouldn’t have any of today’s libc++ craziness. However, I still think no_extern_template is the right answer for the time being, given it fits exactly in the place where __always_inline__ is used today in libc++. Unless there are serious concerns with the attribute, I’d like to solicit feedback on the following points:

  • What entities does it make sense to apply this attribute to? Currently, I’m thinking only static and non-static member functions of templates, for lack of imagination and other use cases. Does it make sense to apply it to static data members? To the vtable and RTTI somehow?

  • What other attributes would be mutually exclusive with this one? Right now I can only think of internal_linkage, but is there anything else?

Thanks,
Louis

True, if the dylib does not provide the symbols that are being called directly from user code, then neither of my suggestions will help. You really do need to emit the functions with linkonce_odr linkage, because they are not actually available, and the extern template declaration is a bit of a lie.

At this point, you might want to consider finding a way to make libc++.dylib expose the symbols so that at some point in the future so that these functions can be emitted as avaiable_externally instead of linkonce_odr.

The problem here is that there’s no function in the dylib that we can call that would itself have access to __vector_base_common::__vector_base_common(), which has hidden visibility.

Also, even disregarding this issue, it turns out that preventing inlining of all methods that are part of the ABI is kind of a big deal – I’m quite concerned about the performance impact this could have. I’d much rather pursue a path that does not require telling the compiler whether to inline something or not, as this is an orthogonal decision IMO. Does that make sense?

True, if the dylib does not provide the symbols that are being called directly from user code, then neither of my suggestions will help. You really do need to emit the functions with linkonce_odr linkage, because they are not actually available, and the extern template declaration is a bit of a lie.

Yes, it is indeed a lie. More specifically, the extern template declaration is a lie for a subset of the methods in the class template — some of them are actually in the dylib, but some of them are not.

At this point, you might want to consider finding a way to make libc++.dylib expose the symbols so that at some point in the future so that these functions can be emitted as avaiable_externally instead of linkonce_odr.

The problem is that we don’t want to increase the surface of the ABI if we can avoid it. The larger our ABI surface is, the harder it is to make changes because we need to maintain ABI stability.

Louis

Hi,

This message is related to solving the issue explained at [1], and indirectly, the usage of always_inline in libc++ as explained at [2].

I’ve been looking to add an attribute (tentatively called no_extern_template) which would prevent member functions in a template from getting available_externally linkage even when there is a matching extern template declaration. In other words, given the following code:

template
struct Foo { void func() { } };
extern template struct Foo;

void use() {
Foo f;
f.func();
}

it is possible for Clang to emit a call to the extern function Foo<int>::func(), because the extern template declaration promises that it exists somewhere else in the program. Clang could also decide to inline the function and generate no extern call, but it does not have to. What I want is an attribute that inhibits generating an external call, i.e. that makes sure Foo<int>::func() is either emitted in this TU despite the extern template declaration, or inlined (in which case a definition is obviously not needed). If the function is emitted, it should be emitted with proper linkage, in this case linkonce_odr (IIUC). The attribute would be applied to the member function that should be opted-out of the extern template declaration, like so:

template
struct Foo { attribute((no_extern_template)) void func() { } };
extern template struct Foo;

I’d like to have some feedback on this idea, specifically:

I think I’m following what you’re asking for: the idea is that an explicit instantiation declaration for the class would not be treated as an explicit instantiation declaration for the members of the class that have the attribute, right? So the desired behavior for:

template struct Foo { // non-polymorphic class
void foo() { }
attribute((no_extern_template)) void bar() { }

void baz() { }

};
extern template struct Foo;

would be exactly the same as the standard behavior of:

template struct Foo {
void foo() { }
void bar() { }

void baz() { }

};
extern void Foo::foo();

extern void Foo::baz();

Yes, this is what I’m asking for.

except that this is an opt-out mechanism whereas the standard mechanism is opt-in. (For polymorphic class types, there’s more differences, as explicit instantiations can also affect where vtables are emitted.)

Given that (I’m guessing) the idea is to more precisely control which functions are part of the libc++ DSO’s ABI, have you considered explicitly listing those functions (that is, following the opt-in strategy) rather than adding an opt-out mechanism? That seems to give more direct control over the ABI surface, albeit at the cost of presumably making the header larger. Is there a reason that approach won’t work or is undesirable?

We’ve talked about it in the thread starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058519.html. I think this is a superior solution because it would create a very clear list of what’s in the ABI. It might be tedious to create (lots of boilerplate declarations), but that’s not a huge concern IMO.

However, the reason why this is not feasible right now is that we lack a way to declare an extern instantiation of a vtable and RTTI, and to explicitly instantiate those. I guess we could either add an extension that allows that and/or try standardizing a feature that allows that. I think standardizing a way of doing this would be useful nonetheless — it would for example remove the need for anchor functions to pick which TU the vtable is emitted in, which is kind of a hack.

GCC for many years had an extension to do this: https://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html (see the bottom of the page).

It’s long been on our list of “potentially useful GCC extensions we never got around to implementing”. I’m not sure that’s quite enough to be really useful, though; while that lets you say “instantiate the vtable here”, there doesn’t seem to be a way to say “do not instantiate the vtable here; it was instantiated elsewhere”.

If we can just quietly let that extension die, I think the world would be a better place. The basic idea isn’t bad, but it obviously only uses static and inline because there’s already parser support for them.

If we’re thinking of adding a vendor-specific attribute, why don’t we just add an attribute to mark an explicit instantiation def/decl as only instantiating the class data? Or even just propose that as a feature to the committee? For the latter, I think the obvious spelling would be (with or without parens):

‘extern’? ‘typeid’ ‘(’ type-id ‘)’

Separating this from explicit instantiations would also let it apply to arbitrary other class types, not just templates, which would be nice for micro-optimizing code that uses RTTI but can’t reasonably use key functions (as well as ABIs that don’t provide key-function-like optimizations). If RTTI is disabled, we’d just emit the v-table, and we’d complain if the class wasn’t polymorphic. I guess emitting v-tables in addition to RTTI would prevent someone from using this just to define the RTTI and not the v-table, but… I can’t imagine why someone would want to do that.

John.

I’ve given more thought to Richard’s suggestion. I’m fully on-board with having a way to externally declare and explicitly instantiate typeids and vtables for arbitrary classes (templates or not). I think that’s a great idea that fills a need and I’m willing to pursue a standard proposal that does that.

However, I’m concerned about making libc++’s ability to drop always_inline contingent on such a feature or compiler extension for the following reasons:

  • We have to make sure libc++ still works with GCC. If we wanted to use this hypothetical compiler extension in libc++, we’d have to keep the same annotations as today, but also add the explicit declarations of what’s in the ABI. This increases the complexity of libc++’s visibility system significantly, and that complexity is already too high.
  • libc++ has been opt-out since the beginning. It would arguably be nicer if we had what Richard suggests, and we may get there someday, but it’s just not the way things have been designed in libc++ and doing otherwise is a huge change. There’s no telling what subtle problems we may find or even create down that road, and I’d like to avoid such a big unknown.

So, in a perfect world, I’d have a standardized way of explicitly declaring what is part of my ABI, and I wouldn’t have any of today’s libc++ craziness. However, I still think no_extern_template is the right answer for the time being, given it fits exactly in the place where __always_inline__ is used today in libc++.

I don’t necessarily want to redirect you from this course of action; pragmatically-speaking, the attribute you’re proposing seems very reasonable to me, and is probably the right short-to-medium-term solution. However:

It seems to me there are two different compilations that we need to care about:

  1. the compilation of the DSO itself
  2. the compilation of a user of the DSO

For (1), we would need to use a compiler that can force-emit the vtable, ideally without emitting all inline functions in the class. (If it emits too much, we do have ways to prevent the extra symbols being part of the DSO’s ABI, but it’s not ideal.) Any version of GCC can do that (via “inline template”), and if we add a standard or vendor-specific feature to clang to emit the type info, then recent Clang can do that too. Older Clang and other compilers will be left emitting too many symbols, which is likely tolerable, because the result should still be correct and building a new libc++ DSO with an old Clang is likely something we can discourage.

For (2), it’s my understanding that we do not /need/ to prevent users of libc++ from emitting their own copies of symbols that are also in the DSO. If we don’t have a way of saying “the vtable is emitted in the DSO” for a particular compiler, the cost is that we may emit an unnecessary but mostly harmless copy of the vtable in the client program, not that we will miscompile or create an ABI problem.

So I think it might still be viable to switch libc++ entirely to per-function explicit instantiations, even before we have ubiquitous compiler support to deal with the result. But it’s probably worth delaying that until such compiler features are at least broadly available, since there will be some costs (notably, code size) to compilers for which we cannot declare that class type info is available externally.

Unless there are serious concerns with the attribute, I’d like to solicit feedback on the following points:

  • What entities does it make sense to apply this attribute to? Currently, I’m thinking only static and non-static member functions of templates, for lack of imagination and other use cases. Does it make sense to apply it to static data members? To the vtable and RTTI somehow?

I would expect the attribute to be applicable to all members of templated classes that would be explicitly instantiated by an explicit instantiation of the enclosing class ([temp.explicit]p10),. That would be member functions (static or non-static), member classes (to suppress recursion into their members), and static data members.

  • What other attributes would be mutually exclusive with this one? Right now I can only think of internal_linkage, but is there anything else?

I don’t think internal linkage needs to be mutually-exclusive with this attribute. I would expect that an internal_linkage + no_extern_template function would simply be unaffected by ‘extern template’, so would still be implicitly instantiated if referenced in a context where a definition is needed.

Hi,

This message is related to solving the issue explained at [1], and indirectly, the usage of always_inline in libc++ as explained at [2].

I’ve been looking to add an attribute (tentatively called no_extern_template) which would prevent member functions in a template from getting available_externally linkage even when there is a matching extern template declaration. In other words, given the following code:

template
struct Foo { void func() { } };
extern template struct Foo;

void use() {
Foo f;
f.func();
}

it is possible for Clang to emit a call to the extern function Foo<int>::func(), because the extern template declaration promises that it exists somewhere else in the program. Clang could also decide to inline the function and generate no extern call, but it does not have to. What I want is an attribute that inhibits generating an external call, i.e. that makes sure Foo<int>::func() is either emitted in this TU despite the extern template declaration, or inlined (in which case a definition is obviously not needed). If the function is emitted, it should be emitted with proper linkage, in this case linkonce_odr (IIUC). The attribute would be applied to the member function that should be opted-out of the extern template declaration, like so:

template
struct Foo { attribute((no_extern_template)) void func() { } };
extern template struct Foo;

I’d like to have some feedback on this idea, specifically:

I think I’m following what you’re asking for: the idea is that an explicit instantiation declaration for the class would not be treated as an explicit instantiation declaration for the members of the class that have the attribute, right? So the desired behavior for:

template struct Foo { // non-polymorphic class
void foo() { }
attribute((no_extern_template)) void bar() { }

void baz() { }

};
extern template struct Foo;

would be exactly the same as the standard behavior of:

template struct Foo {
void foo() { }
void bar() { }

void baz() { }

};
extern void Foo::foo();

extern void Foo::baz();

Yes, this is what I’m asking for.

except that this is an opt-out mechanism whereas the standard mechanism is opt-in. (For polymorphic class types, there’s more differences, as explicit instantiations can also affect where vtables are emitted.)

Given that (I’m guessing) the idea is to more precisely control which functions are part of the libc++ DSO’s ABI, have you considered explicitly listing those functions (that is, following the opt-in strategy) rather than adding an opt-out mechanism? That seems to give more direct control over the ABI surface, albeit at the cost of presumably making the header larger. Is there a reason that approach won’t work or is undesirable?

We’ve talked about it in the thread starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058519.html. I think this is a superior solution because it would create a very clear list of what’s in the ABI. It might be tedious to create (lots of boilerplate declarations), but that’s not a huge concern IMO.

However, the reason why this is not feasible right now is that we lack a way to declare an extern instantiation of a vtable and RTTI, and to explicitly instantiate those. I guess we could either add an extension that allows that and/or try standardizing a feature that allows that. I think standardizing a way of doing this would be useful nonetheless — it would for example remove the need for anchor functions to pick which TU the vtable is emitted in, which is kind of a hack.

GCC for many years had an extension to do this: https://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html (see the bottom of the page).

It’s long been on our list of “potentially useful GCC extensions we never got around to implementing”. I’m not sure that’s quite enough to be really useful, though; while that lets you say “instantiate the vtable here”, there doesn’t seem to be a way to say “do not instantiate the vtable here; it was instantiated elsewhere”.

If we can just quietly let that extension die, I think the world would be a better place. The basic idea isn’t bad, but it obviously only uses static and inline because there’s already parser support for them.

If we’re thinking of adding a vendor-specific attribute, why don’t we just add an attribute to mark an explicit instantiation def/decl as only instantiating the class data? Or even just propose that as a feature to the committee? For the latter, I think the obvious spelling would be (with or without parens):

‘extern’? ‘typeid’ ‘(’ type-id ‘)’

Separating this from explicit instantiations would also let it apply to arbitrary other class types, not just templates, which would be nice for micro-optimizing code that uses RTTI but can’t reasonably use key functions (as well as ABIs that don’t provide key-function-like optimizations). If RTTI is disabled, we’d just emit the v-table, and we’d complain if the class wasn’t polymorphic. I guess emitting v-tables in addition to RTTI would prevent someone from using this just to define the RTTI and not the v-table, but… I can’t imagine why someone would want to do that.

John.

I’ve given more thought to Richard’s suggestion. I’m fully on-board with having a way to externally declare and explicitly instantiate typeids and vtables for arbitrary classes (templates or not). I think that’s a great idea that fills a need and I’m willing to pursue a standard proposal that does that.

However, I’m concerned about making libc++’s ability to drop always_inline contingent on such a feature or compiler extension for the following reasons:

  • We have to make sure libc++ still works with GCC. If we wanted to use this hypothetical compiler extension in libc++, we’d have to keep the same annotations as today, but also add the explicit declarations of what’s in the ABI. This increases the complexity of libc++’s visibility system significantly, and that complexity is already too high.

Do you care about supporting more than GCC? If GCC supports the extension Richard linked, then the opt-in strategy can be made portable. But if you care about supporting arbitrary other compilers, that’s tricky.

John.

Hi,

This message is related to solving the issue explained at [1], and indirectly, the usage of always_inline in libc++ as explained at [2].

I’ve been looking to add an attribute (tentatively called no_extern_template) which would prevent member functions in a template from getting available_externally linkage even when there is a matching extern template declaration. In other words, given the following code:

template
struct Foo { void func() { } };
extern template struct Foo;

void use() {
Foo f;
f.func();
}

it is possible for Clang to emit a call to the extern function Foo<int>::func(), because the extern template declaration promises that it exists somewhere else in the program. Clang could also decide to inline the function and generate no extern call, but it does not have to. What I want is an attribute that inhibits generating an external call, i.e. that makes sure Foo<int>::func() is either emitted in this TU despite the extern template declaration, or inlined (in which case a definition is obviously not needed). If the function is emitted, it should be emitted with proper linkage, in this case linkonce_odr (IIUC). The attribute would be applied to the member function that should be opted-out of the extern template declaration, like so:

template
struct Foo { attribute((no_extern_template)) void func() { } };
extern template struct Foo;

I’d like to have some feedback on this idea, specifically:

  • What entities does it make sense to apply this attribute to? Currently, I’m thinking only static and non-static member functions of templates, for lack of imagination and other use cases. Does it make sense to apply it to static data members? To the vtable and RTTI somehow?

  • What other attributes would be mutually exclusive with this one? Right now I can only think of internal_linkage, but is there anything else?

Finally, I’d also welcome any guidance on how to best achieve this in Clang. So far, I’ve achieved something that “works” by forcing declarations with GVA_AvailableExternally linkage to have GVA_DiscardableODR linkage (in adjustGVALinkageForAttributes). I think this is probably the wrong approach but I’m a Clang beginner, so I’m looking for advice if somebody has some. I’ll soon publish an early code review on Phabricator to ease the process of getting feedback on the code itself.

FWIW, I’d implement this by skipping members that are declared with the attribute in this loop: https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaTemplateInstantiate.cpp#L2561

I don’t necessarily want to redirect you from this course of action; pragmatically-speaking, the attribute you’re proposing seems very reasonable to me, and is probably the right short-to-medium-term solution. However:

It seems to me there are two different compilations that we need to care about:

  1. the compilation of the DSO itself
  2. the compilation of a user of the DSO

For (1), we would need to use a compiler that can force-emit the vtable, ideally without emitting all inline functions in the class. (If it emits too much, we do have ways to prevent the extra symbols being part of the DSO’s ABI, but it’s not ideal.) Any version of GCC can do that (via “inline template”), and if we add a standard or vendor-specific feature to clang to emit the type info, then recent Clang can do that too. Older Clang and other compilers will be left emitting too many symbols, which is likely tolerable, because the result should still be correct and building a new libc++ DSO with an old Clang is likely something we can discourage.

It may be inadvisable anyway to link against a DSO build that is not widely distributed; however, binaries linked against a DSO build that exports too much will not load against “proper” DSO builds.

I don’t necessarily want to redirect you from this course of action; pragmatically-speaking, the attribute you’re proposing seems very reasonable to me, and is probably the right short-to-medium-term solution. However:

It seems to me there are two different compilations that we need to care about:

  1. the compilation of the DSO itself
  2. the compilation of a user of the DSO

For (1), we would need to use a compiler that can force-emit the vtable, ideally without emitting all inline functions in the class. (If it emits too much, we do have ways to prevent the extra symbols being part of the DSO’s ABI, but it’s not ideal.) Any version of GCC can do that (via “inline template”), and if we add a standard or vendor-specific feature to clang to emit the type info, then recent Clang can do that too. Older Clang and other compilers will be left emitting too many symbols, which is likely tolerable, because the result should still be correct and building a new libc++ DSO with an old Clang is likely something we can discourage.

It may be inadvisable anyway to link against a DSO build that is not widely distributed; however, binaries linked against a DSO build that exports too much will not load against “proper” DSO builds.

I think we’d only be considering a DSO that contains too much, not one that exports too much; we would presumably still use an explicit export list to control the exported symbols.

Hi,

This message is related to solving the issue explained at [1], and indirectly, the usage of always_inline in libc++ as explained at [2].

I’ve been looking to add an attribute (tentatively called no_extern_template) which would prevent member functions in a template from getting available_externally linkage even when there is a matching extern template declaration. In other words, given the following code:

template
struct Foo { void func() { } };
extern template struct Foo;

void use() {
Foo f;
f.func();
}

it is possible for Clang to emit a call to the extern function Foo<int>::func(), because the extern template declaration promises that it exists somewhere else in the program. Clang could also decide to inline the function and generate no extern call, but it does not have to. What I want is an attribute that inhibits generating an external call, i.e. that makes sure Foo<int>::func() is either emitted in this TU despite the extern template declaration, or inlined (in which case a definition is obviously not needed). If the function is emitted, it should be emitted with proper linkage, in this case linkonce_odr (IIUC). The attribute would be applied to the member function that should be opted-out of the extern template declaration, like so:

template
struct Foo { attribute((no_extern_template)) void func() { } };
extern template struct Foo;

I’d like to have some feedback on this idea, specifically:

I think I’m following what you’re asking for: the idea is that an explicit instantiation declaration for the class would not be treated as an explicit instantiation declaration for the members of the class that have the attribute, right? So the desired behavior for:

template struct Foo { // non-polymorphic class
void foo() { }
attribute((no_extern_template)) void bar() { }

void baz() { }

};
extern template struct Foo;

would be exactly the same as the standard behavior of:

template struct Foo {
void foo() { }
void bar() { }

void baz() { }

};
extern void Foo::foo();

extern void Foo::baz();

Yes, this is what I’m asking for.

except that this is an opt-out mechanism whereas the standard mechanism is opt-in. (For polymorphic class types, there’s more differences, as explicit instantiations can also affect where vtables are emitted.)

Given that (I’m guessing) the idea is to more precisely control which functions are part of the libc++ DSO’s ABI, have you considered explicitly listing those functions (that is, following the opt-in strategy) rather than adding an opt-out mechanism? That seems to give more direct control over the ABI surface, albeit at the cost of presumably making the header larger. Is there a reason that approach won’t work or is undesirable?

We’ve talked about it in the thread starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058519.html. I think this is a superior solution because it would create a very clear list of what’s in the ABI. It might be tedious to create (lots of boilerplate declarations), but that’s not a huge concern IMO.

However, the reason why this is not feasible right now is that we lack a way to declare an extern instantiation of a vtable and RTTI, and to explicitly instantiate those. I guess we could either add an extension that allows that and/or try standardizing a feature that allows that. I think standardizing a way of doing this would be useful nonetheless — it would for example remove the need for anchor functions to pick which TU the vtable is emitted in, which is kind of a hack.

GCC for many years had an extension to do this: https://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html (see the bottom of the page).

It’s long been on our list of “potentially useful GCC extensions we never got around to implementing”. I’m not sure that’s quite enough to be really useful, though; while that lets you say “instantiate the vtable here”, there doesn’t seem to be a way to say “do not instantiate the vtable here; it was instantiated elsewhere”.

If we can just quietly let that extension die, I think the world would be a better place. The basic idea isn’t bad, but it obviously only uses static and inline because there’s already parser support for them.

If we’re thinking of adding a vendor-specific attribute, why don’t we just add an attribute to mark an explicit instantiation def/decl as only instantiating the class data? Or even just propose that as a feature to the committee? For the latter, I think the obvious spelling would be (with or without parens):

‘extern’? ‘typeid’ ‘(’ type-id ‘)’

Separating this from explicit instantiations would also let it apply to arbitrary other class types, not just templates, which would be nice for micro-optimizing code that uses RTTI but can’t reasonably use key functions (as well as ABIs that don’t provide key-function-like optimizations). If RTTI is disabled, we’d just emit the v-table, and we’d complain if the class wasn’t polymorphic. I guess emitting v-tables in addition to RTTI would prevent someone from using this just to define the RTTI and not the v-table, but… I can’t imagine why someone would want to do that.

John.

I’ve given more thought to Richard’s suggestion. I’m fully on-board with having a way to externally declare and explicitly instantiate typeids and vtables for arbitrary classes (templates or not). I think that’s a great idea that fills a need and I’m willing to pursue a standard proposal that does that.

However, I’m concerned about making libc++’s ability to drop always_inline contingent on such a feature or compiler extension for the following reasons:

  • We have to make sure libc++ still works with GCC. If we wanted to use this hypothetical compiler extension in libc++, we’d have to keep the same annotations as today, but also add the explicit declarations of what’s in the ABI. This increases the complexity of libc++’s visibility system significantly, and that complexity is already too high.

Do you care about supporting more than GCC? If GCC supports the extension Richard linked, then the opt-in strategy can be made portable. But if you care about supporting arbitrary other compilers, that’s tricky.

Based on __config, we seem to support Clang, GCC, MSVC and IBM’s compiler:

#if defined(clang)

define _LIBCPP_COMPILER_CLANG

#elif defined(GNUC)

define _LIBCPP_COMPILER_GCC

#elif defined(_MSC_VER)

define _LIBCPP_COMPILER_MSVC

#elif defined(IBMCPP)

define _LIBCPP_COMPILER_IBM

I don’t know what level of support we have in each of those compilers, since that does not seem to be documented officially.

Louis

Hi,

This message is related to solving the issue explained at [1], and indirectly, the usage of always_inline in libc++ as explained at [2].

I’ve been looking to add an attribute (tentatively called no_extern_template) which would prevent member functions in a template from getting available_externally linkage even when there is a matching extern template declaration. In other words, given the following code:

template
struct Foo { void func() { } };
extern template struct Foo;

void use() {
Foo f;
f.func();
}

it is possible for Clang to emit a call to the extern function Foo<int>::func(), because the extern template declaration promises that it exists somewhere else in the program. Clang could also decide to inline the function and generate no extern call, but it does not have to. What I want is an attribute that inhibits generating an external call, i.e. that makes sure Foo<int>::func() is either emitted in this TU despite the extern template declaration, or inlined (in which case a definition is obviously not needed). If the function is emitted, it should be emitted with proper linkage, in this case linkonce_odr (IIUC). The attribute would be applied to the member function that should be opted-out of the extern template declaration, like so:

template
struct Foo { attribute((no_extern_template)) void func() { } };
extern template struct Foo;

I’d like to have some feedback on this idea, specifically:

I think I’m following what you’re asking for: the idea is that an explicit instantiation declaration for the class would not be treated as an explicit instantiation declaration for the members of the class that have the attribute, right? So the desired behavior for:

template struct Foo { // non-polymorphic class
void foo() { }
attribute((no_extern_template)) void bar() { }

void baz() { }

};
extern template struct Foo;

would be exactly the same as the standard behavior of:

template struct Foo {
void foo() { }
void bar() { }

void baz() { }

};
extern void Foo::foo();

extern void Foo::baz();

Yes, this is what I’m asking for.

except that this is an opt-out mechanism whereas the standard mechanism is opt-in. (For polymorphic class types, there’s more differences, as explicit instantiations can also affect where vtables are emitted.)

Given that (I’m guessing) the idea is to more precisely control which functions are part of the libc++ DSO’s ABI, have you considered explicitly listing those functions (that is, following the opt-in strategy) rather than adding an opt-out mechanism? That seems to give more direct control over the ABI surface, albeit at the cost of presumably making the header larger. Is there a reason that approach won’t work or is undesirable?

We’ve talked about it in the thread starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058519.html. I think this is a superior solution because it would create a very clear list of what’s in the ABI. It might be tedious to create (lots of boilerplate declarations), but that’s not a huge concern IMO.

However, the reason why this is not feasible right now is that we lack a way to declare an extern instantiation of a vtable and RTTI, and to explicitly instantiate those. I guess we could either add an extension that allows that and/or try standardizing a feature that allows that. I think standardizing a way of doing this would be useful nonetheless — it would for example remove the need for anchor functions to pick which TU the vtable is emitted in, which is kind of a hack.

GCC for many years had an extension to do this: https://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html (see the bottom of the page).

It’s long been on our list of “potentially useful GCC extensions we never got around to implementing”. I’m not sure that’s quite enough to be really useful, though; while that lets you say “instantiate the vtable here”, there doesn’t seem to be a way to say “do not instantiate the vtable here; it was instantiated elsewhere”.

If we can just quietly let that extension die, I think the world would be a better place. The basic idea isn’t bad, but it obviously only uses static and inline because there’s already parser support for them.

If we’re thinking of adding a vendor-specific attribute, why don’t we just add an attribute to mark an explicit instantiation def/decl as only instantiating the class data? Or even just propose that as a feature to the committee? For the latter, I think the obvious spelling would be (with or without parens):

‘extern’? ‘typeid’ ‘(’ type-id ‘)’

Separating this from explicit instantiations would also let it apply to arbitrary other class types, not just templates, which would be nice for micro-optimizing code that uses RTTI but can’t reasonably use key functions (as well as ABIs that don’t provide key-function-like optimizations). If RTTI is disabled, we’d just emit the v-table, and we’d complain if the class wasn’t polymorphic. I guess emitting v-tables in addition to RTTI would prevent someone from using this just to define the RTTI and not the v-table, but… I can’t imagine why someone would want to do that.

John.

I’ve given more thought to Richard’s suggestion. I’m fully on-board with having a way to externally declare and explicitly instantiate typeids and vtables for arbitrary classes (templates or not). I think that’s a great idea that fills a need and I’m willing to pursue a standard proposal that does that.

However, I’m concerned about making libc++’s ability to drop always_inline contingent on such a feature or compiler extension for the following reasons:

  • We have to make sure libc++ still works with GCC. If we wanted to use this hypothetical compiler extension in libc++, we’d have to keep the same annotations as today, but also add the explicit declarations of what’s in the ABI. This increases the complexity of libc++’s visibility system significantly, and that complexity is already too high.

Do you care about supporting more than GCC? If GCC supports the extension Richard linked, then the opt-in strategy can be made portable. But if you care about supporting arbitrary other compilers, that’s tricky.

Based on __config, we seem to support Clang, GCC, MSVC and IBM’s compiler:

#if defined(clang)

define _LIBCPP_COMPILER_CLANG

#elif defined(GNUC)

define _LIBCPP_COMPILER_GCC

#elif defined(_MSC_VER)

define _LIBCPP_COMPILER_MSVC

#elif defined(IBMCPP)

define _LIBCPP_COMPILER_IBM

I don’t know what level of support we have in each of those compilers, since that does not seem to be documented officially.

Okay. So, per Richard’s suggestion, is there anything reasonable we could do in MSVC and IBM if we wanted to switch to opt-in instantiation? Would we just have to have an instantiation of the entire class in the library?

I don’t know what the ABI-stability requirements are on those ports.

John.