When a template-id refers to a single function template, and the

explicitly-specified template arguments are enough to determine the
instantiation, and either template argument deduction fails or is not
performed in that context, we can resolve the template-id down to a
function template specialization (so sayeth C++0x
[temp.arg.explicit]p3). Fixes PR5811.

llvm-svn: 91852
This commit is contained in:
Douglas Gregor 2009-12-21 23:17:24 +00:00
parent bf20018423
commit 8364e6b568
8 changed files with 249 additions and 30 deletions

View File

@ -589,7 +589,8 @@ def err_temp_copy_deleted : Error<
// C++0x decltype
def err_cannot_determine_declared_type_of_overloaded_function : Error<
"can't determine the declared type of an overloaded function">;
"cannot determine the %select{type|declared type}0 of an overloaded "
"function">;
// C++0x auto
def err_auto_variable_cannot_appear_in_own_initializer : Error<
@ -1007,6 +1008,8 @@ def err_template_arg_unnamed_type : Error<
"template argument uses unnamed type">;
def note_template_unnamed_type_here : Note<
"unnamed type used in template argument was declared here">;
def err_template_arg_overload_type : Error<
"template argument is the type of an unresolved overloaded function">;
def err_template_arg_not_class_template : Error<
"template argument does not refer to a class template or template "
"template parameter">;

View File

@ -1036,6 +1036,8 @@ public:
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
bool Complain);
FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From);
Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
OwningExprResult FixOverloadedFunctionReference(OwningExprResult,
FunctionDecl *Fn);
@ -2664,7 +2666,10 @@ public:
TDK_TooFewArguments,
/// \brief The explicitly-specified template arguments were not valid
/// template arguments for the given template.
TDK_InvalidExplicitArguments
TDK_InvalidExplicitArguments,
/// \brief The arguments included an overloaded function name that could
/// not be resolved to a suitable function.
TDK_FailedOverloadResolution
};
/// \brief Provides information about an attempted template argument
@ -2778,6 +2783,12 @@ public:
CXXConversionDecl *&Specialization,
TemplateDeductionInfo &Info);
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info);
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC);

View File

@ -4591,6 +4591,93 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
return 0;
}
/// \brief Given an expression that refers to an overloaded function, try to
/// resolve that overloaded function expression down to a single function.
///
/// This routine can only resolve template-ids that refer to a single function
/// template, where that template-id refers to a single template whose template
/// arguments are either provided by the template-id or have defaults,
/// as described in C++0x [temp.arg.explicit]p3.
FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
// C++ [over.over]p1:
// [...] [Note: any redundant set of parentheses surrounding the
// overloaded function name is ignored (5.1). ]
Expr *OvlExpr = From->IgnoreParens();
// C++ [over.over]p1:
// [...] The overloaded function name can be preceded by the &
// operator.
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(OvlExpr)) {
if (UnOp->getOpcode() == UnaryOperator::AddrOf)
OvlExpr = UnOp->getSubExpr()->IgnoreParens();
}
bool HasExplicitTemplateArgs = false;
TemplateArgumentListInfo ExplicitTemplateArgs;
llvm::SmallVector<NamedDecl*,8> Fns;
// Look into the overloaded expression.
if (UnresolvedLookupExpr *UL
= dyn_cast<UnresolvedLookupExpr>(OvlExpr)) {
Fns.append(UL->decls_begin(), UL->decls_end());
if (UL->hasExplicitTemplateArgs()) {
HasExplicitTemplateArgs = true;
UL->copyTemplateArgumentsInto(ExplicitTemplateArgs);
}
} else if (UnresolvedMemberExpr *ME
= dyn_cast<UnresolvedMemberExpr>(OvlExpr)) {
Fns.append(ME->decls_begin(), ME->decls_end());
if (ME->hasExplicitTemplateArgs()) {
HasExplicitTemplateArgs = true;
ME->copyTemplateArgumentsInto(ExplicitTemplateArgs);
}
}
// If we didn't actually find any template-ids, we're done.
if (Fns.empty() || !HasExplicitTemplateArgs)
return 0;
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
FunctionDecl *Matched = 0;
for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(),
E = Fns.end(); I != E; ++I) {
// C++0x [temp.arg.explicit]p3:
// [...] In contexts where deduction is done and fails, or in contexts
// where deduction is not done, if a template argument list is
// specified and it, along with any default template arguments,
// identifies a single function template specialization, then the
// template-id is an lvalue for the function template specialization.
FunctionTemplateDecl *FunctionTemplate = cast<FunctionTemplateDecl>(*I);
// C++ [over.over]p2:
// If the name is a function template, template argument deduction is
// done (14.8.2.2), and if the argument deduction succeeds, the
// resulting template argument list is used to generate a single
// function template specialization, which is added to the set of
// overloaded functions considered.
// FIXME: We don't really want to build the specialization here, do we?
FunctionDecl *Specialization = 0;
TemplateDeductionInfo Info(Context);
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
Specialization, Info)) {
// FIXME: make a note of the failed deduction for diagnostics.
(void)Result;
continue;
}
// Multiple matches; we can't resolve to a single declaration.
if (Matched)
return 0;
Matched = Specialization;
}
return Matched;
}
/// \brief Add a single candidate to the overload set.
static void AddOverloadedCallCandidate(Sema &S,
NamedDecl *Callee,

View File

@ -2189,6 +2189,9 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR;
Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here);
return true;
} else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) {
SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange();
return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR;
}
return false;

View File

@ -1506,15 +1506,39 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
ParamType->getAs<PointerType>()->getPointeeType())))
TDF |= TDF_DerivedClass;
// FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
// pointer parameters.
if (Context.hasSameUnqualifiedType(ArgType, Context.OverloadTy)) {
// We know that template argument deduction will fail if the argument is
// still an overloaded function. Check whether we can resolve this
// argument as a single function template specialization per
// C++ [temp.arg.explicit]p3.
FunctionDecl *ExplicitSpec
= ResolveSingleFunctionTemplateSpecialization(Args[I]);
Expr *ResolvedArg = 0;
if (ExplicitSpec)
ResolvedArg = FixOverloadedFunctionReference(Args[I], ExplicitSpec);
if (!ExplicitSpec || !ResolvedArg) {
// Template argument deduction fails if we can't resolve the overloaded
// function.
return TDK_FailedOverloadResolution;
}
// Get the type of the resolved argument.
ArgType = ResolvedArg->getType();
if (ArgType->isPointerType() || ArgType->isMemberPointerType())
TDF |= TDF_IgnoreQualifiers;
ResolvedArg->Destroy(Context);
}
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(Context, TemplateParams,
ParamType, ArgType, Info, Deduced,
TDF))
return Result;
// FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
// pointer parameters.
// FIXME: we need to check that the deduced A is the same as A,
// modulo the various allowed differences.
}
@ -1524,24 +1548,19 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
}
/// \brief Deduce template arguments when taking the address of a function
/// template (C++ [temp.deduct.funcaddr]) or matching a
/// template (C++ [temp.deduct.funcaddr]) or matching a specialization to
/// a template.
///
/// \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 ExplicitTemplateArguments the explicitly-specified template
/// arguments.
///
/// \param ArgFunctionType the function type that will be used as the
/// "argument" type (A) when performing template argument deduction from the
/// function template's function type.
/// function template's function type. This type may be NULL, if there is no
/// argument type to compare against, in C++0x [temp.arg.explicit]p3.
///
/// \param Specialization if template argument deduction was successful,
/// this will be set to the function template specialization produced by
@ -1578,6 +1597,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// Trap any errors that might occur.
SFINAETrap Trap(*this);
if (!ArgFunctionType.isNull()) {
// Deduce template arguments from the function type.
Deduced.resize(TemplateParams->size());
if (TemplateDeductionResult Result
@ -1585,6 +1605,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
FunctionType, ArgFunctionType, Info,
Deduced, 0))
return Result;
}
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
Specialization, Info);
@ -1694,6 +1715,32 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
return Result;
}
/// \brief Deduce template arguments for a function template when there is
/// nothing to deduce against (C++0x [temp.arg.explicit]p3).
///
/// \param FunctionTemplate the function template for which we are performing
/// template argument deduction.
///
/// \param ExplicitTemplateArguments the explicitly-specified template
/// arguments.
///
/// \param Specialization if template argument deduction was successful,
/// this will be set to the function template specialization produced by
/// template argument deduction.
///
/// \param Info the argument will be updated to provide additional information
/// about template argument deduction.
///
/// \returns the result of template argument deduction.
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
QualType(), Specialization, Info);
}
/// \brief Stores the result of comparing the qualifiers of two types.
enum DeductionQualifierComparison {
NeitherMoreQualified = 0,

View File

@ -308,7 +308,11 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
Expr *E = static_cast<Expr *>(DS.getTypeRep());
assert(E && "Didn't get an expression for typeof?");
// TypeQuals handled by caller.
Result = Context.getTypeOfExprType(E);
Result = TheSema.BuildTypeofExprType(E);
if (Result.isNull()) {
Result = Context.IntTy;
TheDeclarator.setInvalidType(true);
}
break;
}
case DeclSpec::TST_decltype: {
@ -1826,14 +1830,41 @@ QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) {
}
QualType Sema::BuildTypeofExprType(Expr *E) {
if (E->getType() == Context.OverloadTy) {
// C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a
// function template specialization wherever deduction cannot occur.
if (FunctionDecl *Specialization
= ResolveSingleFunctionTemplateSpecialization(E)) {
E = FixOverloadedFunctionReference(E, Specialization);
if (!E)
return QualType();
} else {
Diag(E->getLocStart(),
diag::err_cannot_determine_declared_type_of_overloaded_function)
<< false << E->getSourceRange();
return QualType();
}
}
return Context.getTypeOfExprType(E);
}
QualType Sema::BuildDecltypeType(Expr *E) {
if (E->getType() == Context.OverloadTy) {
// C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a
// function template specialization wherever deduction cannot occur.
if (FunctionDecl *Specialization
= ResolveSingleFunctionTemplateSpecialization(E)) {
E = FixOverloadedFunctionReference(E, Specialization);
if (!E)
return QualType();
} else {
Diag(E->getLocStart(),
diag::err_cannot_determine_declared_type_of_overloaded_function);
diag::err_cannot_determine_declared_type_of_overloaded_function)
<< true << E->getSourceRange();
return QualType();
}
}
return Context.getDecltypeType(E);
}

View File

@ -0,0 +1,37 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// PR5811
template <class F> void Call(F f) { f(1); }
template <typename T> void f(T);
void a() { Call(f<int>); }
// Check the conversion of a template-id to a pointer
template<typename T, T* Address> struct Constant { };
Constant<void(int), &f<int> > constant0;
template<typename T, T* Address> void constant_func();
void test_constant_func() {
constant_func<void(int), &f<int> >();
}
// Check typeof() on a template-id referring to a single function
template<typename T, typename U>
struct is_same {
static const bool value = false;
};
template<typename T>
struct is_same<T, T> {
static const bool value = true;
};
int typeof0[is_same<__typeof__(f<int>), void (int)>::value? 1 : -1];
int typeof1[is_same<__typeof__(&f<int>), void (*)(int)>::value? 1 : -1];
template <typename T> void g(T);
template <typename T> void g(T, T);
int typeof2[is_same<__typeof__(g<float>), void (int)>::value? 1 : -1]; // \
// expected-error{{cannot determine the type of an overloaded function}} \
// FIXME: expected-error{{use of undeclared identifier}}

View File

@ -2,10 +2,10 @@
void f();
void f(int);
decltype(f) a; // expected-error{{can't determine the declared type of an overloaded function}}
decltype(f) a; // expected-error{{cannot determine the declared type of an overloaded function}}
template<typename T> struct S {
decltype(T::f) * f; // expected-error{{can't determine the declared type of an overloaded function}}
decltype(T::f) * f; // expected-error{{cannot determine the declared type of an overloaded function}}
};
struct K { void f(); void f(int); };