Factor out more common logic in template argument deduction from function call arguments.

No functionality change intended.

llvm-svn: 291074
This commit is contained in:
Richard Smith 2017-01-05 04:08:31 +00:00
parent bbd3490bcc
commit 707eab6655
1 changed files with 62 additions and 71 deletions

View File

@ -3197,19 +3197,20 @@ 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,
Optional<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 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
@ -3217,8 +3218,7 @@ 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.
QualType ElTy;
auto *ArrTy = S.Context.getAsArrayType(AdjustedParamType);
if (ArrTy)
@ -3232,8 +3232,9 @@ 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, None,
TDF))
return Result;
}
}
@ -3259,30 +3260,39 @@ 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,
Optional<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, 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.
//
// FIXME: We are supposed to perform this check for the P/A pairs we extract
// from the initializer list case too.
if (ArgIdx)
OriginalCallArgs.push_back(
Sema::OriginalCallArg(OrigParamType, *ArgIdx, ArgType));
return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
ArgType, Info, Deduced, TDF);
}
@ -3365,31 +3375,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, ArgIdx, /*TDF*/ 0);
};
// Deduce template arguments from the function parameters.
@ -4055,8 +4051,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);
@ -4071,12 +4065,14 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_Failed;
};
SmallVector<OriginalCallArg, 4> OriginalCallArgs;
InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
if (InitList) {
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, None, /*TDF*/0))
return DeductionFailed();
}
} else {
@ -4085,13 +4081,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, /*ArgIdx*/0, /*TDF*/0))
return DeductionFailed();
}
@ -4113,12 +4105,11 @@ 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();
for (const OriginalCallArg &OriginalArg : OriginalCallArgs) {
if (CheckOriginalCallArgDeduction(*this, OriginalArg, Result)) {
Result = QualType();
return DeductionFailed();
}
}
return DAR_Succeeded;