From: Sebastian Redl Date: Tue, 17 Jan 2012 22:49:58 +0000 (+0000) Subject: Template argument deduction for std::initializer_list arguments from initializer... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=84760e3a5d885ab19b5d11aafe78dfdfe2911e3a;p=clang Template argument deduction for std::initializer_list arguments from initializer lists. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148352 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 85c292ff4c..13face95e9 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5777,19 +5777,29 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) { if (!StdNamespace) // If we haven't seen namespace std yet, this can't be it. return false; - const RecordType *RT = Ty->getAs(); - if (!RT) - return false; + ClassTemplateDecl *Template = 0; + const TemplateArgument *Arguments = 0; - ClassTemplateSpecializationDecl *Specialization = - dyn_cast(RT->getDecl()); - if (!Specialization) - return false; + if (const RecordType *RT = Ty->getAs()) { - if (Specialization->getSpecializationKind() != TSK_ImplicitInstantiation) - return false; + ClassTemplateSpecializationDecl *Specialization = + dyn_cast(RT->getDecl()); + if (!Specialization) + return false; - ClassTemplateDecl *Template = Specialization->getSpecializedTemplate(); + if (Specialization->getSpecializationKind() != TSK_ImplicitInstantiation) + return false; + + Template = Specialization->getSpecializedTemplate(); + Arguments = Specialization->getTemplateArgs().data(); + } else if (const TemplateSpecializationType *TST = + Ty->getAs()) { + Template = dyn_cast_or_null( + TST->getTemplateName().getAsTemplateDecl()); + Arguments = TST->getArgs(); + } + if (!Template) + return false; if (!StdInitializerList) { // Haven't recognized std::initializer_list yet, maybe this is it. @@ -5814,9 +5824,8 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) { return false; // This is an instance of std::initializer_list. Find the argument type. - if (Element) { - *Element = Specialization->getTemplateArgs()[0].getAsType(); - } + if (Element) + *Element = Arguments[0].getAsType(); return true; } diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index ab2c2a3e67..738e596ef3 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2971,6 +2971,28 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, if (!hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) continue; + // If the argument is an initializer list ... + if (InitListExpr *ILE = dyn_cast(Arg)) { + // ... then the parameter is an undeduced context, unless the parameter + // type is (reference to cv) std::initializer_list, in which case + // deduction is done for each element of the initializer list, and the + // result is the deduced type if it's the same for all elements. + QualType X; + // Removing references was already done. + if (!isStdInitializerList(ParamType, &X)) + continue; + + for (unsigned i = 0, e = ILE->getNumInits(); i < e; ++i) { + if (TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, X, + ILE->getInit(i)->getType(), + Info, Deduced, TDF)) + return Result; + } + // Don't track the argument type, since an initializer list has none. + continue; + } + // Keep track of the argument type and corresponding parameter index, // so we can check for compatibility between the deduced A and A. OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1, @@ -3042,17 +3064,35 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, break; } - // Keep track of the argument type and corresponding argument index, - // so we can check for compatibility between the deduced A and A. - if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) - OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx, - ArgType)); + // As above, initializer lists need special handling. + if (InitListExpr *ILE = dyn_cast(Arg)) { + QualType X; + if (!isStdInitializerList(ParamType, &X)) { + ++ArgIdx; + break; + } - if (TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, - ParamType, ArgType, Info, - Deduced, TDF)) - return Result; + for (unsigned i = 0, e = ILE->getNumInits(); i < e; ++i) { + if (TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, X, + ILE->getInit(i)->getType(), + Info, Deduced, TDF)) + return Result; + } + } else { + + // Keep track of the argument type and corresponding argument index, + // so we can check for compatibility between the deduced A and A. + if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) + OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx, + ArgType)); + + if (TemplateDeductionResult Result + = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, + ParamType, ArgType, Info, + Deduced, TDF)) + return Result; + } // Capture the deduced template arguments for each parameter pack expanded // by this pack expansion, add them to the list of arguments we've deduced diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp index 87e7e8462b..a08a04806c 100644 --- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -32,6 +32,11 @@ namespace std { }; } +template +struct same_type { static const bool value = false; }; +template +struct same_type { static const bool value = true; }; + struct one { char c[1]; }; struct two { char c[2]; }; @@ -87,3 +92,20 @@ void overloaded_call() { // But here, user-defined is worst in both cases. ov2({1, 2, D()}); // expected-error {{ambiguous}} } + +template +T deduce(std::initializer_list); // expected-note {{conflicting types for parameter 'T' ('int' vs. 'double')}} +template +T deduce_ref(const std::initializer_list&); // expected-note {{conflicting types for parameter 'T' ('int' vs. 'double')}} + +void argument_deduction() { + static_assert(same_type::value, "bad deduction"); + static_assert(same_type::value, "bad deduction"); + + deduce({1, 2.0}); // expected-error {{no matching function}} + + static_assert(same_type::value, "bad deduction"); + static_assert(same_type::value, "bad deduction"); + + deduce_ref({1, 2.0}); // expected-error {{no matching function}} +}