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
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 8306eb4..d72faac 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2686,6 +2686,10 @@
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">;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index a835bb2..c95ce62 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1247,12 +1247,28 @@
OverloadCandidateSet& CandidateSet,
bool PartialOverloading = false);
+ // Emit as a 'note' the specific overload candidate
void NoteOverloadCandidate(FunctionDecl *Fn);
+
+ // 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 *From, QualType ToType,
+ 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 @@
SourceLocation Loc,
const PartialDiagnostic &NoneDiag,
const PartialDiagnostic &AmbigDiag,
- const PartialDiagnostic &CandidateDiag);
+ const PartialDiagnostic &CandidateDiag,
+ bool Complain = true);
ClassTemplatePartialSpecializationDecl *
getMoreSpecializedPartialSpecialization(
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 30bb576..4e5a481 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -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 @@
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 @@
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 @@
// 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 @@
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 @@
return TC_Success;
}
-
-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);
- }
+// 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);
+
+ 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 @@
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 @@
// 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 @@
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 {
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 3aeb518..b074948 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -3190,7 +3190,10 @@
/*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 @@
<< 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;
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 3d0608e..6fb789c 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1036,6 +1036,21 @@
// 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 @@
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 @@
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
+
+ bool Complain;
+ //DeclAccessPair& ResultFunctionAccessPair;
+ ASTContext& Context;
- // 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 TargetTypeIsNonStaticMemberFunction;
+ bool FoundNonTemplateFunction;
- return 0;
- }
-
- // 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();
-
- // 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));
+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();
+
+ 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;
+ }
+
+ bool FindAllFunctionsThatMatchTargetTypeExactly() {
+ bool Ret = false;
+
+ // 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;
+ }
+ assert(Ret || Matches.empty());
+ return Ret;
}
- // 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);
- }
-
- 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);
- }
- return Result;
- }
-
- // 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 @@
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 @@
/// 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 @@
}
// Multiple matches; we can't resolve to a single declaration.
- if (Matched)
+ if (Matched) {
+ if (FoundResult)
+ *FoundResult = DeclAccessPair();
+
+ if (Complain) {
+ Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
+ << OvlExpr->getName();
+ NoteAllOverloadCandidates(OvlExpr);
+ }
return 0;
-
- Matched = Specialization;
+ }
+
+ if ((Matched = Specialization) && FoundResult)
+ *FoundResult = I.getPair();
}
return Matched;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 12ed373..9a11c68 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1824,6 +1824,11 @@
// 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");
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 5a0359c..fceeaa7 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -3322,9 +3322,11 @@
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 @@
}
// 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;
diff --git a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
new file mode 100644
index 0000000..f38a74e
--- /dev/null
+++ b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
@@ -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}}
+
+}
+
+
diff --git a/test/CXX/over/over.over/p2.cpp b/test/CXX/over/over.over/p2.cpp
index 1c3d036..3e8d0f1 100644
--- a/test/CXX/over/over.over/p2.cpp
+++ b/test/CXX/over/over.over/p2.cpp
@@ -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;
diff --git a/test/CXX/over/over.over/p4.cpp b/test/CXX/over/over.over/p4.cpp
index 7b5009a..27d070e 100644
--- a/test/CXX/over/over.over/p4.cpp
+++ b/test/CXX/over/over.over/p4.cpp
@@ -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 @@
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}}
diff --git a/test/SemaCXX/addr-of-overloaded-function-casting.cpp b/test/SemaCXX/addr-of-overloaded-function-casting.cpp
index 49abdea..cfd55ee 100644
--- a/test/SemaCXX/addr-of-overloaded-function-casting.cpp
+++ b/test/SemaCXX/addr-of-overloaded-function-casting.cpp
@@ -4,8 +4,8 @@
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);
diff --git a/test/SemaCXX/addr-of-overloaded-function.cpp b/test/SemaCXX/addr-of-overloaded-function.cpp
index 00d9104..a1079ff 100644
--- a/test/SemaCXX/addr-of-overloaded-function.cpp
+++ b/test/SemaCXX/addr-of-overloaded-function.cpp
@@ -57,11 +57,11 @@
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}}