<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div><blockquote type="cite" class=""><div class="">On Aug 22, 2018, at 8:41 PM, Richard Smith via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a>> wrote:</div><div class=""><div dir="ltr" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><div class="gmail_quote"><div dir="ltr" class="">On Wed, 22 Aug 2018 at 08:39, Louis Dionne via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Aug 21, 2018, at 18:21, Richard Smith <<a href="mailto:richard@metafoo.co.uk" target="_blank" class="">richard@metafoo.co.uk</a>> wrote:</div><br class="gmail-m_8602693362901822949Apple-interchange-newline"><div class=""><div dir="ltr" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; text-decoration: none;" class=""><div class="gmail_quote"><div dir="ltr" class="">On Tue, 21 Aug 2018 at 14:44, Louis Dionne via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank" class="">cfe-dev@lists.llvm.org</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;">Hi,<br class=""><br class="">This message is related to solving the issue explained at [1], and indirectly, the usage of __always_inline__ in libc++ as explained at [2].<br class=""><br class="">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 class=""><br class="">   <span class="gmail-m_8602693362901822949Apple-converted-space"> </span>template <class T><br class="">   <span class="gmail-m_8602693362901822949Apple-converted-space"> </span>struct Foo { void func() { } };<br class="">   <span class="gmail-m_8602693362901822949Apple-converted-space"> </span>extern template struct Foo<int>;<br class=""><br class="">   <span class="gmail-m_8602693362901822949Apple-converted-space"> </span>void use() {<br class="">     <span class="gmail-m_8602693362901822949Apple-converted-space"> </span>Foo<int> f;<br class="">     <span class="gmail-m_8602693362901822949Apple-converted-space"> </span>f.func();<br class="">   <span class="gmail-m_8602693362901822949Apple-converted-space"> </span>}<br class=""><br class="">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:<br class=""><br class="">   <span class="gmail-m_8602693362901822949Apple-converted-space"> </span>template <class T><br class="">   <span class="gmail-m_8602693362901822949Apple-converted-space"> </span>struct Foo { __attribute__((no_extern_template)) void func() { } };<br class="">   <span class="gmail-m_8602693362901822949Apple-converted-space"> </span>extern template struct Foo<int>;<br class=""><br class="">I'd like to have some feedback on this idea, specifically:<br class=""></blockquote><div class=""><br class=""></div><div class="">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:</div><div class=""><br class=""></div><div class=""><div class="">template <class T> struct Foo { // non-polymorphic class</div><div class=""> <span class="Apple-converted-space"> </span>void foo() { }</div><div class=""> <span class="Apple-converted-space"> </span>__attribute__((no_extern_template)) void bar() { }<br class=""></div><div class=""> <span class="Apple-converted-space"> </span>void baz() { }<br class=""></div><div class="">};</div><div class="">extern template struct Foo<int>;</div></div><div class=""><br class=""></div><div class="">would be exactly the same as the standard behavior of:</div><div class=""><br class=""></div><div class=""><div class=""><div class="">template <class T> struct Foo {</div><div class=""> <span class="Apple-converted-space"> </span>void foo() { }</div><div class=""> <span class="Apple-converted-space"> </span>void bar() { }<br class=""></div><div class=""> <span class="Apple-converted-space"> </span>void baz() { }<br class=""></div><div class="">};</div><div class="">extern void Foo<int>::foo();</div></div></div><div class="">extern void Foo<int>::baz();<br class=""></div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Yes, this is what I’m asking for.</div><div class=""><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; text-decoration: none;" class=""><div class="gmail_quote"><div class="">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.)</div><div class=""><br class=""></div><div class="">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?</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">We’ve talked about it in the thread starting here: <a href="http://lists.llvm.org/pipermail/cfe-dev/2018-July/058519.html" target="_blank" class="">http://lists.llvm.org/pipermail/cfe-dev/2018-July/058519.html</a>. 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.</div><div class=""><br class=""></div><div class="">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.</div></div></div></blockquote><div class=""><br class=""></div><div class="">GCC for many years had an extension to do this:<span class="Apple-converted-space"> </span><a href="https://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html" class="">https://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html</a><span class="Apple-converted-space"> </span>(see the bottom of the page).</div><div class=""><br class=""></div><div class="">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".</div></div></div></div></blockquote><div><br class=""></div>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.</div><div><br class=""></div><div>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):</div><div><br class=""></div><div>  'extern'? 'typeid' '(' type-id ')'</div><div><br class=""></div><div>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.</div><div><br class=""></div><div>John.</div><div> <br class=""><blockquote type="cite" class=""><div dir="ltr" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><div class="">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.</div><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><div class="">Louis</div><div class=""><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; text-decoration: none;" class=""><div class="gmail_quote"><div class=""><br class="gmail-m_8602693362901822949gmail-Apple-interchange-newline"></div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;">- 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?<br class=""><br class="">- What other attributes would be mutually exclusive with this one? Right now I can only think of `internal_linkage`, but is there anything else?<br class=""><br class="">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.<br class=""><br class="">Thanks,<br class="">Louis<br class=""><br class="">[1]:<span class="gmail-m_8602693362901822949Apple-converted-space"> </span><a href="http://lists.llvm.org/pipermail/cfe-dev/2018-July/058460.html" rel="noreferrer" target="_blank" class="">http://lists.llvm.org/pipermail/cfe-dev/2018-July/058460.html</a><br class="">[2]:<span class="gmail-m_8602693362901822949Apple-converted-space"> </span><a href="http://lists.llvm.org/pipermail/cfe-dev/2018-July/058419.html" rel="noreferrer" target="_blank" class="">http://lists.llvm.org/pipermail/cfe-dev/2018-July/058419.html</a><br class=""><br class="">_______________________________________________<br class="">cfe-dev mailing list<br class=""><a href="mailto:cfe-dev@lists.llvm.org" target="_blank" class="">cfe-dev@lists.llvm.org</a><br class=""><a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank" class="">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a></blockquote></div></div></div></blockquote></div><br class=""></div>_______________________________________________<br class="">cfe-dev mailing list<br class=""><a href="mailto:cfe-dev@lists.llvm.org" target="_blank" class="">cfe-dev@lists.llvm.org</a><br class=""><a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank" class="">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br class=""></blockquote></div></div><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">_______________________________________________</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">cfe-dev mailing list</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><a href="mailto:cfe-dev@lists.llvm.org" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">cfe-dev@lists.llvm.org</a><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a></blockquote></div><br class=""></body></html>