Handle the resolution of a reference to a function template (which

includes explicitly-specified template arguments) to a function
template specialization in cases where no deduction is performed or
deduction fails. Patch by Faisal Vali, fixes PR7505!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126048 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2011-02-19 21:32:49 +00:00
Родитель 6c94837815
Коммит 1be8eec3dd
12 изменённых файлов: 597 добавлений и 265 удалений

Просмотреть файл

@ -2686,6 +2686,10 @@ def err_bad_reinterpret_cast_overload : Error<
def err_bad_static_cast_overload : Error<
"address of overloaded function %0 cannot be static_cast to type %1">;
def err_bad_cstyle_cast_overload : Error<
"address of overloaded function %0 cannot be cast to type %1">;
def err_bad_cxx_cast_generic : Error<
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
"functional-style cast}0 from %1 to %2 is not allowed">;

Просмотреть файл

@ -1247,12 +1247,28 @@ public:
OverloadCandidateSet& CandidateSet,
bool PartialOverloading = false);
// Emit as a 'note' the specific overload candidate
void NoteOverloadCandidate(FunctionDecl *Fn);
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// Emit as a series of 'note's all template and non-templates
// identified by the expression Expr
void NoteAllOverloadCandidates(Expr* E);
// [PossiblyAFunctionType] --> [Return]
// NonFunctionType --> NonFunctionType
// R (A) --> R(A)
// R (*)(A) --> R (A)
// R (&)(A) --> R (A)
// R (S::*)(A) --> R (A)
QualType ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType);
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType,
bool Complain,
DeclAccessPair &Found);
FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From);
FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From,
bool Complain = false,
DeclAccessPair* Found = 0);
Expr *FixOverloadedFunctionReference(Expr *E,
DeclAccessPair FoundDecl,
@ -3702,7 +3718,8 @@ public:
SourceLocation Loc,
const PartialDiagnostic &NoneDiag,
const PartialDiagnostic &AmbigDiag,
const PartialDiagnostic &CandidateDiag);
const PartialDiagnostic &CandidateDiag,
bool Complain = true);
ClassTemplatePartialSpecializationDecl *
getMoreSpecializedPartialSpecialization(

Просмотреть файл

@ -22,7 +22,6 @@
using namespace clang;
static void NoteAllOverloadCandidates(Expr* const Expr, Sema& sema);
enum TryCastResult {
TC_NotApplicable, ///< The cast method is not applicable.
@ -122,12 +121,24 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
CXXCastPath &BasePath);
static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
bool CStyle, unsigned &msg);
static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind);
static ExprResult
ResolveAndFixSingleFunctionTemplateSpecialization(
Sema &Self, Expr *SrcExpr,
bool DoFunctionPointerConverion = false,
bool Complain = false,
const SourceRange& OpRangeForComplaining = SourceRange(),
QualType DestTypeForComplaining = QualType(),
unsigned DiagIDForComplaining = 0);
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
ExprResult
Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
@ -583,7 +594,7 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_overload)
<< OverloadExpr::find(SrcExpr).Expression->getName()
<< DestType << OpRange;
NoteAllOverloadCandidates(SrcExpr, Self);
Self.NoteAllOverloadCandidates(SrcExpr);
} else {
diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr, DestType);
@ -604,7 +615,20 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
if (DestType->isVoidType()) {
Self.IgnoredValueConversions(SrcExpr);
Kind = CK_ToVoid;
if (SrcExpr->getType() == Self.Context.OverloadTy) {
ExprResult SingleFunctionExpression =
ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr,
false, // Decay Function to ptr
true, // Complain
OpRange, DestType, diag::err_bad_static_cast_overload);
if (SingleFunctionExpression.isUsable())
{
SrcExpr = SingleFunctionExpression.release();
Kind = CK_ToVoid;
}
}
else
Kind = CK_ToVoid;
return;
}
@ -614,13 +638,12 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
Kind, BasePath) != TC_Success && msg != 0)
{
Kind, BasePath) != TC_Success && msg != 0) {
if (SrcExpr->getType() == Self.Context.OverloadTy) {
OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression;
Self.Diag(OpRange.getBegin(), diag::err_bad_static_cast_overload)
<< oe->getName() << DestType << OpRange << oe->getQualifierRange();
NoteAllOverloadCandidates(SrcExpr, Self);
Self.NoteAllOverloadCandidates(SrcExpr);
} else {
diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr, DestType);
}
@ -1236,32 +1259,44 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
return TC_Success;
}
// A helper function to resolve and fix an overloaded expression that
// can be resolved because it identifies a single function
// template specialization
// Last three arguments should only be supplied if Complain = true
static ExprResult ResolveAndFixSingleFunctionTemplateSpecialization(
Sema &Self, Expr *SrcExpr,
bool DoFunctionPointerConverion,
bool Complain,
const SourceRange& OpRangeForComplaining,
QualType DestTypeForComplaining,
unsigned DiagIDForComplaining) {
assert(SrcExpr->getType() == Self.Context.OverloadTy);
DeclAccessPair Found;
bool ret = false;
Expr* SingleFunctionExpression = 0;
if (FunctionDecl* Fn = Self.ResolveSingleFunctionTemplateSpecialization(
SrcExpr, false, // false -> Complain
&Found)) {
if (!Self.DiagnoseUseOfDecl(Fn, SrcExpr->getSourceRange().getBegin())) {
// mark the expression as resolved to Fn
SingleFunctionExpression = Self.FixOverloadedFunctionReference(SrcExpr,
Found, Fn);
static void NoteAllOverloadCandidates(Expr* const Expr, Sema& sema)
{
assert(Expr->getType() == sema.Context.OverloadTy);
OverloadExpr::FindResult Ovl = OverloadExpr::find(Expr);
OverloadExpr *const OvlExpr = Ovl.Expression;
for (UnresolvedSetIterator it = OvlExpr->decls_begin(),
end = OvlExpr->decls_end(); it != end; ++it) {
if ( FunctionTemplateDecl *ftd =
dyn_cast<FunctionTemplateDecl>((*it)->getUnderlyingDecl()) )
{
sema.NoteOverloadCandidate(ftd->getTemplatedDecl());
}
else if ( FunctionDecl *f =
dyn_cast<FunctionDecl>((*it)->getUnderlyingDecl()) )
{
sema.NoteOverloadCandidate(f);
if (DoFunctionPointerConverion)
Self.DefaultFunctionArrayLvalueConversion(SingleFunctionExpression);
}
}
if (!SingleFunctionExpression && Complain) {
OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression;
Self.Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining)
<< oe->getName() << DestTypeForComplaining << OpRangeForComplaining
<< oe->getQualifierRange();
Self.NoteAllOverloadCandidates(SrcExpr);
}
return SingleFunctionExpression;
}
static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
@ -1272,9 +1307,20 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
QualType SrcType = SrcExpr->getType();
// Is the source an overloaded name? (i.e. &foo)
// If so, reinterpret_cast can not help us here (13.4, p1, bullet 5)
if (SrcType == Self.Context.OverloadTy)
return TC_NotApplicable;
// If so, reinterpret_cast can not help us here (13.4, p1, bullet 5) ...
if (SrcType == Self.Context.OverloadTy) {
// ... unless foo<int> resolves to an lvalue unambiguously
ExprResult SingleFunctionExpr =
ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr,
Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr
);
if (SingleFunctionExpr.isUsable()) {
SrcExpr = SingleFunctionExpr.release();
SrcType = SrcExpr->getType();
}
else
return TC_NotApplicable;
}
if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) {
bool LValue = DestTypeTmp->isLValueReferenceType();
@ -1495,8 +1541,24 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
if (CastTy->isVoidType()) {
IgnoredValueConversions(CastExpr);
Kind = CK_ToVoid;
return false;
bool ret = false; // false is 'able to convert'
if (CastExpr->getType() == Context.OverloadTy) {
ExprResult SingleFunctionExpr =
ResolveAndFixSingleFunctionTemplateSpecialization(*this,
CastExpr,
/* Decay Function to ptr */ false,
/* Complain */ true,
R, CastTy, diag::err_bad_cstyle_cast_overload);
if (SingleFunctionExpr.isUsable()) {
CastExpr = SingleFunctionExpr.release();
Kind = CK_ToVoid;
}
else
ret = true;
}
else
Kind = CK_ToVoid;
return ret;
}
// Make sure we determine the value kind before we bail out for
@ -1547,7 +1609,9 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
CastTy,
/* Complain */ true,
Found);
assert(!Fn && "cast failed but able to resolve overload expression!!");
assert(!Fn
&& "cast failed but able to resolve overload expression!!");
(void)Fn;
} else {

Просмотреть файл

@ -3190,7 +3190,10 @@ InitializationSequence::InitializationSequence(Sema &S,
/*InOverloadResolution*/ false,
/*CStyle=*/Kind.isCStyleOrFunctionalCast()))
{
if (Initializer->getType() == Context.OverloadTy)
DeclAccessPair dap;
if (Initializer->getType() == Context.OverloadTy &&
!S.ResolveAddressOfOverloadedFunction(Initializer
, DestType, false, dap))
SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
else
SetFailed(InitializationSequence::FK_ConversionFailed);
@ -4161,15 +4164,16 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
break;
case FK_ConversionFailed:
case FK_ConversionFailed: {
QualType FromType = Args[0]->getType();
S.Diag(Kind.getLocation(), diag::err_init_conversion_failed)
<< (int)Entity.getKind()
<< DestType
<< Args[0]->isLValue()
<< Args[0]->getType()
<< FromType
<< Args[0]->getSourceRange();
break;
}
case FK_TooManyInitsForScalar: {
SourceRange R;

Просмотреть файл

@ -1036,6 +1036,21 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// We were able to resolve the address of the overloaded function,
// so we can convert to the type of that function.
FromType = Fn->getType();
// we can sometimes resolve &foo<int> regardless of ToType, so check
// if the type matches (identity) or we are converting to bool
if (!S.Context.hasSameUnqualifiedType(
S.ExtractUnqualifiedFunctionType(ToType), FromType)) {
QualType resultTy;
// if the function type matches except for [[noreturn]], it's ok
if (!IsNoReturnConversion(S.Context, FromType,
S.ExtractUnqualifiedFunctionType(ToType), resultTy))
// otherwise, only a boolean conversion is standard
if (!ToType->isBooleanType())
return false;
}
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
if (!Method->isStatic()) {
const Type *ClassType
@ -6349,6 +6364,27 @@ void Sema::NoteOverloadCandidate(FunctionDecl *Fn) {
MaybeEmitInheritedConstructorNote(*this, Fn);
}
//Notes the location of all overload candidates designated through
// OverloadedExpr
void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr) {
assert(OverloadedExpr->getType() == Context.OverloadTy);
OverloadExpr::FindResult Ovl = OverloadExpr::find(OverloadedExpr);
OverloadExpr *OvlExpr = Ovl.Expression;
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
IEnd = OvlExpr->decls_end();
I != IEnd; ++I) {
if (FunctionTemplateDecl *FunTmpl =
dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) {
NoteOverloadCandidate(FunTmpl->getTemplatedDecl());
} else if (FunctionDecl *Fun
= dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) {
NoteOverloadCandidate(Fun);
}
}
}
/// Diagnoses an ambiguous conversion. The partial diagnostic is the
/// "lead" diagnostic; it will be given two arguments, the source and
/// target types of the conversion.
@ -7049,186 +7085,207 @@ static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) {
return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(E), D);
}
/// ResolveAddressOfOverloadedFunction - Try to resolve the address of
/// an overloaded function (C++ [over.over]), where @p From is an
/// expression with overloaded function type and @p ToType is the type
/// we're trying to resolve to. For example:
///
/// @code
/// int f(double);
/// int f(int);
///
/// int (*pfd)(double) = f; // selects f(double)
/// @endcode
///
/// This routine returns the resulting FunctionDecl if it could be
/// resolved, and NULL otherwise. When @p Complain is true, this
/// routine will emit diagnostics if there is an error.
FunctionDecl *
Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
bool Complain,
DeclAccessPair &FoundResult) {
QualType FunctionType = ToType;
bool IsMember = false;
if (const PointerType *ToTypePtr = ToType->getAs<PointerType>())
FunctionType = ToTypePtr->getPointeeType();
else if (const ReferenceType *ToTypeRef = ToType->getAs<ReferenceType>())
FunctionType = ToTypeRef->getPointeeType();
// [PossiblyAFunctionType] --> [Return]
// NonFunctionType --> NonFunctionType
// R (A) --> R(A)
// R (*)(A) --> R (A)
// R (&)(A) --> R (A)
// R (S::*)(A) --> R (A)
QualType Sema::ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType) {
QualType Ret = PossiblyAFunctionType;
if (const PointerType *ToTypePtr =
PossiblyAFunctionType->getAs<PointerType>())
Ret = ToTypePtr->getPointeeType();
else if (const ReferenceType *ToTypeRef =
PossiblyAFunctionType->getAs<ReferenceType>())
Ret = ToTypeRef->getPointeeType();
else if (const MemberPointerType *MemTypePtr =
ToType->getAs<MemberPointerType>()) {
FunctionType = MemTypePtr->getPointeeType();
IsMember = true;
}
PossiblyAFunctionType->getAs<MemberPointerType>())
Ret = MemTypePtr->getPointeeType();
Ret =
Context.getCanonicalType(Ret).getUnqualifiedType();
return Ret;
}
// C++ [over.over]p1:
// [...] [Note: any redundant set of parentheses surrounding the
// overloaded function name is ignored (5.1). ]
// C++ [over.over]p1:
// [...] The overloaded function name can be preceded by the &
// operator.
// However, remember whether the expression has member-pointer form:
// C++ [expr.unary.op]p4:
// A pointer to member is only formed when an explicit & is used
// and its operand is a qualified-id not enclosed in
// parentheses.
OverloadExpr::FindResult Ovl = OverloadExpr::find(From);
OverloadExpr *OvlExpr = Ovl.Expression;
// A helper class to help with address of function resolution
// - allows us to avoid passing around all those ugly parameters
class AddressOfFunctionResolver
{
Sema& S;
Expr* SourceExpr;
const QualType& TargetType;
QualType TargetFunctionType; // Extracted function type from target type
// We expect a pointer or reference to function, or a function pointer.
FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType();
if (!FunctionType->isFunctionType()) {
if (Complain)
Diag(From->getLocStart(), diag::err_addr_ovl_not_func_ptrref)
<< OvlExpr->getName() << ToType;
bool Complain;
//DeclAccessPair& ResultFunctionAccessPair;
ASTContext& Context;
return 0;
}
bool TargetTypeIsNonStaticMemberFunction;
bool FoundNonTemplateFunction;
// If the overload expression doesn't have the form of a pointer to
// member, don't try to convert it to a pointer-to-member type.
if (IsMember && !Ovl.HasFormOfMemberPointer) {
if (!Complain) return 0;
// TODO: Should we condition this on whether any functions might
// have matched, or is it more appropriate to do that in callers?
// TODO: a fixit wouldn't hurt.
Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier)
<< ToType << OvlExpr->getSourceRange();
return 0;
}
TemplateArgumentListInfo ETABuffer, *ExplicitTemplateArgs = 0;
if (OvlExpr->hasExplicitTemplateArgs()) {
OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer);
ExplicitTemplateArgs = &ETABuffer;
}
assert(From->getType() == Context.OverloadTy);
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
OverloadExpr::FindResult OvlExprInfo;
OverloadExpr *OvlExpr;
TemplateArgumentListInfo OvlExplicitTemplateArgs;
llvm::SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
llvm::SmallVector<FunctionDecl *, 4> NonMatches;
bool FoundNonTemplateFunction = false;
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
E = OvlExpr->decls_end(); I != E; ++I) {
// Look through any using declarations to find the underlying function.
NamedDecl *Fn = (*I)->getUnderlyingDecl();
public:
AddressOfFunctionResolver(Sema &S, Expr* SourceExpr,
const QualType& TargetType, bool Complain)
: S(S), SourceExpr(SourceExpr), TargetType(TargetType),
Complain(Complain), Context(S.getASTContext()),
TargetTypeIsNonStaticMemberFunction(
!!TargetType->getAs<MemberPointerType>()),
FoundNonTemplateFunction(false),
OvlExprInfo(OverloadExpr::find(SourceExpr)),
OvlExpr(OvlExprInfo.Expression)
{
ExtractUnqualifiedFunctionTypeFromTargetType();
// C++ [over.over]p3:
// Non-member functions and static member functions match
// targets of type "pointer-to-function" or "reference-to-function."
// Nonstatic member functions match targets of
// type "pointer-to-member-function."
// Note that according to DR 247, the containing class does not matter.
if (FunctionTemplateDecl *FunctionTemplate
= dyn_cast<FunctionTemplateDecl>(Fn)) {
if (CXXMethodDecl *Method
= dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl())) {
// Skip non-static function templates when converting to pointer, and
// static when converting to member pointer.
if (Method->isStatic() == IsMember)
continue;
} else if (IsMember)
continue;
// 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.
FunctionDecl *Specialization = 0;
TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc());
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
FunctionType, Specialization, Info)) {
// FIXME: make a note of the failed deduction for diagnostics.
(void)Result;
} else {
// Template argument deduction ensures that we have an exact match.
// This function template specicalization works.
Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl());
assert(FunctionType
== Context.getCanonicalType(Specialization->getType()));
Matches.push_back(std::make_pair(I.getPair(), Specialization));
if (!TargetFunctionType->isFunctionType()) {
if (OvlExpr->hasExplicitTemplateArgs()) {
DeclAccessPair dap;
if( FunctionDecl* Fn = S.ResolveSingleFunctionTemplateSpecialization(
OvlExpr, false, &dap) ) {
Matches.push_back(std::make_pair(dap,Fn));
}
}
continue;
return;
}
if (OvlExpr->hasExplicitTemplateArgs())
OvlExpr->getExplicitTemplateArgs().copyInto(OvlExplicitTemplateArgs);
if (FindAllFunctionsThatMatchTargetTypeExactly()) {
// C++ [over.over]p4:
// If more than one function is selected, [...]
if (Matches.size() > 1) {
if (FoundNonTemplateFunction)
EliminateAllTemplateMatches();
else
EliminateAllExceptMostSpecializedTemplate();
}
}
}
private:
bool isTargetTypeAFunction() const {
return TargetFunctionType->isFunctionType();
}
// [ToType] [Return]
// R (*)(A) --> R (A), IsNonStaticMemberFunction = false
// R (&)(A) --> R (A), IsNonStaticMemberFunction = false
// R (S::*)(A) --> R (A), IsNonStaticMemberFunction = true
void inline ExtractUnqualifiedFunctionTypeFromTargetType() {
TargetFunctionType = S.ExtractUnqualifiedFunctionType(TargetType);
}
// return true if any matching specializations were found
bool AddMatchingTemplateFunction(FunctionTemplateDecl* FunctionTemplate,
const DeclAccessPair& CurAccessFunPair) {
if (CXXMethodDecl *Method
= dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl())) {
// Skip non-static function templates when converting to pointer, and
// static when converting to member pointer.
if (Method->isStatic() == TargetTypeIsNonStaticMemberFunction)
return false;
}
else if (TargetTypeIsNonStaticMemberFunction)
return false;
// 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.
FunctionDecl *Specialization = 0;
TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc());
if (Sema::TemplateDeductionResult Result
= S.DeduceTemplateArguments(FunctionTemplate,
&OvlExplicitTemplateArgs,
TargetFunctionType, Specialization,
Info)) {
// FIXME: make a note of the failed deduction for diagnostics.
(void)Result;
return false;
}
// Template argument deduction ensures that we have an exact match.
// This function template specicalization works.
Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl());
assert(TargetFunctionType
== Context.getCanonicalType(Specialization->getType()));
Matches.push_back(std::make_pair(CurAccessFunPair, Specialization));
return true;
}
bool AddMatchingNonTemplateFunction(NamedDecl* Fn,
const DeclAccessPair& CurAccessFunPair) {
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
// Skip non-static functions when converting to pointer, and static
// when converting to member pointer.
if (Method->isStatic() == IsMember)
continue;
// If we have explicit template arguments, skip non-templates.
if (OvlExpr->hasExplicitTemplateArgs())
continue;
} else if (IsMember)
continue;
if (Method->isStatic() == TargetTypeIsNonStaticMemberFunction)
return false;
}
else if (TargetTypeIsNonStaticMemberFunction)
return false;
if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) {
QualType ResultTy;
if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) ||
IsNoReturnConversion(Context, FunDecl->getType(), FunctionType,
if (Context.hasSameUnqualifiedType(TargetFunctionType,
FunDecl->getType()) ||
IsNoReturnConversion(Context, FunDecl->getType(), TargetFunctionType,
ResultTy)) {
Matches.push_back(std::make_pair(I.getPair(),
cast<FunctionDecl>(FunDecl->getCanonicalDecl())));
Matches.push_back(std::make_pair(CurAccessFunPair,
cast<FunctionDecl>(FunDecl->getCanonicalDecl())));
FoundNonTemplateFunction = true;
return true;
}
}
return false;
}
// If there were 0 or 1 matches, we're done.
if (Matches.empty()) {
if (Complain) {
Diag(From->getLocStart(), diag::err_addr_ovl_no_viable)
<< OvlExpr->getName() << FunctionType;
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
E = OvlExpr->decls_end();
I != E; ++I)
if (FunctionDecl *F = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()))
NoteOverloadCandidate(F);
}
bool FindAllFunctionsThatMatchTargetTypeExactly() {
bool Ret = false;
return 0;
} else if (Matches.size() == 1) {
FunctionDecl *Result = Matches[0].second;
FoundResult = Matches[0].first;
MarkDeclarationReferenced(From->getLocStart(), Result);
if (Complain) {
CheckAddressOfMemberAccess(OvlExpr, Matches[0].first);
// If the overload expression doesn't have the form of a pointer to
// member, don't try to convert it to a pointer-to-member type.
if (IsInvalidFormOfPointerToMemberFunction())
return false;
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
E = OvlExpr->decls_end();
I != E; ++I) {
// Look through any using declarations to find the underlying function.
NamedDecl *Fn = (*I)->getUnderlyingDecl();
// C++ [over.over]p3:
// Non-member functions and static member functions match
// targets of type "pointer-to-function" or "reference-to-function."
// Nonstatic member functions match targets of
// type "pointer-to-member-function."
// Note that according to DR 247, the containing class does not matter.
if (FunctionTemplateDecl *FunctionTemplate
= dyn_cast<FunctionTemplateDecl>(Fn)) {
if (AddMatchingTemplateFunction(FunctionTemplate, I.getPair()))
Ret = true;
}
// If we have explicit template arguments supplied, skip non-templates.
else if (!OvlExpr->hasExplicitTemplateArgs() &&
AddMatchingNonTemplateFunction(Fn, I.getPair()))
Ret = true;
}
return Result;
assert(Ret || Matches.empty());
return Ret;
}
// C++ [over.over]p4:
// If more than one function is selected, [...]
if (!FoundNonTemplateFunction) {
void EliminateAllExceptMostSpecializedTemplate() {
// [...] and any given function template specialization F1 is
// eliminated if the set contains a second function template
// specialization whose function template is more specialized
@ -7245,54 +7302,127 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
MatchesCopy.addDecl(Matches[I].second, Matches[I].first.getAccess());
UnresolvedSetIterator Result =
getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(),
TPOC_Other, 0, From->getLocStart(),
PDiag(),
PDiag(diag::err_addr_ovl_ambiguous)
<< Matches[0].second->getDeclName(),
PDiag(diag::note_ovl_candidate)
<< (unsigned) oc_function_template);
if (Result == MatchesCopy.end())
return 0;
S.getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(),
TPOC_Other, 0, SourceExpr->getLocStart(),
S.PDiag(),
S.PDiag(diag::err_addr_ovl_ambiguous)
<< Matches[0].second->getDeclName(),
S.PDiag(diag::note_ovl_candidate)
<< (unsigned) oc_function_template,
Complain);
MarkDeclarationReferenced(From->getLocStart(), *Result);
FoundResult = Matches[Result - MatchesCopy.begin()].first;
if (Complain)
CheckUnresolvedAccess(*this, OvlExpr, FoundResult);
return cast<FunctionDecl>(*Result);
}
// [...] any function template specializations in the set are
// eliminated if the set also contains a non-template function, [...]
for (unsigned I = 0, N = Matches.size(); I != N; ) {
if (Matches[I].second->getPrimaryTemplate() == 0)
++I;
else {
Matches[I] = Matches[--N];
Matches.set_size(N);
if (Result != MatchesCopy.end()) {
// Make it the first and only element
Matches[0].first = Matches[Result - MatchesCopy.begin()].first;
Matches[0].second = cast<FunctionDecl>(*Result);
Matches.resize(1);
}
}
// [...] After such eliminations, if any, there shall remain exactly one
// selected function.
if (Matches.size() == 1) {
MarkDeclarationReferenced(From->getLocStart(), Matches[0].second);
FoundResult = Matches[0].first;
void EliminateAllTemplateMatches() {
// [...] any function template specializations in the set are
// eliminated if the set also contains a non-template function, [...]
for (unsigned I = 0, N = Matches.size(); I != N; ) {
if (Matches[I].second->getPrimaryTemplate() == 0)
++I;
else {
Matches[I] = Matches[--N];
Matches.set_size(N);
}
}
}
public:
void ComplainNoMatchesFound() const {
assert(Matches.empty());
S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_no_viable)
<< OvlExpr->getName() << TargetFunctionType
<< OvlExpr->getSourceRange();
S.NoteAllOverloadCandidates(OvlExpr);
}
bool IsInvalidFormOfPointerToMemberFunction() const {
return TargetTypeIsNonStaticMemberFunction &&
!OvlExprInfo.HasFormOfMemberPointer;
}
void ComplainIsInvalidFormOfPointerToMemberFunction() const {
// TODO: Should we condition this on whether any functions might
// have matched, or is it more appropriate to do that in callers?
// TODO: a fixit wouldn't hurt.
S.Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier)
<< TargetType << OvlExpr->getSourceRange();
}
void ComplainOfInvalidConversion() const {
S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_not_func_ptrref)
<< OvlExpr->getName() << TargetType;
}
void ComplainMultipleMatchesFound() const {
assert(Matches.size() > 1);
S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_ambiguous)
<< OvlExpr->getName()
<< OvlExpr->getSourceRange();
S.NoteAllOverloadCandidates(OvlExpr);
}
int getNumMatches() const { return Matches.size(); }
FunctionDecl* getMatchingFunctionDecl() const {
if (Matches.size() != 1) return 0;
return Matches[0].second;
}
const DeclAccessPair* getMatchingFunctionAccessPair() const {
if (Matches.size() != 1) return 0;
return &Matches[0].first;
}
};
/// ResolveAddressOfOverloadedFunction - Try to resolve the address of
/// an overloaded function (C++ [over.over]), where @p From is an
/// expression with overloaded function type and @p ToType is the type
/// we're trying to resolve to. For example:
///
/// @code
/// int f(double);
/// int f(int);
///
/// int (*pfd)(double) = f; // selects f(double)
/// @endcode
///
/// This routine returns the resulting FunctionDecl if it could be
/// resolved, and NULL otherwise. When @p Complain is true, this
/// routine will emit diagnostics if there is an error.
FunctionDecl *
Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType,
bool Complain,
DeclAccessPair &FoundResult) {
assert(AddressOfExpr->getType() == Context.OverloadTy);
AddressOfFunctionResolver Resolver(*this, AddressOfExpr, TargetType, Complain);
int NumMatches = Resolver.getNumMatches();
FunctionDecl* Fn = 0;
if ( NumMatches == 0 && Complain) {
if (Resolver.IsInvalidFormOfPointerToMemberFunction())
Resolver.ComplainIsInvalidFormOfPointerToMemberFunction();
else
Resolver.ComplainNoMatchesFound();
}
else if (NumMatches > 1 && Complain)
Resolver.ComplainMultipleMatchesFound();
else if (NumMatches == 1) {
Fn = Resolver.getMatchingFunctionDecl();
assert(Fn);
FoundResult = *Resolver.getMatchingFunctionAccessPair();
MarkDeclarationReferenced(AddressOfExpr->getLocStart(), Fn);
if (Complain)
CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first);
return cast<FunctionDecl>(Matches[0].second);
CheckAddressOfMemberAccess(AddressOfExpr, FoundResult);
}
// FIXME: We should probably return the same thing that BestViableFunction
// returns (even if we issue the diagnostics here).
if (Complain) {
Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
<< Matches[0].second->getDeclName();
for (unsigned I = 0, E = Matches.size(); I != E; ++I)
NoteOverloadCandidate(Matches[I].second);
}
return 0;
return Fn;
}
/// \brief Given an expression that refers to an overloaded function, try to
@ -7302,14 +7432,15 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
/// 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) {
FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From,
bool Complain,
DeclAccessPair* FoundResult) {
// C++ [over.over]p1:
// [...] [Note: any redundant set of parentheses surrounding the
// overloaded function name is ignored (5.1). ]
// C++ [over.over]p1:
// [...] The overloaded function name can be preceded by the &
// operator.
if (From->getType() != Context.OverloadTy)
return 0;
@ -7353,10 +7484,20 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
}
// Multiple matches; we can't resolve to a single declaration.
if (Matched)
return 0;
if (Matched) {
if (FoundResult)
*FoundResult = DeclAccessPair();
Matched = Specialization;
if (Complain) {
Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
<< OvlExpr->getName();
NoteAllOverloadCandidates(OvlExpr);
}
return 0;
}
if ((Matched = Specialization) && FoundResult)
*FoundResult = I.getPair();
}
return Matched;

Просмотреть файл

@ -1824,6 +1824,11 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
// template arguments that we have against the template name, if the template
// name refers to a single template. That's not a terribly common case,
// though.
// foo<int> could identify a single function unambiguously
// This approach does NOT work, since f<int>(1);
// gets resolved prior to resorting to overload resolution
// i.e., template<class T> void f(double);
// vs template<class T, class U> void f(U);
// These should be filtered out by our callers.
assert(!R.empty() && "empty lookup results when building templateid");

Просмотреть файл

@ -3322,9 +3322,11 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
SourceLocation Loc,
const PartialDiagnostic &NoneDiag,
const PartialDiagnostic &AmbigDiag,
const PartialDiagnostic &CandidateDiag) {
const PartialDiagnostic &CandidateDiag,
bool Complain) {
if (SpecBegin == SpecEnd) {
Diag(Loc, NoneDiag);
if (Complain)
Diag(Loc, NoneDiag);
return SpecEnd;
}
@ -3370,13 +3372,15 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
}
// Diagnose the ambiguity.
Diag(Loc, AmbigDiag);
if (Complain)
Diag(Loc, AmbigDiag);
if (Complain)
// FIXME: Can we order the candidates in some sane way?
for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I)
Diag((*I)->getLocation(), CandidateDiag)
<< getTemplateArgumentBindingsText(
cast<FunctionDecl>(*I)->getPrimaryTemplate()->getTemplateParameters(),
for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I)
Diag((*I)->getLocation(), CandidateDiag)
<< getTemplateArgumentBindingsText(
cast<FunctionDecl>(*I)->getPrimaryTemplate()->getTemplateParameters(),
*cast<FunctionDecl>(*I)->getTemplateSpecializationArgs());
return SpecEnd;

Просмотреть файл

@ -0,0 +1,95 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
typedef __typeof__(((int*)0)-((int*)0)) ptrdiff_t;
namespace DontResolveTooEarly_WaitForOverloadResolution
{
template <class T> T* f(int); // #1
template <class T, class U> T& f(U); // #2
void g() {
int *ip = f<int>(1); // calls #1
}
template <class T>
T* f2(int);
template <class T, class U>
T& f2(U);
void g2() {
int*ip = (f2<int>)(1); // ok
}
} // End namespace
template<typename T>
void twoT() { }
template<typename T, typename U>
void twoT(T) { }
void two() { }; //expected-note 5{{candidate}}
void two(int) { }; //expected-note 5{{candidate}}
void one() { }
template<class T>
void oneT() { }
template<class T>
void cant_resolve() { } //expected-note 3{{candidate}}
template<class T> void cant_resolve(T) { }//expected-note 3{{candidate}}
int main()
{
{ static_cast<void>(one); }
{ (void)(one); }
{ static_cast<void>(oneT<int>); }
{ (void)(oneT<int>); }
{ static_cast<void>(two); } // expected-error {{address of overloaded}}
{ (void)(two); } // expected-error {{address of overloaded}}
{ static_cast<void>(twoT<int>); }
{ (void)(twoT<int>); }
{ ptrdiff_t x = reinterpret_cast<ptrdiff_t>(oneT<int>); }
{ (void) reinterpret_cast<int (*)(char, double)>(oneT<int>); }
{ (void) reinterpret_cast<ptrdiff_t>(one); }
{ (void) reinterpret_cast<int (*)(char, double)>(one); }
{ ptrdiff_t x = reinterpret_cast<ptrdiff_t>(twoT<int>); }
{ (void) reinterpret_cast<int (*)(char, double)>(twoT<int>); }
{ (void) reinterpret_cast<void (*)(int)>(two); } //expected-error {{reinterpret_cast}}
{ (void) static_cast<void (*)(int)>(two); } //ok
{ (void) reinterpret_cast<int>(two); } //expected-error {{reinterpret_cast}}
{ (void) reinterpret_cast<int (*)(char, double)>(two); } //expected-error {{reinterpret_cast}}
{ bool b = (twoT<int>); } // ok
{ bool b = (twoT<int, int>); } //ok
{ bool b = &twoT<int>; //&foo<int>; }
b = &(twoT<int>); }
{ ptrdiff_t x = (ptrdiff_t) &twoT<int>;
x = (ptrdiff_t) &twoT<int>; }
{ ptrdiff_t x = (ptrdiff_t) twoT<int>;
x = (ptrdiff_t) twoT<int>; }
{ ptrdiff_t x = (ptrdiff_t) &twoT<int,int>;
x = (ptrdiff_t) &twoT<int>; }
{ oneT<int>; &oneT<int>; } //expected-warning 2{{ expression result unused }}
{ static_cast<void>(cant_resolve<int>); } // expected-error {{address of overload}}
{ bool b = cant_resolve<int>; } // expected-error {{address of overload}}
{ (void) cant_resolve<int>; } // expected-error {{address of overload}}
}

Просмотреть файл

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
template<typename T> T f0(T, T);
template<typename T> T f0(T, T); //expected-note{{candidate}}
void test_f0() {
int (*f0a)(int, int) = f0;

Просмотреть файл

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
template<typename T> T f0(T);
template<typename T> T f0(T); // expected-note{{candidate function}}
int f0(int); // expected-note{{candidate function}}
void test_f0() {
@ -13,8 +13,6 @@ namespace N {
int f0(int); // expected-note{{candidate function}}
}
int f0(int);
void test_f0_2() {
using namespace N;
int (*fp0)(int) = f0; // expected-error{{address of overloaded function 'f0' is ambiguous}}

Просмотреть файл

@ -4,8 +4,8 @@ void g();
void f(); // expected-note 9{{candidate function}}
void f(int); // expected-note 9{{candidate function}}
template<class T> void t(T); // expected-note 3{{candidate function}}
template<class T> void t(T*); // expected-note 3{{candidate function}}
template<class T> void t(T); // expected-note 6{{candidate function}}
template<class T> void t(T*); // expected-note 6{{candidate function}}
template<class T> void u(T);

Просмотреть файл

@ -57,11 +57,11 @@ struct B
struct C {
C &getC() {
return makeAC; // expected-error{{address of overloaded function 'makeAC' cannot be converted to type 'C'}}
return makeAC; // expected-error{{address of overloaded function 'makeAC'}}
}
C &makeAC();
const C &makeAC() const;
C &makeAC(); //expected-note{{candidate function}}
const C &makeAC() const; //expected-note{{candidate function}}
static void f(); // expected-note{{candidate function}}
static void f(int); // expected-note{{candidate function}}