Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -11873,6 +11873,14 @@ } OverloadExpr *Ovl = cast(E); + /// Allow pointer to static member function. + /// GCC and MSVC both accepts this. + if (!Ovl->hasExplicitTemplateArgs()) + if (auto *UME = dyn_cast(Ovl)) + if (!UME->isImplicitAccess()) + // static member function access + return Context.OverloadTy; + if (isa(Ovl)) if (!ResolveSingleFunctionTemplateSpecialization(Ovl)) { Diag(OpLoc, diag::err_invalid_form_pointer_member_function) Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -11337,18 +11337,8 @@ S.Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier) << TargetType << OvlExpr->getSourceRange(); } - - bool IsStaticMemberFunctionFromBoundPointer() const { - return StaticMemberFunctionFromBoundPointer; - } - - void ComplainIsStaticMemberFunctionFromBoundPointer() const { - S.Diag(OvlExpr->getBeginLoc(), - diag::err_invalid_form_pointer_member_function) - << OvlExpr->getSourceRange(); - } - - void ComplainOfInvalidConversion() const { + +void ComplainOfInvalidConversion() const { S.Diag(OvlExpr->getBeginLoc(), diag::err_addr_ovl_not_func_ptrref) << OvlExpr->getName() << TargetType; } @@ -11420,10 +11410,9 @@ ResolveExceptionSpec(AddressOfExpr->getExprLoc(), FPT); FoundResult = *Resolver.getMatchingFunctionAccessPair(); if (Complain) { - if (Resolver.IsStaticMemberFunctionFromBoundPointer()) - Resolver.ComplainIsStaticMemberFunctionFromBoundPointer(); - else - CheckAddressOfMemberAccess(AddressOfExpr, FoundResult); + /// Allow pointer to static member function. + /// GCC and MSVC both accepts this. + CheckAddressOfMemberAccess(AddressOfExpr, FoundResult); } } Index: test/CXX/drs/dr0xx.cpp =================================================================== --- test/CXX/drs/dr0xx.cpp +++ test/CXX/drs/dr0xx.cpp @@ -751,8 +751,8 @@ // This is (presumably) valid, because x.f does not refer to an overloaded // 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}} + void (*q)() = &y.f; // OK + void (*r)() = y.f; // OK } namespace dr62 { // dr62: yes Index: test/CXX/drs/dr1xx.cpp =================================================================== --- test/CXX/drs/dr1xx.cpp +++ test/CXX/drs/dr1xx.cpp @@ -124,8 +124,8 @@ } namespace dr115 { // dr115: yes - template int f(T); // expected-note +{{}} - template int g(T); // expected-note +{{}} + template int f(T); // expected-note +{{}} + template int g(T); // expected-note +{{}} template int g(T, int); // expected-note +{{}} int k1 = f(&f); // expected-error {{no match}} @@ -148,16 +148,16 @@ template static int g(T, int); } s; - int k4 = f(&s.f); // expected-error {{non-constant pointer to member}} + int k4 = f(&s.f); // expected-error {{no match}} int k5 = f(&s.f); int k6 = f(&s.g); // expected-error {{non-constant pointer to member}} void i() { - (void)&s.f; // expected-error {{non-constant pointer to member}} + (void)&s.f; // expected-error {{address of overloaded function 'f' cannot be cast to type 'void'}} (void)&s.f; (void)&s.g; // expected-error {{non-constant pointer to member}} - &s.f; // expected-error {{non-constant pointer to member}} + &s.f; // expected-error {{reference to overloaded function could not be resolved}} &s.f; // expected-warning {{unused}} &s.g; // expected-error {{non-constant pointer to member}} } @@ -168,16 +168,16 @@ template int g(T, int); } t; - int k7 = f(&s.f); // expected-error {{non-constant pointer to member}} + int k7 = f(&s.f); // expected-error {{no match}} int k8 = f(&s.f); int k9 = f(&s.g); // expected-error {{non-constant pointer to member}} void j() { - (void)&s.f; // expected-error {{non-constant pointer to member}} + (void)&s.f; // expected-error {{address of overloaded function 'f' cannot be cast to type 'void'}} (void)&s.f; (void)&s.g; // expected-error {{non-constant pointer to member}} - &s.f; // expected-error {{non-constant pointer to member}} + &s.f; // expected-error {{reference to overloaded function could not be resolved}} &s.f; // expected-warning {{unused}} &s.g; // expected-error {{non-constant pointer to member}} } Index: test/CodeGenCXX/pointer-to-static-member.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/pointer-to-static-member.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 %s -fexceptions -O0 -triple x86_64-unknown-linux-gnu -emit-llvm -o - | FileCheck %s + +struct X { + static void foo(); +} x; +struct Y { + static void bar(); + static void bar(int); +} y; + +void (*ptr1)() = &x.foo; +void (*ptr2)() = &y.bar; +void (*ptr3)() = y.bar; + +struct X *xptr = &x; +void (*p1)() = &xptr->foo; + +struct Y *yptr = &y; +void (*ptr4)() = &yptr->bar; +void (*ptr5)(int) = &yptr->bar; + +// CHECK: @{{.*}}ptr1{{.*}} = global {{.+}}@[[PTR1:.+]], +// CHECK: store {{.+}}[[PTR1]],{{.*}}@{{.*}}p1 Index: test/Sema/pointer-to-static-member.cpp =================================================================== --- /dev/null +++ test/Sema/pointer-to-static-member.cpp @@ -0,0 +1,80 @@ +// RUN: %clang_cc1 %s -fexceptions -O0 -verify + +namespace member_pointers { +struct S { + template + bool f(T) { return false; } + template + static bool g(T) { return false; } + + template + bool h(T) { return false; } // expected-note 3 {{possible target for call}} + template + static bool h(int) { return false; } // expected-note 3 {{possible target for call}} +}; + +void test(S s) { + if (&S::f) + return; + if (&S::f) + return; + if (&s.f) // expected-error {{cannot create a non-constant pointer to member function}} + return; + if (&s.f) // expected-error {{cannot create a non-constant pointer to member function}} + return; + + if (&S::g) + return; + if (&S::g) + return; + if (&s.g) + return; + if (&s.g) + return; + + if (S::h<42>) // expected-warning {{address of function 'S::h<42>' will always evaluate to 'true'}} \ + // expected-note {{prefix with the address-of operator to silence this warning}} + return; + + if (S::h) // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} + return; + if (&S::h<42>) + return; + if (&S::h) + return; + if (s.h) // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} + return; + if (&s.h<42>) + return; + if (&s.h) // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} + return; + + { bool b = &S::f; } + { bool b = &S::f; } + { bool b = &s.f; } // expected-error {{cannot create a non-constant pointer to member function}} + { bool b = &s.f; } // expected-error {{cannot create a non-constant pointer to member function}} +} +} + +struct Y { + static void bar(); + static void bar(int); +} y; + +struct Y *yptr = &y; +void (*ptr4)() = &yptr->bar; +void (*ptr5)(int) = &yptr->bar; + +bool foo() { + return ptr4 == &Y::bar; // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} +} + +struct A +{ + static void f (int) {} + static void f () {}; +}; + + +A a; +void (*p) (int) = a.f;