<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Aug 21, 2014 at 6:22 PM, Michael Park <span dir="ltr"><<a href="mailto:mcypark@gmail.com" target="_blank">mcypark@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr">Hi Richard, thanks for the reply!<div><br></div>
<div>Funnily enough, the member functions of local classes that have deduced return types actually don't run into this problem because the definition gets instantiated eagerly in order to deduce the return type.</div>
<div>So the following actually works in clang++-3.4.2.</div><div><br></div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class="">
template <typename T><br>void F() {<br> struct Num {<br></div> static constexpr auto Get() { return 42; }<br> };<br> static_assert(Num::Get() == 42, "");<div class=""><br>}<br>int main() {<br> F<int>();<br>
}</div></blockquote>
<div><br>
</div><div> I tried the recommended approach of instantiating at the end of the local class instead, like so:</div></div><div><br></div><div><div class=""><blockquote style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex" class="gmail_quote">
// DR1484 clarifies that the members of a local class are instantiated as part<br>// of the instantiation of their enclosing entity.<br>if (D->isCompleteDefinition() && D->isLocalClass()) {<br> SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs,<br>
TSK_ImplicitInstantiation,<br> /*Complain=*/true);<br> SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,<br> TSK_ImplicitInstantiation);<br>
</blockquote></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><b> SemaRef.PerformPendingInstantiations(/*LocalOnly=*/true);</b> </blockquote>
<blockquote style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex" class="gmail_quote">}</blockquote><div><br></div><div>Although there are <b>PeformPendingInstantiations </b>calls that should be removed, it effectively will be a no-op so I just tried this out for now.</div>
<div>It actually passes <b>make test</b> and also passes the example above!<br></div></div><div><br></div><div>But I worry that instantiating at the end of the local class is still too late, because I run into the same issue if I bring the <b>static_assert</b> into the body of the local struct.</div>
<div><br></div><div><div class=""><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">template <typename T> </blockquote>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">void F() {</blockquote></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class="">
struct Num {<br> static constexpr int Get() { return 42; }<br></div> static_assert(range == 42, "");<br> };</blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
}</blockquote></div></div></blockquote><div><br></div><div>The core language is somewhat unclear on whether that's supposed to work. Note that it doesn't work if F is not a template. I think the standard committee will end up deciding that this case is ill-formed, so I'm happy for us to reject it for now.</div>
<div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div>This case also works if I change the return type of <b>Get</b> to <b>auto</b>.</div>
<div><br></div><div>Even I bring out the local struct to namespace scope, it still breaks. But I think this might be a different bug. (In this case changing <b>Get</b>'s return type to <b>auto</b> doesn't resolve the problem.)</div>
</div></blockquote><div><br></div><div>=) Yep. See <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1626">http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1626</a></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div dir="ltr"><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class="">struct Num {<br> static constexpr int Get() { return 42; }<br>
</div>
static_assert(Get() == 42, "");<br>};</blockquote><div><br></div><div>P.S. Thanks so much for helping out.</div></div></div><div class=""><div class="h5"><div class="gmail_extra"><br><br><div class="gmail_quote">
On 20 August 2014 22:31, Richard Smith <span dir="ltr"><<a href="mailto:richard@metafoo.co.uk" target="_blank">richard@metafoo.co.uk</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">
<div>On Tue, Aug 12, 2014 at 8:09 PM, Michael Park <span dir="ltr"><<a href="mailto:mcypark@gmail.com" target="_blank">mcypark@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div>Hello,</div></div></blockquote><div><br>
</div></div><div>Hi and welcome! (And sorry for the delay.)</div><div><div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div dir="ltr"><div>I'm new to clang development and was hoping to get some help in tackling this bug that I found/filed: <a href="http://llvm.org/bugs/show_bug.cgi?id=20625" target="_blank">http://llvm.org/bugs/show_bug.cgi?id=20625</a></div>
<div><br></div><div>Example:</div><div><br></div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">template <typename T><br>
void F() {<br> struct Num {<br> static constexpr int Get() { return 42; }<br> };<br> constexpr int n = Num::Get();<br>}<br>int main() {<br> F<int>();<br>}</blockquote></div><div><br></div><div>The summary of the issue is that the local struct <b>Num</b> and its static constexpr function <b>Get</b> is not yet instantiated when we validate the constexpr variable initialization of <b>n</b> during <b>F</b>'s instantiation.</div>
<div><br></div><div>More details:</div><div><br></div><div><div><b>Num</b> and <b>Get</b> gets added to <b>PendingLocalImplicitInstantiations</b> in <b>SubstStmt</b> at <i>SemaTemplateInstantiationDecl.cpp:3437</i>, and is instantiated later by <b>PerformPendingInstantiations</b> at<b> </b><i>SemaTemplateInstantiationDecl.cpp:3458</i>. However, the validation of the constexpr variable initialization of <b>n</b> happens in <b>SubstStmt</b> at which point we don't yet have the definition of <b>Get</b> instantiated.</div>
<div><br></div></div><div>I'm not exactly sure what the correct approach would be to solve the problem. It seems that the local implicit instantiations need to be performed earlier, or the validation of constexpr variables need to be delayed.</div>
<div><br></div><div>If someone can point me in the right direction it would be appreciated.</div></div></blockquote><div><br></div></div></div><div>The implicit instantiations should be performed sooner. (FWIW, the same problem will affect member functions of local classes that have deduced return types.) Perhaps the easiest way to address this would be to perform all the local implicit instantiations discovered while instantiating a local class when we reach the end of that local class, instead of delaying them until the end of the surrounding function. We try to delay these instantiations as much as we can, to reduce the stack usage in recursive template instantiation, but that's probably not going to be significant here because there's not likely to be many layers of AST between the function and the class definition.</div>
<div><br></div><div>One place to put this fix would be around SemaTemplateInstantiateDecl.cpp:1104:</div><div><br></div><div><div> // DR1484 clarifies that the members of a local class are instantiated as part</div><div>
// of the instantiation of their enclosing entity.</div><div> if (D->isCompleteDefinition() && D->isLocalClass()) {</div><div> SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs,</div>
<div> TSK_ImplicitInstantiation,</div><div> /*Complain=*/true);</div><div> SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,</div><div> TSK_ImplicitInstantiation);</div>
<div> }</div></div><div><br></div><div>You could save, perform, and restore the pending local implicit instantiations around these calls.</div></div></div></div>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div></div>