[clang] [clang] pointer to member with qualified-id enclosed in parentheses in unevaluated context should be invalid (PR #89713)

via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 24 08:51:17 PDT 2024


https://github.com/zwuis updated https://github.com/llvm/llvm-project/pull/89713

>From f6fd1e5e5f42b3c72cb5aeaf9e6d4e91d5424bee Mon Sep 17 00:00:00 2001
From: YanzuoLiu <zwuis at outlook.com>
Date: Tue, 23 Apr 2024 14:56:12 +0800
Subject: [PATCH 1/3] Add missing check when making pointer to member

---
 clang/lib/Sema/SemaExpr.cpp                    | 11 +++++++++++
 .../CXX/expr/expr.unary/expr.unary.op/p3.cpp   | 18 +++++++++++++++++-
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 5c861467bc1023..824667fb722365 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -14644,6 +14644,17 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
             return QualType();
           }
 
+          // C++11 [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.
+          if (isa<ParenExpr>(OrigOp.get())) {
+            // `op->getEndLoc()` is the last part of the qualified-id.
+            // For example, "baz" in "foo::bar::baz".
+            Diag(op->getEndLoc(), diag::err_invalid_non_static_member_use)
+                << dcl->getDeclName() << op->getSourceRange();
+            return QualType();
+          }
+
           while (cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion())
             Ctx = Ctx->getParent();
 
diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
index 08ab0ca56fb632..73d850a6839da7 100644
--- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
+++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -fsyntax-only %s -verify 
-// expected-no-diagnostics
 
 namespace rdar10544564 {
   // Check that we don't attempt to use an overloaded operator& when
@@ -27,3 +26,20 @@ namespace rdar10544564 {
   X (Y::*func_mem_ptr1)() = &Y::memfunc1;
   X (Y::*func_mem_ptr2)() = &Y::memfunc2;
 }
+
+namespace test2 {
+  struct A {
+    int val;
+    void func() {}
+  };
+
+  void test() {
+    decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}}
+    int A::* ptr2 = &(A::val); // expected-error {{invalid use of non-static data member 'val'}}
+
+    // FIXME: Error messages in these cases are less than clear, we can do
+    // better.
+    int size = sizeof(&(A::func)); // expected-error {{call to non-static member function without an object argument}}
+    void (A::* ptr3)() = &(A::func); // expected-error {{call to non-static member function without an object argument}}
+  }
+}

>From 22b18d32d79e5dcd0390aa17c454f373e565868a Mon Sep 17 00:00:00 2001
From: YanzuoLiu <zwuis at outlook.com>
Date: Wed, 24 Apr 2024 17:21:14 +0800
Subject: [PATCH 2/3] Apply suggestion from cor3ntin

Co-authored-by: cor3ntin <corentinjabot at gmail.com>
---
 clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
index 73d850a6839da7..3e99b333d0e584 100644
--- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
+++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
@@ -27,7 +27,7 @@ namespace rdar10544564 {
   X (Y::*func_mem_ptr2)() = &Y::memfunc2;
 }
 
-namespace test2 {
+namespace GH40906 {
   struct A {
     int val;
     void func() {}

>From 81fd55780b34c92566bdfb7fc1a2cde690675d66 Mon Sep 17 00:00:00 2001
From: YanzuoLiu <zwuis at outlook.com>
Date: Wed, 24 Apr 2024 17:39:45 +0800
Subject: [PATCH 3/3] Move tests to the right place

---
 .../CXX/expr/expr.unary/expr.unary.op/p3.cpp   | 18 +-----------------
 .../CXX/expr/expr.unary/expr.unary.op/p4.cpp   | 17 +++++++++++++++++
 2 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
index 3e99b333d0e584..08ab0ca56fb632 100644
--- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
+++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only %s -verify 
+// expected-no-diagnostics
 
 namespace rdar10544564 {
   // Check that we don't attempt to use an overloaded operator& when
@@ -26,20 +27,3 @@ namespace rdar10544564 {
   X (Y::*func_mem_ptr1)() = &Y::memfunc1;
   X (Y::*func_mem_ptr2)() = &Y::memfunc2;
 }
-
-namespace GH40906 {
-  struct A {
-    int val;
-    void func() {}
-  };
-
-  void test() {
-    decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}}
-    int A::* ptr2 = &(A::val); // expected-error {{invalid use of non-static data member 'val'}}
-
-    // FIXME: Error messages in these cases are less than clear, we can do
-    // better.
-    int size = sizeof(&(A::func)); // expected-error {{call to non-static member function without an object argument}}
-    void (A::* ptr3)() = &(A::func); // expected-error {{call to non-static member function without an object argument}}
-  }
-}
diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp
index 537d676738bef8..a9efbb38859c5d 100644
--- a/clang/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp
+++ b/clang/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp
@@ -41,3 +41,20 @@ namespace test2 {
     int (A::*ptr)(int) = &(A::foo); // expected-error {{cannot create a non-constant pointer to member function}}
   }
 }
+
+namespace GH40906 {
+  struct A {
+    int val;
+    void func() {}
+  };
+
+  void test() {
+    decltype(&(A::val)) ptr1; // expected-error {{invalid use of non-static data member 'val'}}
+    int A::* ptr2 = &(A::val); // expected-error {{invalid use of non-static data member 'val'}}
+
+    // FIXME: Error messages in these cases are less than clear, we can do
+    // better.
+    int size = sizeof(&(A::func)); // expected-error {{call to non-static member function without an object argument}}
+    void (A::* ptr3)() = &(A::func); // expected-error {{call to non-static member function without an object argument}}
+  }
+}



More information about the cfe-commits mailing list