When explicit template arguments are provided for a function call,

substitute those template arguments into the function parameter types
prior to template argument deduction. There's still a bit of work to
do to make this work properly when only some of the template arguments
are specified.

llvm-svn: 74576
This commit is contained in:
Douglas Gregor 2009-06-30 23:57:56 +00:00
parent 1938fb1954
commit 89026b5018
5 changed files with 172 additions and 31 deletions

View File

@ -701,6 +701,9 @@ public:
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
bool HasExplicitTemplateArgs,
const TemplateArgument *ExplicitTemplateArgs,
unsigned NumExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
@ -747,6 +750,9 @@ public:
FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
DeclarationName UnqualifiedName,
bool HasExplicitTemplateArgs,
const TemplateArgument *ExplicitTemplateArgs,
unsigned NumExplicitTemplateArgs,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
@ -2247,7 +2253,10 @@ public:
TDK_TooManyArguments,
/// \brief When performing template argument deduction for a class
/// template, there were too few call arguments.
TDK_TooFewArguments
TDK_TooFewArguments,
/// \brief The explicitly-specified template arguments were not valid
/// template arguments for the given template.
TDK_InvalidExplicitArguments
};
/// \brief Provides information about an attempted template argument
@ -2329,6 +2338,9 @@ public:
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
bool HasExplicitTemplateArgs,
const TemplateArgument *ExplicitTemplateArgs,
unsigned NumExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info);

View File

@ -2635,8 +2635,13 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
}
// If we're directly calling a function, get the appropriate declaration.
// Also, in C++, keep track of whether we should perform argument-dependent
// lookup and whether there were any explicitly-specified template arguments.
Expr *FnExpr = Fn;
bool ADL = true;
bool HasExplicitTemplateArgs = 0;
const TemplateArgument *ExplicitTemplateArgs = 0;
unsigned NumExplicitTemplateArgs = 0;
while (true) {
if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr))
FnExpr = IcExpr->getSubExpr();
@ -2661,6 +2666,28 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
} else if (TemplateIdRefExpr *TemplateIdRef
= dyn_cast<TemplateIdRefExpr>(FnExpr)) {
NDecl = TemplateIdRef->getTemplateName().getAsTemplateDecl();
HasExplicitTemplateArgs = true;
ExplicitTemplateArgs = TemplateIdRef->getTemplateArgs();
NumExplicitTemplateArgs = TemplateIdRef->getNumTemplateArgs();
// C++ [temp.arg.explicit]p6:
// [Note: For simple function names, argument dependent lookup (3.4.2)
// applies even when the function name is not visible within the
// scope of the call. This is because the call still has the syntactic
// form of a function call (3.4.1). But when a function template with
// explicit template arguments is used, the call does not have the
// correct syntactic form unless there is a function template with
// that name visible at the point of the call. If no such name is
// visible, the call is not syntactically well-formed and
// argument-dependent lookup does not apply. If some such name is
// visible, argument dependent lookup applies and additional function
// templates may be found in other namespaces.
//
// The summary of this paragraph is that, if we get to this point and the
// template-id was not a qualified name, then argument-dependent lookup
// is still possible.
if (TemplateIdRef->getQualifier())
ADL = false;
break;
} else {
// Any kind of name that does not refer to a declaration (or
@ -2692,8 +2719,12 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
ADL = false;
if (Ovl || FunctionTemplate || ADL) {
FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName, LParenLoc,
Args, NumArgs, CommaLocs, RParenLoc, ADL);
FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName,
HasExplicitTemplateArgs,
ExplicitTemplateArgs,
NumExplicitTemplateArgs,
LParenLoc, Args, NumArgs, CommaLocs,
RParenLoc, ADL);
if (!FDecl)
return ExprError();

View File

@ -2166,8 +2166,9 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions,
AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
SuppressUserConversions);
else
AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*F), Args,
NumArgs, CandidateSet,
AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*F),
/*FIXME: explicit args */false, 0, 0,
Args, NumArgs, CandidateSet,
SuppressUserConversions);
}
}
@ -2273,6 +2274,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
/// template specialization.
void
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
bool HasExplicitTemplateArgs,
const TemplateArgument *ExplicitTemplateArgs,
unsigned NumExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
@ -2289,8 +2293,9 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
TemplateDeductionInfo Info(Context);
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, Args, NumArgs,
Specialization, Info)) {
= DeduceTemplateArguments(FunctionTemplate, HasExplicitTemplateArgs,
ExplicitTemplateArgs, NumExplicitTemplateArgs,
Args, NumArgs, Specialization, Info)) {
// FIXME: Record what happened with template argument deduction, so
// that we can give the user a beautiful diagnostic.
(void)Result;
@ -3438,8 +3443,9 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func))
AddOverloadCandidate(FD, Args, NumArgs, CandidateSet);
else
AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func), Args,
NumArgs, CandidateSet);
AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func),
/*FIXME: explicit args */false, 0, 0,
Args, NumArgs, CandidateSet);
}
}
@ -3758,6 +3764,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
/// arguments and Fn, and returns NULL.
FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
DeclarationName UnqualifiedName,
bool HasExplicitTemplateArgs,
const TemplateArgument *ExplicitTemplateArgs,
unsigned NumExplicitTemplateArgs,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
@ -3790,11 +3799,17 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
Func != FuncEnd; ++Func) {
DeclContext *Ctx = 0;
if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Func)) {
if (HasExplicitTemplateArgs)
continue;
AddOverloadCandidate(FunDecl, Args, NumArgs, CandidateSet);
Ctx = FunDecl->getDeclContext();
} else {
FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*Func);
AddTemplateOverloadCandidate(FunTmpl, Args, NumArgs, CandidateSet);
AddTemplateOverloadCandidate(FunTmpl, HasExplicitTemplateArgs,
ExplicitTemplateArgs,
NumExplicitTemplateArgs,
Args, NumArgs, CandidateSet);
Ctx = FunTmpl->getDeclContext();
}
@ -3803,6 +3818,7 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
ArgumentDependentLookup = false;
}
} else if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Callee)) {
assert(!HasExplicitTemplateArgs && "Explicit template arguments?");
AddOverloadCandidate(Func, Args, NumArgs, CandidateSet);
if (Func->getDeclContext()->isRecord() ||
@ -3810,7 +3826,10 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
ArgumentDependentLookup = false;
} else if (FunctionTemplateDecl *FuncTemplate
= dyn_cast_or_null<FunctionTemplateDecl>(Callee)) {
AddTemplateOverloadCandidate(FuncTemplate, Args, NumArgs, CandidateSet);
AddTemplateOverloadCandidate(FuncTemplate, HasExplicitTemplateArgs,
ExplicitTemplateArgs,
NumExplicitTemplateArgs,
Args, NumArgs, CandidateSet);
if (FuncTemplate->getDeclContext()->isRecord())
ArgumentDependentLookup = false;
@ -3819,6 +3838,7 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
if (Callee)
UnqualifiedName = Callee->getDeclName();
// FIXME: Pass explicit template arguments through for ADL
if (ArgumentDependentLookup)
AddArgumentDependentLookupCandidates(UnqualifiedName, Args, NumArgs,
CandidateSet);

View File

@ -868,6 +868,16 @@ static bool isSimpleTemplateIdType(QualType T) {
/// \param FunctionTemplate the function template for which we are performing
/// template argument deduction.
///
/// \param HasExplicitTemplateArgs whether any template arguments were
/// explicitly specified.
///
/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
/// the explicitly-specified template arguments.
///
/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
/// the number of explicitly-specified template arguments in
/// @p ExplicitTemplateArguments. This value may be zero.
///
/// \param Args the function call arguments
///
/// \param NumArgs the number of arguments in Args
@ -880,22 +890,22 @@ static bool isSimpleTemplateIdType(QualType T) {
/// about template argument deduction.
///
/// \returns the result of template argument deduction.
///
/// FIXME: We will also need to pass in any explicitly-specified template
/// arguments.
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
bool HasExplicitTemplateArgs,
const TemplateArgument *ExplicitTemplateArgs,
unsigned NumExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
// C++ [temp.deduct.call]p1:
// Template argument deduction is done by comparing each function template
// parameter type (call it P) with the type of the corresponding argument
// of the call (call it A) as described below.
unsigned CheckArgs = NumArgs;
if (NumArgs < Function->getNumParams())
if (NumArgs < Function->getMinRequiredArguments())
return TDK_TooFewArguments;
else if (NumArgs > Function->getNumParams()) {
const FunctionProtoType *Proto
@ -905,18 +915,83 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
CheckArgs = Function->getNumParams();
}
// Template argument deduction for function templates in a SFINAE context.
// Trap any errors that might occur.
SFINAETrap Trap(*this);
// Deduce template arguments from the function parameters.
llvm::SmallVector<TemplateArgument, 4> Deduced;
Deduced.resize(FunctionTemplate->getTemplateParameters()->size());
// The types of the parameters from which we will perform template argument
// deduction.
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
llvm::SmallVector<TemplateArgument, 4> Deduced;
llvm::SmallVector<QualType, 4> ParamTypes;
if (NumExplicitTemplateArgs) {
// C++ [temp.arg.explicit]p3:
// Template arguments that are present shall be specified in the
// declaration order of their corresponding template-parameters. The
// template argument list shall not specify more template-arguments than
// there are corresponding template-parameters.
TemplateArgumentListBuilder Builder(TemplateParams,
NumExplicitTemplateArgs);
if (CheckTemplateArgumentList(FunctionTemplate,
SourceLocation(), SourceLocation(),
ExplicitTemplateArgs,
NumExplicitTemplateArgs,
SourceLocation(),
Builder) || Trap.hasErrorOccurred())
return TDK_InvalidExplicitArguments;
// Enter a new template instantiation context for the substitution of the
// explicitly-specified template arguments into the
InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
FunctionTemplate, Deduced.data(), Deduced.size());
if (Inst)
return TDK_InstantiationDepth;
// Form the template argument list from the explicitly-specified
// template arguments.
TemplateArgumentList *ExplicitArgumentList
= new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
Info.reset(ExplicitArgumentList);
// Instantiate the types of each of the function parameters given the
// explicitly-specified template arguments.
for (FunctionDecl::param_iterator P = Function->param_begin(),
PEnd = Function->param_end();
P != PEnd;
++P) {
QualType ParamType = InstantiateType((*P)->getType(),
*ExplicitArgumentList,
(*P)->getLocation(),
(*P)->getDeclName());
if (ParamType.isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
ParamTypes.push_back(ParamType);
}
// C++ [temp.arg.explicit]p2:
// Trailing template arguments that can be deduced (14.8.2) may be
// omitted from the list of explicit template- arguments. If all of the
// template arguments can be deduced, they may all be omitted; in this
// case, the empty template argument list <> itself may also be omitted.
//
// Take all of the explicitly-specified arguments and put them into the
// set of deduced template arguments.
Deduced.reserve(TemplateParams->size());
for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I)
Deduced.push_back(ExplicitArgumentList->get(I));
} else {
// Just fill in the parameter types from the function declaration.
for (unsigned I = 0; I != CheckArgs; ++I)
ParamTypes.push_back(Function->getParamDecl(I)->getType());
}
// Deduce template arguments from the function parameters.
Deduced.resize(TemplateParams->size());
for (unsigned I = 0; I != CheckArgs; ++I) {
QualType ParamType = Function->getParamDecl(I)->getType();
QualType ParamType = ParamTypes[I];
QualType ArgType = Args[I]->getType();
// C++ [temp.deduct.call]p2:
@ -998,11 +1073,6 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// FIXME: C++ [temp.deduct.call] paragraphs 6-9 deal with function
// pointer parameters.
}
InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
FunctionTemplate, Deduced.data(), Deduced.size());
if (Inst)
return TDK_InstantiationDepth;
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
@ -1030,6 +1100,13 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
= new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
Info.reset(DeducedArgumentList);
// Enter a new template instantiation context while we instantiate the
// actual function declaration.
InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
FunctionTemplate, Deduced.data(), Deduced.size());
if (Inst)
return TDK_InstantiationDepth;
// Substitute the deduced template arguments into the function template
// declaration to produce the function template specialization.
Specialization = cast_or_null<FunctionDecl>(

View File

@ -2,10 +2,11 @@
template<typename T> struct A { };
template<typename T> T make(A<T>);
template<typename T> T make();
template<typename T> T make2(const T&);
void test_make() {
int& ir0 = make<int&>(A<int&>());
A<int> a0 = make< A<int> >(A<A<int> >());
int& ir0 = make<int&>();
A<int> a0 = make< A<int> >();
A<int> a1 = make2< A<int> >(A<int>());
}