<div dir="ltr">Hi Richard,<div><br></div><div>The following test triggers an assertion, even after this patch:</div><div><br></div><div><div>#include <memory></div><div>#include <string></div><div><br></div><div>template <class T></div><div>struct TestAlloc : std::allocator<T> {};</div><div><br></div><div>template <class Char, class Traits = std::char_traits<Char>,</div><div> class Allocator = std::allocator<Char>></div><div>struct String {</div><div> using size_type = typename Allocator::size_type;</div><div><br></div><div> String() = default;</div><div> String(const String&, size_type, size_type, const Allocator& = Allocator()) {}</div><div> String(String const&, size_type, const Allocator& = Allocator()) {}</div><div>};</div><div><br></div><div>int main() {</div><div> using BStr = String<char>;</div><div> BStr bs;</div><div> String s(bs, 1ul, 1ul, std::allocator<char>{});</div><div> static_assert(std::is_same_v<decltype(s), BStr>);</div><div>}</div></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Feb 13, 2017 at 6:50 PM, Richard Smith via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rsmith<br>
Date: Mon Feb 13 19:49:59 2017<br>
New Revision: 295016<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=295016&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=295016&view=rev</a><br>
Log:<br>
Canonicalize implicit deduction guide parameter types when forming a deduction<br>
guide from a constructor.<br>
<br>
The purpose of this change is to avoid triggering instantiation of the class<br>
when substituting back into the deduction guide if it uses a typedef member.<br>
We will still instantiate the class if the constructor (explicitly or<br>
implicitly, directly or indirectly) uses the current instantiation in a way<br>
that we can't canonicalize out, but that seems unavoidable.<br>
<br>
Modified:<br>
cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp<br>
cfe/trunk/test/SemaCXX/cxx1z-<wbr>class-template-argument-<wbr>deduction.cpp<br>
<br>
Modified: cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=295016&r1=295015&r2=295016&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp?rev=295016&<wbr>r1=295015&r2=295016&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp (original)<br>
+++ cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp Mon Feb 13 19:49:59 2017<br>
@@ -1585,12 +1585,7 @@ private:<br>
<br>
// -- The types of the function parameters are those of the constructor.<br>
for (auto *OldParam : TL.getParams()) {<br>
- // If we're transforming a non-template constructor, just reuse its<br>
- // parameters as the parameters of the deduction guide. Otherwise, we<br>
- // need to transform their references to constructor template parameters.<br>
- ParmVarDecl *NewParam = Args.getNumLevels()<br>
- ? transformFunctionTypeParam(<wbr>OldParam, Args)<br>
- : OldParam;<br>
+ ParmVarDecl *NewParam = transformFunctionTypeParam(<wbr>OldParam, Args);<br>
if (!NewParam)<br>
return QualType();<br>
ParamTypes.push_back(NewParam-<wbr>>getType());<br>
@@ -1636,16 +1631,31 @@ private:<br>
transformFunctionTypeParam(<wbr>ParmVarDecl *OldParam,<br>
MultiLevelTemplateArgumentList &Args) {<br>
TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo();<br>
- TypeSourceInfo *NewDI = SemaRef.SubstType(<br>
- OldDI, Args, OldParam->getLocation(), OldParam->getDeclName());<br>
+ TypeSourceInfo *NewDI =<br>
+ Args.getNumLevels()<br>
+ ? SemaRef.SubstType(OldDI, Args, OldParam->getLocation(),<br>
+ OldParam->getDeclName())<br>
+ : OldDI;<br>
if (!NewDI)<br>
return nullptr;<br>
<br>
+ // Canonicalize the type. This (for instance) replaces references to<br>
+ // typedef members of the current instantiations with the definitions of<br>
+ // those typedefs, avoiding triggering instantiation of the deduced type<br>
+ // during deduction.<br>
+ // FIXME: It would be preferable to retain type sugar and source<br>
+ // information here (and handle this in substitution instead).<br>
+ NewDI = SemaRef.Context.<wbr>getTrivialTypeSourceInfo(<br>
+ SemaRef.Context.<wbr>getCanonicalType(NewDI-><wbr>getType()),<br>
+ OldParam->getLocation());<br>
+<br>
// Resolving a wording defect, we also inherit default arguments from the<br>
// constructor.<br>
ExprResult NewDefArg;<br>
if (OldParam->hasDefaultArg()) {<br>
- NewDefArg = SemaRef.SubstExpr(OldParam-><wbr>getDefaultArg(), Args);<br>
+ NewDefArg = Args.getNumLevels()<br>
+ ? SemaRef.SubstExpr(OldParam-><wbr>getDefaultArg(), Args)<br>
+ : OldParam->getDefaultArg();<br>
if (NewDefArg.isInvalid())<br>
return nullptr;<br>
}<br>
<br>
Modified: cfe/trunk/test/SemaCXX/cxx1z-<wbr>class-template-argument-<wbr>deduction.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp?rev=295016&r1=295015&r2=295016&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>SemaCXX/cxx1z-class-template-<wbr>argument-deduction.cpp?rev=<wbr>295016&r1=295015&r2=295016&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/SemaCXX/cxx1z-<wbr>class-template-argument-<wbr>deduction.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/cxx1z-<wbr>class-template-argument-<wbr>deduction.cpp Mon Feb 13 19:49:59 2017<br>
@@ -136,4 +136,17 @@ namespace look_into_current_instantiatio<br>
B(typename X::type); // expected-note {{couldn't infer template argument 'T'}}<br>
};<br>
B b = 0; // expected-error {{no viable}}<br>
+<br>
+ // We should have a substitution failure in the immediate context of<br>
+ // deduction when using the C(T, U) constructor (probably; core wording<br>
+ // unclear).<br>
+ template<typename T> struct C {<br>
+ using U = typename T::type;<br>
+ C(T, U);<br>
+ };<br>
+<br>
+ struct R { R(int); typedef R type; };<br>
+ C(...) -> C<R>;<br>
+<br>
+ C c = {1, 2};<br>
}<br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>