forked from OSchip/llvm-project
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:
parent
bf20018423
commit
8364e6b568
|
@ -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">;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,14 +1597,16 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
|
|||
// Trap any errors that might occur.
|
||||
SFINAETrap Trap(*this);
|
||||
|
||||
// Deduce template arguments from the function type.
|
||||
Deduced.resize(TemplateParams->size());
|
||||
if (TemplateDeductionResult Result
|
||||
= ::DeduceTemplateArguments(Context, TemplateParams,
|
||||
FunctionType, ArgFunctionType, Info,
|
||||
Deduced, 0))
|
||||
return Result;
|
||||
|
||||
if (!ArgFunctionType.isNull()) {
|
||||
// Deduce template arguments from the function type.
|
||||
Deduced.resize(TemplateParams->size());
|
||||
if (TemplateDeductionResult Result
|
||||
= ::DeduceTemplateArguments(Context, TemplateParams,
|
||||
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,
|
||||
|
|
|
@ -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) {
|
||||
Diag(E->getLocStart(),
|
||||
diag::err_cannot_determine_declared_type_of_overloaded_function);
|
||||
return QualType();
|
||||
// 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)
|
||||
<< true << E->getSourceRange();
|
||||
return QualType();
|
||||
}
|
||||
}
|
||||
|
||||
return Context.getDecltypeType(E);
|
||||
}
|
||||
|
|
|
@ -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}}
|
|
@ -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); };
|
||||
|
|
Loading…
Reference in New Issue