r290996 - Factor out duplicated code and simplify.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 4 11:47:19 PST 2017
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}}
More information about the cfe-commits
mailing list