<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Mon, Jul 7, 2014 at 6:01 AM, Logan Chien <span dir="ltr"><<a href="mailto:tzuhsiang.chien@gmail.com" target="_blank">tzuhsiang.chien@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><div>Ping?<br><br>This patch tries to fix an assertion failure related to the template alias with two (or more) parameter packs. For example,<div class="">
<br><br>
template <typename... T> struct tuple;<br></div><div class="">
template <typename... T> struct extract_;<br></div>template <typename... T> using extract = typename extract_<T...>::type;<div class=""><br>
template <typename... A, typename... B><br></div><div class="">
inline auto test(tuple<A...>&& xs, B&&... ys) -> extract<A&&..., B...> { }<br><br></div></div>Please have a look, and feel free to let me know if there is any problem. Thanks!<br></div>
</div></blockquote><div><br></div><div>Testcase reduced to:</div><div><br></div><div><div><div>template <typename... T> struct extract_;</div><div>template <typename... T> using extract = typename extract_<T...>::type;</div>
<div>template <typename... A, typename B> void test(extract<A..., B>);</div></div></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></div>
<div>Sincerely,<br></div>Logan<br></div><div class=""><div class="h5"><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Jun 30, 2014 at 1:10 AM, Logan Chien <span dir="ltr"><<a href="mailto:tzuhsiang.chien@gmail.com" target="_blank">tzuhsiang.chien@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">Hi rsmith,<br>
<br>
If the template has two variadic formal parameters, then the type<br>
might not be canonical. We have call ASTContext.getCanonicalType()<br>
to canonicalize the type; otherwise, an assertion failure will be<br>
raised.<br>
<br>
This patch fix this issue by adding getCanonicalType() in<br>
TransformTemplateTypeParmType.<br></blockquote></div></div></div></div></blockquote><div><br></div><div>This seems to be blindly addressing a symptom rather than going after the actual problem.</div><div><br></div><div>When we match the template arguments <A..., B> against the parameters of 'extract', we form <template-parameter-0-0..., B>. Note we canonicalize the first but not the second. This is because Sema::CheckTemplateArgumentList does no checking for template arguments after the first pack expansion:</div>
<div><br></div><div><div> // If we just saw a pack expansion, then directly convert the remaining</div><div> // arguments, because we don't know what parameters they'll match up</div><div> // with.</div>
</div><div><br></div><div>This means we fail to check or canonicalize any arguments after a pack expansion. With that knowledge in hand, here's a testcase for the same bug that your patch won't fix:</div><div><br>
</div><div><div> template <typename... T> struct extract_;</div><div> template <typename... T> using extract = typename extract_<T...>::type;</div><div> template <typename... A, typename B> void test(extract<A..., 123>);</div>
</div><div><br></div><div>The right fix here would be for CheckTemplateArgumentList to distinguish between the case where more substitution and expansion will be performed before the template is instantiated, and the case where it actually needs to match up the parameters and arguments properly.</div>
<div><br></div><div>And then in a case like this:</div><div><br></div><div> template<typename ...T> struct A {</div><div> template<T ...U, typename V> using B = V;</div><div> void f(B<T()..., int>);</div>
<div> };</div><div><br></div><div>(for which we currently reject-valid), if CheckTemplateArgumentList is called for an alias template, it needs to tell its caller to create a dependent type rather than performing a substitution.</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 class=""><div class="h5"><div class="gmail_extra">
<div class="gmail_quote"><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">
<a href="http://reviews.llvm.org/D4343" target="_blank">http://reviews.llvm.org/D4343</a><br>
<br>
Files:<br>
lib/Sema/SemaTemplateInstantiate.cpp<br>
test/SemaTemplate/alias-templates.cpp<br>
<br>
Index: lib/Sema/SemaTemplateInstantiate.cpp<br>
===================================================================<br>
--- lib/Sema/SemaTemplateInstantiate.cpp<br>
+++ lib/Sema/SemaTemplateInstantiate.cpp<br>
@@ -1376,7 +1376,7 @@<br>
assert(Arg.getKind() == TemplateArgument::Type &&<br>
"Template argument kind mismatch");<br>
<br>
- QualType Replacement = Arg.getAsType();<br>
+ QualType Replacement = getSema().Context.getCanonicalType(Arg.getAsType());<br>
<br>
// TODO: only do this uniquing once, at the start of instantiation.<br>
QualType Result<br>
Index: test/SemaTemplate/alias-templates.cpp<br>
===================================================================<br>
--- test/SemaTemplate/alias-templates.cpp<br>
+++ test/SemaTemplate/alias-templates.cpp<br>
@@ -201,3 +201,17 @@<br>
template <typename T, typename U, typename V><br>
using derived2 = ::PR16904::base<T, U>::template derived<V>; // expected-error {{expected a type}} expected-error {{expected ';'}}<br>
}<br>
+<br>
+namespace VariadicTemplateAlias {<br>
+ template <typename... T> struct tuple;<br>
+ template <typename... T> struct extract_;<br>
+<br>
+ // Note: Both the template alias and the concatenation of variadic template<br>
+ // arguments A and B are required to trigger the assertion failure.<br>
+<br>
+ template <typename... T><br>
+ using extract = typename extract_<T...>::type;<br>
+<br>
+ template <typename... A, typename... B><br>
+ inline auto test(tuple<A...>&& xs, B&&... ys) -> extract<A&&..., B...> { }<br>
+}<br>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div></div>