From 3280b3307f67d5b7406c6d8d3b451ddd0aad8832 Mon Sep 17 00:00:00 2001 From: Hubert Tong Date: Thu, 25 Jun 2015 00:25:49 +0000 Subject: [PATCH] Consolidate and unify initializer list deduction Summary: This patch reduces duplication in the template argument deduction code for handling deduction from initializer lists in a function call. This extends the fix for PR12119 to also apply to the case where the corresponding parameter is a trailing parameter pack. Test Plan: A test for deduction from nested initializer lists where the corresponding parameter is a trailing parameter pack is added in `clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp`. Reviewers: fraggamuffin, rsmith Reviewed By: rsmith Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D10681 llvm-svn: 240612 --- clang/lib/Sema/SemaTemplateDeduction.cpp | 82 +++++++++++++--------- .../cxx0x-initializer-stdinitializerlist.cpp | 7 ++ 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 6f676ad..02e59af 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3190,6 +3190,40 @@ static bool hasDeducibleTemplateParameters(Sema &S, FunctionTemplateDecl *FunctionTemplate, QualType T); +static Sema::TemplateDeductionResult DeduceTemplateArgumentByListElement( + Sema &S, TemplateParameterList *TemplateParams, QualType ParamType, + Expr *Arg, TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced, unsigned TDF); + +/// \brief Attempt template argument deduction from an initializer list +/// deemed to be an argument in a function call. +static bool +DeduceFromInitializerList(Sema &S, TemplateParameterList *TemplateParams, + QualType AdjustedParamType, InitListExpr *ILE, + TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced, + unsigned TDF, Sema::TemplateDeductionResult &Result) { + // If the argument is an initializer list 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 as-if it were an argument in a function call, and + // the result is the deduced type if it's the same for all elements. + QualType X; + if (!S.isStdInitializerList(AdjustedParamType, &X)) + return false; + + Result = Sema::TDK_Success; + + // Recurse down into the init list. + for (unsigned i = 0, e = ILE->getNumInits(); i < e; ++i) { + if ((Result = DeduceTemplateArgumentByListElement( + S, TemplateParams, X, ILE->getInit(i), Info, Deduced, TDF))) + return true; + } + + return true; +} + /// \brief Perform template argument deduction by matching a parameter type /// against a single expression, where the expression is an element of /// an initializer list that was originally matched against a parameter @@ -3204,19 +3238,13 @@ DeduceTemplateArgumentByListElement(Sema &S, // Handle the case where an init list contains another init list as the // element. if (InitListExpr *ILE = dyn_cast(Arg)) { - QualType X; - if (!S.isStdInitializerList(ParamType.getNonReferenceType(), &X)) + Sema::TemplateDeductionResult Result; + if (!DeduceFromInitializerList(S, TemplateParams, + ParamType.getNonReferenceType(), ILE, Info, + Deduced, TDF, Result)) return Sema::TDK_Success; // Just ignore this expression. - // Recurse down into the init list. - for (unsigned i = 0, e = ILE->getNumInits(); i < e; ++i) { - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentByListElement(S, TemplateParams, X, - ILE->getInit(i), - Info, Deduced, TDF)) - return Result; - } - return Sema::TDK_Success; + return Result; } // For all other cases, just match by type. @@ -3335,22 +3363,14 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // 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; + TemplateDeductionResult Result; // Removing references was already done. - if (!isStdInitializerList(ParamType, &X)) + if (!DeduceFromInitializerList(*this, TemplateParams, ParamType, ILE, + Info, Deduced, TDF, Result)) continue; - for (unsigned i = 0, e = ILE->getNumInits(); i < e; ++i) { - if (TemplateDeductionResult Result = - DeduceTemplateArgumentByListElement(*this, TemplateParams, X, - ILE->getInit(i), - Info, Deduced, TDF)) - return Result; - } + if (Result) + return Result; // Don't track the argument type, since an initializer list has none. continue; } @@ -3406,19 +3426,15 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // As above, initializer lists need special handling. if (InitListExpr *ILE = dyn_cast(Arg)) { - QualType X; - if (!isStdInitializerList(ParamType, &X)) { + TemplateDeductionResult Result; + if (!DeduceFromInitializerList(*this, TemplateParams, ParamType, ILE, + Info, Deduced, TDF, Result)) { ++ArgIdx; break; } - 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; - } + if (Result) + return Result; } else { // Keep track of the argument type and corresponding argument index, diff --git a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp index a78f022..9456dd7 100644 --- a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -275,3 +275,10 @@ namespace TemporaryInitListSourceRange_PR22367 { {0} ); } + +namespace ParameterPackNestedInitializerLists_PR23904c3 { + template + void f(std::initializer_list> ...tt); + + void foo() { f({{0}}, {{'\0'}}); } +} -- 2.7.4