Sema: Diagnose explicitly bound unresolved member expressions decaying into pointers to function type
We would disallow the case where the overloaded member expression is
coming from an address-of operator but we wouldn't issue any diagnostics
when the overloaded member expression comes by way of a function to
pointer decay cast.
Clang's implementation of DR61 is now seemingly complete.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@187559 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 7241551..1a9b829 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -9282,6 +9282,7 @@
bool TargetTypeIsNonStaticMemberFunction;
bool FoundNonTemplateFunction;
+ bool StaticMemberFunctionFromBoundPointer;
OverloadExpr::FindResult OvlExprInfo;
OverloadExpr *OvlExpr;
@@ -9297,33 +9298,35 @@
TargetTypeIsNonStaticMemberFunction(
!!TargetType->getAs<MemberPointerType>()),
FoundNonTemplateFunction(false),
+ StaticMemberFunctionFromBoundPointer(false),
OvlExprInfo(OverloadExpr::find(SourceExpr)),
OvlExpr(OvlExprInfo.Expression),
FailedCandidates(OvlExpr->getNameLoc()) {
ExtractUnqualifiedFunctionTypeFromTargetType();
-
- if (!TargetFunctionType->isFunctionType()) {
- if (OvlExpr->hasExplicitTemplateArgs()) {
- DeclAccessPair dap;
- if (FunctionDecl* Fn = S.ResolveSingleFunctionTemplateSpecialization(
- OvlExpr, false, &dap) ) {
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
- if (!Method->isStatic()) {
- // If the target type is a non-function type and the function
- // found is a non-static member function, pretend as if that was
- // the target, it's the only possible type to end up with.
- TargetTypeIsNonStaticMemberFunction = true;
+ if (TargetFunctionType->isFunctionType()) {
+ if (UnresolvedMemberExpr *UME = dyn_cast<UnresolvedMemberExpr>(OvlExpr))
+ if (!UME->isImplicitAccess() &&
+ !S.ResolveSingleFunctionTemplateSpecialization(UME))
+ StaticMemberFunctionFromBoundPointer = true;
+ } else if (OvlExpr->hasExplicitTemplateArgs()) {
+ DeclAccessPair dap;
+ if (FunctionDecl *Fn = S.ResolveSingleFunctionTemplateSpecialization(
+ OvlExpr, false, &dap)) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn))
+ if (!Method->isStatic()) {
+ // If the target type is a non-function type and the function found
+ // is a non-static member function, pretend as if that was the
+ // target, it's the only possible type to end up with.
+ TargetTypeIsNonStaticMemberFunction = true;
- // And skip adding the function if its not in the proper form.
- // We'll diagnose this due to an empty set of functions.
- if (!OvlExprInfo.HasFormOfMemberPointer)
- return;
- }
+ // And skip adding the function if its not in the proper form.
+ // We'll diagnose this due to an empty set of functions.
+ if (!OvlExprInfo.HasFormOfMemberPointer)
+ return;
}
- Matches.push_back(std::make_pair(dap,Fn));
- }
+ Matches.push_back(std::make_pair(dap, Fn));
}
return;
}
@@ -9536,7 +9539,7 @@
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?
@@ -9544,7 +9547,17 @@
S.Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier)
<< TargetType << OvlExpr->getSourceRange();
}
-
+
+ bool IsStaticMemberFunctionFromBoundPointer() const {
+ return StaticMemberFunctionFromBoundPointer;
+ }
+
+ void ComplainIsStaticMemberFunctionFromBoundPointer() const {
+ S.Diag(OvlExpr->getLocStart(),
+ diag::err_invalid_form_pointer_member_function)
+ << OvlExpr->getSourceRange();
+ }
+
void ComplainOfInvalidConversion() const {
S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_not_func_ptrref)
<< OvlExpr->getName() << TargetType;
@@ -9612,8 +9625,12 @@
Fn = Resolver.getMatchingFunctionDecl();
assert(Fn);
FoundResult = *Resolver.getMatchingFunctionAccessPair();
- if (Complain)
- CheckAddressOfMemberAccess(AddressOfExpr, FoundResult);
+ if (Complain) {
+ if (Resolver.IsStaticMemberFunctionFromBoundPointer())
+ Resolver.ComplainIsStaticMemberFunctionFromBoundPointer();
+ else
+ CheckAddressOfMemberAccess(AddressOfExpr, FoundResult);
+ }
}
if (pHadMultipleCandidates)
diff --git a/test/CXX/drs/dr0xx.cpp b/test/CXX/drs/dr0xx.cpp
index e002641..f8ac57f 100644
--- a/test/CXX/drs/dr0xx.cpp
+++ b/test/CXX/drs/dr0xx.cpp
@@ -659,6 +659,7 @@
// function name.
void (*p)() = &x.f;
void (*q)() = &y.f; // expected-error {{cannot create a non-constant pointer to member function}}
+ void (*r)() = y.f; // expected-error {{cannot create a non-constant pointer to member function}}
}
namespace dr62 { // dr62: yes