aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaOverload.cpp55
-rw-r--r--test/CXX/over/over.over/p2-resolve-single-template-id.cpp66
2 files changed, 103 insertions, 18 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 6fa78a9a46..8125ce1086 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1058,27 +1058,33 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// 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
- = S.Context.getTypeDeclType(Method->getParent()).getTypePtr();
- FromType = S.Context.getMemberPointerType(FromType, ClassType);
- }
}
- // If the "from" expression takes the address of the overloaded
- // function, update the type of the resulting expression accordingly.
- if (FromType->getAs<FunctionType>())
- if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(From->IgnoreParens()))
- if (UnOp->getOpcode() == UO_AddrOf)
- FromType = S.Context.getPointerType(FromType);
+ // Check if the "from" expression is taking the address of an overloaded
+ // function and recompute the FromType accordingly. Take advantage of the
+ // fact that non-static member functions *must* have such an address-of
+ // expression.
+ CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn);
+ if (Method && !Method->isStatic()) {
+ assert(isa<UnaryOperator>(From->IgnoreParens()) &&
+ "Non-unary operator on non-static member address");
+ assert(cast<UnaryOperator>(From->IgnoreParens())->getOpcode()
+ == UO_AddrOf &&
+ "Non-address-of operator on non-static member address");
+ const Type *ClassType
+ = S.Context.getTypeDeclType(Method->getParent()).getTypePtr();
+ FromType = S.Context.getMemberPointerType(FromType, ClassType);
+ } else if (UnaryOperator *UnOp
+ = dyn_cast<UnaryOperator>(From->IgnoreParens())) {
+ assert(UnOp->getOpcode() == UO_AddrOf &&
+ "Non-address-of operator for overloaded function expression");
+ FromType = S.Context.getPointerType(FromType);
+ }
// Check that we've computed the proper type after overload resolution.
- assert(S.Context.hasSameType(FromType,
- S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType()));
+ assert(S.Context.hasSameType(
+ FromType,
+ S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType()));
} else {
return false;
}
@@ -7174,6 +7180,21 @@ public:
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;
+ }
+ }
+
Matches.push_back(std::make_pair(dap,Fn));
}
}
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
index 64871edcbc..f4a5e8f633 100644
--- a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
+++ b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
@@ -123,4 +123,68 @@ int main()
}
-
+namespace member_pointers {
+ struct S {
+ template <typename T> bool f(T) { return false; }
+ template <typename T> static bool g(T) { return false; }
+
+ template <typename T> bool h(T) { return false; }
+ template <int N> static bool h(int) { return false; }
+ };
+
+ void test(S s) {
+ if (S::f<char>) return; // expected-error {{call to non-static member function without an object argument}}
+ if (S::f<int>) return; // expected-error {{call to non-static member function without an object argument}}
+ if (&S::f<char>) return;
+ if (&S::f<int>) return;
+ if (s.f<char>) return; // expected-error {{contextually convertible}}
+ if (s.f<int>) return; // expected-error {{contextually convertible}}
+ if (&s.f<char>) return; // expected-error {{contextually convertible}}
+ if (&s.f<int>) return; // expected-error {{contextually convertible}}
+
+ if (S::g<char>) return;
+ if (S::g<int>) return;
+ if (&S::g<char>) return;
+ if (&S::g<int>) return;
+ if (s.g<char>) return;
+ if (s.g<int>) return;
+ if (&s.g<char>) return;
+ if (&s.g<int>) return;
+
+ if (S::h<42>) return;
+ if (S::h<int>) return; // expected-error {{contextually convertible}}
+ if (&S::h<42>) return;
+ if (&S::h<int>) return;
+ if (s.h<42>) return;
+ if (s.h<int>) return; // expected-error {{contextually convertible}}
+ if (&s.h<42>) return;
+ if (&s.h<int>) return; // expected-error {{contextually convertible}}
+
+ { bool b = S::f<char>; } // expected-error {{call to non-static member function without an object argument}}
+ { bool b = S::f<int>; } // expected-error {{call to non-static member function without an object argument}}
+ { bool b = &S::f<char>; }
+ { bool b = &S::f<int>; }
+ { bool b = s.f<char>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+ { bool b = s.f<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+ { bool b = &s.f<char>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+ { bool b = &s.f<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+
+ { bool b = S::g<char>; }
+ { bool b = S::g<int>; }
+ { bool b = &S::g<char>; }
+ { bool b = &S::g<int>; }
+ { bool b = s.g<char>; }
+ { bool b = s.g<int>; }
+ { bool b = &s.g<char>; }
+ { bool b = &s.g<int>; }
+
+ { bool b = S::h<42>; }
+ { bool b = S::h<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+ { bool b = &S::h<42>; }
+ { bool b = &S::h<int>; }
+ { bool b = s.h<42>; }
+ { bool b = s.h<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+ { bool b = &s.h<42>; }
+ { bool b = &s.h<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+ }
+}