summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaTemplateDeduction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaTemplateDeduction.cpp')
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp244
1 files changed, 152 insertions, 92 deletions
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index c16b28bcf139..b79904c0a703 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeOrdering.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/Template.h"
@@ -1899,8 +1900,9 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
// Check whether we have enough arguments.
if (!hasTemplateArgumentForDeduction(Args, ArgIdx))
- return NumberOfArgumentsMustMatch ? Sema::TDK_TooFewArguments
- : Sema::TDK_Success;
+ return NumberOfArgumentsMustMatch
+ ? Sema::TDK_MiscellaneousDeductionFailure
+ : Sema::TDK_Success;
// C++1z [temp.deduct.type]p9:
// During partial ordering, if Ai was originally a pack expansion [and]
@@ -2214,25 +2216,26 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
if (!Deduced[I].isNull()) {
if (I < NumAlreadyConverted) {
- // We have already fully type-checked and converted this
- // argument, because it was explicitly-specified. Just record the
- // presence of this argument.
- Builder.push_back(Deduced[I]);
// We may have had explicitly-specified template arguments for a
// template parameter pack (that may or may not have been extended
// via additional deduced arguments).
- if (Param->isParameterPack() && CurrentInstantiationScope) {
- if (CurrentInstantiationScope->getPartiallySubstitutedPack() ==
- Param) {
- // Forget the partially-substituted pack; its substitution is now
- // complete.
- CurrentInstantiationScope->ResetPartiallySubstitutedPack();
- }
+ if (Param->isParameterPack() && CurrentInstantiationScope &&
+ CurrentInstantiationScope->getPartiallySubstitutedPack() == Param) {
+ // Forget the partially-substituted pack; its substitution is now
+ // complete.
+ CurrentInstantiationScope->ResetPartiallySubstitutedPack();
+ // We still need to check the argument in case it was extended by
+ // deduction.
+ } else {
+ // We have already fully type-checked and converted this
+ // argument, because it was explicitly-specified. Just record the
+ // presence of this argument.
+ Builder.push_back(Deduced[I]);
+ continue;
}
- continue;
}
- // We have deduced this argument, so it still needs to be
+ // We may have deduced this argument, so it still needs to be
// checked and converted.
if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info,
IsDeduced, Builder)) {
@@ -2854,6 +2857,36 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
return true;
}
+/// Find the pack index for a particular parameter index in an instantiation of
+/// a function template with specific arguments.
+///
+/// \return The pack index for whichever pack produced this parameter, or -1
+/// if this was not produced by a parameter. Intended to be used as the
+/// ArgumentPackSubstitutionIndex for further substitutions.
+// FIXME: We should track this in OriginalCallArgs so we don't need to
+// reconstruct it here.
+static unsigned getPackIndexForParam(Sema &S,
+ FunctionTemplateDecl *FunctionTemplate,
+ const MultiLevelTemplateArgumentList &Args,
+ unsigned ParamIdx) {
+ unsigned Idx = 0;
+ for (auto *PD : FunctionTemplate->getTemplatedDecl()->parameters()) {
+ if (PD->isParameterPack()) {
+ unsigned NumExpansions =
+ S.getNumArgumentsInExpansion(PD->getType(), Args).getValueOr(1);
+ if (Idx + NumExpansions > ParamIdx)
+ return ParamIdx - Idx;
+ Idx += NumExpansions;
+ } else {
+ if (Idx == ParamIdx)
+ return -1; // Not a pack expansion
+ ++Idx;
+ }
+ }
+
+ llvm_unreachable("parameter index would not be produced from template");
+}
+
/// \brief Finish template argument deduction for a function template,
/// checking the deduced template arguments for completeness and forming
/// the function template specialization.
@@ -2904,9 +2937,9 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
DeclContext *Owner = FunctionTemplate->getDeclContext();
if (FunctionTemplate->getFriendObjectKind())
Owner = FunctionTemplate->getLexicalDeclContext();
+ MultiLevelTemplateArgumentList SubstArgs(*DeducedArgumentList);
Specialization = cast_or_null<FunctionDecl>(
- SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner,
- MultiLevelTemplateArgumentList(*DeducedArgumentList)));
+ SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs));
if (!Specialization || Specialization->isInvalidDecl())
return TDK_SubstitutionFailure;
@@ -2932,19 +2965,46 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// In general, the deduction process attempts to find template argument
// values that will make the deduced A identical to A (after the type A
// is transformed as described above). [...]
+ llvm::SmallDenseMap<std::pair<unsigned, QualType>, QualType> DeducedATypes;
for (unsigned I = 0, N = OriginalCallArgs->size(); I != N; ++I) {
OriginalCallArg OriginalArg = (*OriginalCallArgs)[I];
- unsigned ParamIdx = OriginalArg.ArgIdx;
+ auto ParamIdx = OriginalArg.ArgIdx;
if (ParamIdx >= Specialization->getNumParams())
+ // FIXME: This presumably means a pack ended up smaller than we
+ // expected while deducing. Should this not result in deduction
+ // failure? Can it even happen?
continue;
- QualType DeducedA = Specialization->getParamDecl(ParamIdx)->getType();
+ QualType DeducedA;
+ if (!OriginalArg.DecomposedParam) {
+ // P is one of the function parameters, just look up its substituted
+ // type.
+ DeducedA = Specialization->getParamDecl(ParamIdx)->getType();
+ } else {
+ // P is a decomposed element of a parameter corresponding to a
+ // braced-init-list argument. Substitute back into P to find the
+ // deduced A.
+ QualType &CacheEntry =
+ DeducedATypes[{ParamIdx, OriginalArg.OriginalParamType}];
+ if (CacheEntry.isNull()) {
+ ArgumentPackSubstitutionIndexRAII PackIndex(
+ *this, getPackIndexForParam(*this, FunctionTemplate, SubstArgs,
+ ParamIdx));
+ CacheEntry =
+ SubstType(OriginalArg.OriginalParamType, SubstArgs,
+ Specialization->getTypeSpecStartLoc(),
+ Specialization->getDeclName());
+ }
+ DeducedA = CacheEntry;
+ }
+
if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
Info.FirstArg = TemplateArgument(DeducedA);
Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType);
Info.CallArgIndex = OriginalArg.ArgIdx;
- return TDK_DeducedMismatch;
+ return OriginalArg.DecomposedParam ? TDK_DeducedMismatchNested
+ : TDK_DeducedMismatch;
}
}
}
@@ -3196,19 +3256,21 @@ static bool
hasDeducibleTemplateParameters(Sema &S, FunctionTemplateDecl *FunctionTemplate,
QualType T);
-static Sema::TemplateDeductionResult DeduceTemplateArgumentByListElement(
+static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
Sema &S, TemplateParameterList *TemplateParams, QualType ParamType,
Expr *Arg, TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF);
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs,
+ bool DecomposedParam, unsigned ArgIdx, unsigned TDF);
/// \brief Attempt template argument deduction from an initializer list
/// deemed to be an argument in a function call.
-static Sema::TemplateDeductionResult
-DeduceFromInitializerList(Sema &S, TemplateParameterList *TemplateParams,
- QualType AdjustedParamType, InitListExpr *ILE,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- unsigned TDF) {
+static Sema::TemplateDeductionResult DeduceFromInitializerList(
+ Sema &S, TemplateParameterList *TemplateParams, QualType AdjustedParamType,
+ InitListExpr *ILE, TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs, unsigned ArgIdx,
+ 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
@@ -3216,8 +3278,10 @@ DeduceFromInitializerList(Sema &S, TemplateParameterList *TemplateParams,
// 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>&&>
+ // We've already removed references and cv-qualifiers here.
+ if (!ILE->getNumInits())
+ return Sema::TDK_Success;
+
QualType ElTy;
auto *ArrTy = S.Context.getAsArrayType(AdjustedParamType);
if (ArrTy)
@@ -3231,15 +3295,15 @@ DeduceFromInitializerList(Sema &S, TemplateParameterList *TemplateParams,
// Deduction only needs to be done for dependent types.
if (ElTy->isDependentType()) {
for (Expr *E : ILE->inits()) {
- if (auto Result = DeduceTemplateArgumentByListElement(
- S, TemplateParams, ElTy, E, Info, Deduced, TDF))
+ if (auto Result = DeduceTemplateArgumentsFromCallArgument(
+ S, TemplateParams, ElTy, E, Info, Deduced, OriginalCallArgs, true,
+ ArgIdx, TDF))
return Result;
}
}
// 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 =
@@ -3258,30 +3322,35 @@ DeduceFromInitializerList(Sema &S, TemplateParameterList *TemplateParams,
return Sema::TDK_Success;
}
-/// \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
-/// of type \c initializer_list\<ParamType\>.
-static Sema::TemplateDeductionResult
-DeduceTemplateArgumentByListElement(Sema &S,
- TemplateParameterList *TemplateParams,
- QualType ParamType, Expr *Arg,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- unsigned TDF) {
- // Handle the case where an init list contains another init list as the
- // element.
- 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.
+/// \brief Perform template argument deduction per [temp.deduct.call] for a
+/// single parameter / argument pair.
+static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
+ Sema &S, TemplateParameterList *TemplateParams, QualType ParamType,
+ Expr *Arg, TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs,
+ bool DecomposedParam, unsigned ArgIdx, unsigned TDF) {
QualType ArgType = Arg->getType();
+ QualType OrigParamType = ParamType;
+
+ // If P is a reference type [...]
+ // If P is a cv-qualified type [...]
if (AdjustFunctionParmAndArgTypesForDeduction(S, TemplateParams, ParamType,
ArgType, Arg, TDF))
return Sema::TDK_Success;
+ // If [...] the argument is a non-empty initializer list [...]
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg))
+ return DeduceFromInitializerList(S, TemplateParams, ParamType, ILE, Info,
+ Deduced, OriginalCallArgs, ArgIdx, TDF);
+
+ // [...] the deduction process attempts to find template argument values
+ // that will make the deduced A identical to A
+ //
+ // 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(
+ Sema::OriginalCallArg(OrigParamType, DecomposedParam, ArgIdx, ArgType));
return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
ArgType, Info, Deduced, TDF);
}
@@ -3364,31 +3433,17 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
// 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.
+ // C++ [demp.deduct.call]p1: (DR1391)
+ // Template argument deduction is done by comparing each function template
+ // parameter that contains template-parameters that participate in
+ // template argument deduction ...
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);
+ // ... with the type of the corresponding argument
+ return DeduceTemplateArgumentsFromCallArgument(
+ *this, TemplateParams, ParamType, Args[ArgIdx], Info, Deduced,
+ OriginalCallArgs, /*Decomposed*/false, ArgIdx, /*TDF*/ 0);
};
// Deduce template arguments from the function parameters.
@@ -4054,8 +4109,6 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
// Deduce type of TemplParam in Func(Init)
SmallVector<DeducedTemplateArgument, 1> Deduced;
Deduced.resize(1);
- QualType InitType = Init->getType();
- unsigned TDF = 0;
TemplateDeductionInfo Info(Loc, Depth);
@@ -4070,12 +4123,21 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_Failed;
};
+ SmallVector<OriginalCallArg, 4> OriginalCallArgs;
+
InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
if (InitList) {
+ // Notionally, we substitute std::initializer_list<T> for 'auto' and deduce
+ // against that. Such deduction only succeeds if removing cv-qualifiers and
+ // references results in std::initializer_list<T>.
+ if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
+ return DAR_Failed;
+
for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
- if (DeduceTemplateArgumentByListElement(*this, TemplateParamsSt.get(),
- TemplArg, InitList->getInit(i),
- Info, Deduced, TDF))
+ if (DeduceTemplateArgumentsFromCallArgument(
+ *this, TemplateParamsSt.get(), TemplArg, InitList->getInit(i),
+ Info, Deduced, OriginalCallArgs, /*Decomposed*/ true,
+ /*ArgIdx*/ 0, /*TDF*/ 0))
return DeductionFailed();
}
} else {
@@ -4084,13 +4146,9 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
}
- if (AdjustFunctionParmAndArgTypesForDeduction(
- *this, TemplateParamsSt.get(), FuncParam, InitType, Init, TDF))
- return DAR_Failed;
-
- if (DeduceTemplateArgumentsByTypeMatch(*this, TemplateParamsSt.get(),
- FuncParam, InitType, Info, Deduced,
- TDF))
+ if (DeduceTemplateArgumentsFromCallArgument(
+ *this, TemplateParamsSt.get(), FuncParam, Init, Info, Deduced,
+ OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0))
return DeductionFailed();
}
@@ -4112,12 +4170,14 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
// Check that the deduced argument type is compatible with the original
// argument type per C++ [temp.deduct.call]p4.
- if (!InitList && !Result.isNull() &&
- CheckOriginalCallArgDeduction(*this,
- Sema::OriginalCallArg(FuncParam,0,InitType),
- Result)) {
- Result = QualType();
- return DeductionFailed();
+ QualType DeducedA = InitList ? Deduced[0].getAsType() : Result;
+ for (const OriginalCallArg &OriginalArg : OriginalCallArgs) {
+ assert((bool)InitList == OriginalArg.DecomposedParam &&
+ "decomposed non-init-list in auto deduction?");
+ if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
+ Result = QualType();
+ return DeductionFailed();
+ }
}
return DAR_Succeeded;