<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Tue, Aug 21, 2018 at 2:44 PM Louis Dionne via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">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:<br></blockquote><div><br></div><div>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.<br></div><div><br></div><div>Is the original problem limited to the __init pattern (below), or are is needed for more than that?</div><div>    template <class T><br>    struct Foo {<br>        inline __attribute__((visibility("hidden")))<br>        int __init(int x) { /* LOTS OF CODE */ }<br><br>        inline __attribute__((visibility("default")))<br>        int bar(int x) { return __init(x); }<br>    };  <br></div><div><br></div><div>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.</div><div><br></div><div>We had a very similar to a problem with dllimport, which also uses available_externally. This is the situation:</div><div><br></div><div>#if BUILDING_FOO</div><div>#define FOO_EXPORT __declspec(dllexport)</div><div>#else</div><div>#define FOO_EXPORT __declspec(dllimport)  <br></div><div>#endif</div><div>struct Foo {</div><div>  void bar();</div><div>  void FOO_EXPORT foo() { bar(); }<br>};</div><div><br></div><div>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.</div><div><br></div><div>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.</div></div></div>