]> granicus.if.org Git - clang/commitdiff
Catch the case of trying to turn '&(X::a)' into a member pointer as well.
authorJohn McCall <rjmccall@apple.com>
Tue, 24 Aug 2010 23:26:21 +0000 (23:26 +0000)
committerJohn McCall <rjmccall@apple.com>
Tue, 24 Aug 2010 23:26:21 +0000 (23:26 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111997 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaOverload.cpp
test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp
test/CXX/expr/expr.unary/expr.unary.op/p4.cpp [new file with mode: 0644]

index 65cd183318679f347f6752c131d0fe3fe48e54dd..6dcb6b01f3d129286e72474daa749b545c240d68 100644 (file)
@@ -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<OverloadExpr*,1> 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<UnaryOperator>(Tmp)) {
+      Tmp = cast<UnaryOperator>(Tmp)->getSubExpr();
+      OvlExpr = cast<OverloadExpr>(Tmp->IgnoreParens());
+      HasFormOfMemberPointer = (Tmp == OvlExpr && OvlExpr->getQualifier());
+    } else {
+      OvlExpr = cast<OverloadExpr>(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
index 7e09bc8aef2c2e0b07b5fd4f94a206e3c05e532e..c81e4ef1b1b873d439265e2383916c63807d06d8 100644 (file)
@@ -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<typename T> void g(T);
-
-    void test() {
-      foo(&g<int>); // 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 (file)
index 0000000..170c734
--- /dev/null
@@ -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<typename T> void g(T);
+
+    void test() {
+      // FIXME: this diagnostic is terrible
+      foo(&g<int>); // expected-error {{cannot initialize a parameter of type 'void (test0::A::*)(int)' with an rvalue of type '<overloaded function 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 '<overloaded function type>'}}
+  }
+}