From: John McCall Date: Tue, 24 Aug 2010 23:26:21 +0000 (+0000) Subject: Catch the case of trying to turn '&(X::a)' into a member pointer as well. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c988fab9860e83f25ef51101fef162b49380582b;p=clang Catch the case of trying to turn '&(X::a)' into a member pointer as well. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111997 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 65cd183318..6dcb6b01f3 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -6216,9 +6216,24 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // C++ [over.over]p1: // [...] The overloaded function name can be preceded by the & // operator. - llvm::PointerIntPair Ovl = OverloadExpr::find(From); - OverloadExpr *OvlExpr = Ovl.getPointer(); - + // 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. + bool HasFormOfMemberPointer = false; + OverloadExpr *OvlExpr; + { + Expr *Tmp = From->IgnoreParens(); + if (isa(Tmp)) { + Tmp = cast(Tmp)->getSubExpr(); + OvlExpr = cast(Tmp->IgnoreParens()); + HasFormOfMemberPointer = (Tmp == OvlExpr && OvlExpr->getQualifier()); + } else { + OvlExpr = cast(Tmp); + } + } + // We expect a pointer or reference to function, or a function pointer. FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType(); if (!FunctionType->isFunctionType()) { @@ -6230,13 +6245,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } // 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: - // 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. - // We don't diagnose the parentheses here, though. Should we? - if (IsMember && !(Ovl.getInt() && OvlExpr->getQualifier())) { + // member, don't try to convert it to a pointer-to-member type. + if (IsMember && !HasFormOfMemberPointer) { if (!Complain) return 0; // TODO: Should we condition this on whether any functions might diff --git a/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp b/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp index 7e09bc8aef..c81e4ef1b1 100644 --- a/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp +++ b/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp @@ -91,28 +91,3 @@ namespace test2 { a.test3(); // expected-note {{in instantiation}} } } - -namespace test3 { - struct A { - void foo(void (A::*)(int)); // expected-note {{passing argument to parameter here}} - template void g(T); - - void test() { - foo(&g); // expected-error {{cannot initialize a parameter}} - } - }; -} - -// This should succeed. -namespace test4 { - struct A { - static void f(void (A::*)()); - static void f(void (*)(int)); - void g(); - static void g(int); - - void test() { - f(&g); - } - }; -} diff --git a/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp b/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp new file mode 100644 index 0000000000..170c734fd3 --- /dev/null +++ b/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// rdar://problem/8347416 +namespace test0 { + struct A { + void foo(void (A::*)(int)); // expected-note {{passing argument to parameter here}} + template void g(T); + + void test() { + // FIXME: this diagnostic is terrible + foo(&g); // expected-error {{cannot initialize a parameter of type 'void (test0::A::*)(int)' with an rvalue of type ''}} + } + }; +} + +// This should succeed. +namespace test1 { + struct A { + static void f(void (A::*)()); + static void f(void (*)(int)); + void g(); + static void g(int); + + void test() { + f(&g); + } + }; +} + +// Also rdar://problem/8347416 +namespace test2 { + struct A { + static int foo(short); + static int foo(float); + int foo(int); + int foo(double); + + void test(); + }; + + void A::test() { + // FIXME: This diagnostic is terrible. + int (A::*ptr)(int) = &(A::foo); // expected-error {{cannot initialize a variable of type 'int (test2::A::*)(int)' with an rvalue of type ''}} + } +}