Author: rsmith Date: Wed Jan 4 13:47:19 2017 New Revision: 290996 URL: http://llvm.org/viewvc/llvm-project?rev=290996&view=rev Log: Factor out duplicated code and simplify.
No functionality change intended. Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=290996&r1=290995&r2=290996&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Jan 4 13:47:19 2017 @@ -3203,67 +3203,59 @@ static Sema::TemplateDeductionResult Ded /// \brief Attempt template argument deduction from an initializer list /// deemed to be an argument in a function call. -static bool +static Sema::TemplateDeductionResult DeduceFromInitializerList(Sema &S, TemplateParameterList *TemplateParams, QualType AdjustedParamType, InitListExpr *ILE, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced, - unsigned TDF, Sema::TemplateDeductionResult &Result) { - - // [temp.deduct.call] p1 (post CWG-1591) - // If removing references and cv-qualifiers from P gives - // std::initializer_list<P0> or P0[N] for some P0 and N and the argument is a - // non-empty initializer list (8.5.4), then deduction is performed instead for - // each element of the initializer list, taking P0 as a function template - // parameter type and the initializer element as its argument, and in the - // P0[N] case, if N is a non-type template parameter, N is deduced from the - // length of the initializer list. Otherwise, an initializer list argument - // causes the parameter to be considered a non-deduced context - - const bool IsConstSizedArray = AdjustedParamType->isConstantArrayType(); - - const bool IsDependentSizedArray = - !IsConstSizedArray && AdjustedParamType->isDependentSizedArrayType(); - - QualType ElTy; // The element type of the std::initializer_list or the array. - - const bool IsSTDList = !IsConstSizedArray && !IsDependentSizedArray && - S.isStdInitializerList(AdjustedParamType, &ElTy); - - if (!IsConstSizedArray && !IsDependentSizedArray && !IsSTDList) - return false; - - Result = Sema::TDK_Success; - // If we are not deducing against the 'T' in a std::initializer_list<T> then - // deduce against the 'T' in T[N]. - if (ElTy.isNull()) { - assert(!IsSTDList); - ElTy = S.Context.getAsArrayType(AdjustedParamType)->getElementType(); + unsigned TDF) { + // C++ [temp.deduct.call]p1: (CWG 1591) + // If removing references and cv-qualifiers from P gives + // std::initializer_list<P0> or P0[N] for some P0 and N and the argument is + // a non-empty initializer list, then deduction is performed instead for + // each element of the initializer list, taking P0 as a function template + // parameter type and the initializer element as its argument + // + // FIXME: Remove references and cv-qualifiers here? Consider + // std::initializer_list<std::initializer_list<T>&&> + QualType ElTy; + auto *ArrTy = S.Context.getAsArrayType(AdjustedParamType); + if (ArrTy) + ElTy = ArrTy->getElementType(); + else if (!S.isStdInitializerList(AdjustedParamType, &ElTy)) { + // Otherwise, an initializer list argument causes the parameter to be + // considered a non-deduced context + return Sema::TDK_Success; } + // Deduction only needs to be done for dependent types. if (ElTy->isDependentType()) { for (Expr *E : ILE->inits()) { - if ((Result = DeduceTemplateArgumentByListElement(S, TemplateParams, ElTy, - E, Info, Deduced, TDF))) - return true; + if (auto Result = DeduceTemplateArgumentByListElement( + S, TemplateParams, ElTy, E, Info, Deduced, TDF)) + return Result; } } - if (IsDependentSizedArray) { - const DependentSizedArrayType *ArrTy = - S.Context.getAsDependentSizedArrayType(AdjustedParamType); + + // in the P0[N] case, if N is a non-type template parameter, N is deduced + // from the length of the initializer list. + // FIXME: We're not supposed to get here if N would be deduced as 0. + if (auto *DependentArrTy = dyn_cast_or_null<DependentSizedArrayType>(ArrTy)) { // Determine the array bound is something we can deduce. if (NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, ArrTy->getSizeExpr())) { + getDeducedParameterFromExpr(Info, DependentArrTy->getSizeExpr())) { // We can perform template argument deduction for the given non-type // template parameter. llvm::APInt Size(S.Context.getIntWidth(NTTP->getType()), ILE->getNumInits()); - Result = DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, llvm::APSInt(Size), NTTP->getType(), - /*ArrayBound=*/true, Info, Deduced); + if (auto Result = DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, llvm::APSInt(Size), NTTP->getType(), + /*ArrayBound=*/true, Info, Deduced)) + return Result; } } - return true; + + return Sema::TDK_Success; } /// \brief Perform template argument deduction by matching a parameter type @@ -3279,15 +3271,10 @@ DeduceTemplateArgumentByListElement(Sema unsigned TDF) { // Handle the case where an init list contains another init list as the // element. - if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg)) { - Sema::TemplateDeductionResult Result; - if (!DeduceFromInitializerList(S, TemplateParams, - ParamType.getNonReferenceType(), ILE, Info, - Deduced, TDF, Result)) - return Sema::TDK_Success; // Just ignore this expression. - - return Result; - } + if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg)) + return DeduceFromInitializerList(S, TemplateParams, + ParamType.getNonReferenceType(), ILE, Info, + Deduced, TDF); // For all other cases, just match by type. QualType ArgType = Arg->getType(); @@ -3374,58 +3361,51 @@ Sema::TemplateDeductionResult Sema::Dedu ParamTypes.push_back(Function->getParamDecl(I)->getType()); } + SmallVector<OriginalCallArg, 4> OriginalCallArgs; + + // Deduce an argument of type ParamType from an expression with index ArgIdx. + auto DeduceCallArgument = [&](QualType ParamType, unsigned ArgIdx) { + Expr *Arg = Args[ArgIdx]; + QualType ArgType = Arg->getType(); + QualType OrigParamType = ParamType; + + unsigned TDF = 0; + if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams, + ParamType, ArgType, Arg, + TDF)) + return Sema::TDK_Success; + + // If we have nothing to deduce, we're done. + if (!hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) + return Sema::TDK_Success; + + // If the argument is an initializer list ... + if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg)) + return DeduceFromInitializerList(*this, TemplateParams, ParamType, ILE, + Info, Deduced, TDF); + + // 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, ArgType)); + + return DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, ParamType, + ArgType, Info, Deduced, TDF); + }; + // Deduce template arguments from the function parameters. Deduced.resize(TemplateParams->size()); - unsigned ArgIdx = 0; - SmallVector<OriginalCallArg, 4> OriginalCallArgs; - for (unsigned ParamIdx = 0, NumParamTypes = ParamTypes.size(); + for (unsigned ParamIdx = 0, NumParamTypes = ParamTypes.size(), ArgIdx = 0; ParamIdx != NumParamTypes; ++ParamIdx) { - QualType OrigParamType = ParamTypes[ParamIdx]; - QualType ParamType = OrigParamType; + QualType ParamType = ParamTypes[ParamIdx]; - const PackExpansionType *ParamExpansion - = dyn_cast<PackExpansionType>(ParamType); + const PackExpansionType *ParamExpansion = + dyn_cast<PackExpansionType>(ParamType); if (!ParamExpansion) { // Simple case: matching a function parameter to a function argument. if (ArgIdx >= CheckArgs) break; - Expr *Arg = Args[ArgIdx++]; - QualType ArgType = Arg->getType(); - - unsigned TDF = 0; - if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams, - ParamType, ArgType, Arg, - TDF)) - continue; - - // If we have nothing to deduce, we're done. - if (!hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) - continue; - - // If the argument is an initializer list ... - if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg)) { - TemplateDeductionResult Result; - // Removing references was already done. - if (!DeduceFromInitializerList(*this, TemplateParams, ParamType, ILE, - Info, Deduced, TDF, Result)) - continue; - - if (Result) - 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, - ArgType)); - - if (TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, - ParamType, ArgType, - Info, Deduced, TDF)) + if (auto Result = DeduceCallArgument(ParamType, ArgIdx++)) return Result; continue; @@ -3440,6 +3420,9 @@ Sema::TemplateDeductionResult Sema::Dedu // the function parameter pack. For a function parameter pack that does // not occur at the end of the parameter-declaration-list, the type of // the parameter pack is a non-deduced context. + // FIXME: This does not say that subsequent parameters are also non-deduced. + // See also DR1388 / DR1399, which effectively says we should keep deducing + // after the pack. if (ParamIdx + 1 < NumParamTypes) break; @@ -3447,43 +3430,9 @@ Sema::TemplateDeductionResult Sema::Dedu PackDeductionScope PackScope(*this, TemplateParams, Deduced, Info, ParamPattern); - for (; ArgIdx < Args.size(); PackScope.nextPackElement(), ++ArgIdx) { - QualType OrigParamType = ParamPattern; - ParamType = OrigParamType; - Expr *Arg = Args[ArgIdx]; - QualType ArgType = Arg->getType(); - - unsigned TDF = 0; - if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams, - ParamType, ArgType, Arg, - TDF)) - continue; - - // 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)) - continue; - - // As above, initializer lists need special handling. - if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg)) { - TemplateDeductionResult Result; - if (!DeduceFromInitializerList(*this, TemplateParams, ParamType, ILE, - Info, Deduced, TDF, Result)) - continue; - - if (Result) - return Result; - } else { - OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx, - ArgType)); - - if (TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, - ParamType, ArgType, Info, - Deduced, TDF)) - return Result; - } - } + for (; ArgIdx < Args.size(); PackScope.nextPackElement(), ++ArgIdx) + if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx)) + return Result; // Build argument packs for each of the parameter packs expanded by this // pack expansion. Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=290996&r1=290995&r2=290996&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp (original) +++ cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp Wed Jan 4 13:47:19 2017 @@ -104,7 +104,7 @@ template <typename T> T deduce_ref(const std::initializer_list<T>&); // expected-note {{conflicting types for parameter 'T' ('int' vs. 'double')}} template<typename T, typename U> struct pair { pair(...); }; -template<typename T> void deduce_pairs(std::initializer_list<pair<T, typename T::type>>); +template<typename T> void deduce_pairs(std::initializer_list<pair<T, typename T::type>>); // expected-note {{something}} struct WithIntType { typedef int type; }; template<typename ...T> void deduce_after_init_list_in_pack(void (*)(T...), T...); // expected-note {{<int, int> vs. <(no value), double>}} @@ -123,7 +123,7 @@ void argument_deduction() { pair<WithIntType, int> pi; pair<WithIntType, float> pf; deduce_pairs({pi, pi, pi}); // ok - deduce_pairs({pi, pf, pi}); // FIXME: This should be rejected, as we fail to produce a type that exactly matches the argument type. + deduce_pairs({pi, pf, pi}); // expected-error {{no matching function}} deduce_after_init_list_in_pack((void(*)(int,int))0, {}, 0); deduce_after_init_list_in_pack((void(*)(int,int))0, {}, 0.0); // expected-error {{no matching function}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits