[clang] [clang] Add tests for CWG issues about friend declaration matching (PR #106117)

Vlad Serebrennikov via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 26 14:21:03 PDT 2024


https://github.com/Endilll updated https://github.com/llvm/llvm-project/pull/106117

>From 65307bd2f5f8ca5c6aaa24335c77a63280d668e3 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Mon, 26 Aug 2024 20:45:31 +0300
Subject: [PATCH 1/2] [clang] Add tests for CWG issues about friend declaration
 matching

---
 clang/test/CXX/drs/cwg14xx.cpp | 19 +++++++++
 clang/test/CXX/drs/cwg1xx.cpp  | 74 ++++++++++++++++++++++++++++++++++
 clang/test/CXX/drs/cwg3xx.cpp  | 69 +++++++++++++++++++++++++++++++
 3 files changed, 162 insertions(+)

diff --git a/clang/test/CXX/drs/cwg14xx.cpp b/clang/test/CXX/drs/cwg14xx.cpp
index a23ac744436331..1240c416451b8f 100644
--- a/clang/test/CXX/drs/cwg14xx.cpp
+++ b/clang/test/CXX/drs/cwg14xx.cpp
@@ -603,6 +603,25 @@ namespace cwg1467 {  // cwg1467: 3.7 c++11
 #endif
 } // cwg1467
 
+namespace cwg1477 { // cwg1477: 2.7
+namespace N {
+struct A {
+  // Name "f" is not bound in N,
+  // so single searches of 'f' in N won't find it,
+  // but the targets scope of this declaration is N,
+  // making it nominable in N.
+  friend int f();
+};
+}
+// Corresponds to the friend declaration,
+// because it's nominable in N,
+// and binds name 'f' in N.
+int N::f() { return 0; }
+// Name 'f' is bound in N,
+// so the search performed by qualified lookup finds it.
+int i = N::f();
+} // namespace cwg1477
+
 namespace cwg1479 { // cwg1479: 3.1
 #if __cplusplus >= 201103L
   int operator"" _a(const char*, std::size_t = 0);
diff --git a/clang/test/CXX/drs/cwg1xx.cpp b/clang/test/CXX/drs/cwg1xx.cpp
index e7dddd1ea9278f..d6ee0844458b1d 100644
--- a/clang/test/CXX/drs/cwg1xx.cpp
+++ b/clang/test/CXX/drs/cwg1xx.cpp
@@ -568,6 +568,80 @@ namespace cwg137 { // cwg137: yes
   const volatile int *cvqcv = static_cast<const volatile int*>(cvp);
 }
 
+namespace cwg138 { // cwg138: partial
+namespace example1 {
+void foo(); // #cwg138-ex1-foo
+namespace A {
+  using example1::foo; // #cwg138-ex1-using
+  class X {
+    static const int i = 10;
+    // This friend declaration is using neither qualified-id nor template-id,
+    // so name 'foo' is not looked up, which means the using-declaration has no effect.
+    // Target scope of this declaration is A, so this is grating friendship to
+    // (hypothetical) A::foo instead of 'example1::foo' using declaration refers to.
+    // A::foo corresponds to example1::foo named by the using declaration,
+    // and since A::foo is a different entity, they potentially conflict.
+    // FIXME: This is ill-formed, but not for the reason diagnostic says.
+    friend void foo();
+    // expected-error at -1 {{cannot befriend target of using declaration}}
+    //   expected-note@#cwg138-ex1-foo {{target of using declaration}}
+    //   expected-note@#cwg138-ex1-using {{using declaration}}
+  };
+}
+} // namespace example1
+
+namespace example2 {
+void f();
+void g();
+class B {
+  void g();
+};
+class A : public B {
+  static const int i = 10;
+  void f();
+  // Both friend declaration are not using qualified-ids or template-ids,
+  // so 'f' and 'g' are not looked up, which means that presence of A::f
+  // and base B have no effect.
+  // Both target scope of namespace 'example2', and grant friendship to
+  // example2::f and example2::g respectively.
+  friend void f();
+  friend void g();
+};
+void f() {
+  int i2 = A::i;
+}
+void g() {
+  int i3 = A::i;
+}
+} // namespace example2
+
+namespace example3 {
+struct Base {
+private:
+  static const int i = 10; // #cwg138-ex3-Base-i
+  
+public:
+  struct Data;
+  // Elaborated type specifier is not the sole constituent of declaration,
+  // so 'Data' undergoes unqualified type-only lookup, which finds Base::Data.
+  friend class Data;
+
+  struct Data {
+    void f() {
+      int i2 = Base::i;
+    }
+  };
+};
+struct Data {
+  void f() {  
+    int i2 = Base::i;
+    // expected-error at -1 {{'i' is a private member of 'cwg138::example3::Base'}}
+    //   expected-note@#cwg138-ex3-Base-i {{declared private here}}
+  }
+};
+} // namespace example3
+} // namespace cwg138
+
 namespace cwg139 { // cwg139: yes
   namespace example1 {
     typedef int f; // #cwg139-typedef-f
diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp
index a10ed95941ba4a..44bf974ef66649 100644
--- a/clang/test/CXX/drs/cwg3xx.cpp
+++ b/clang/test/CXX/drs/cwg3xx.cpp
@@ -1369,6 +1369,75 @@ namespace cwg385 { // cwg385: 2.8
   //   expected-note@#cwg385-n {{member is declared here}}
 }
 
+namespace cwg386 { // cwg386: no
+namespace example1 {
+namespace N1 {
+// Binds name 'f' in N1. Target scope is N1.
+template<typename T> void f( T* x ) {
+  // ... other stuff ...
+  delete x;
+}
+}
+
+namespace N2 {
+// Bind name 'f' in N2. When a single search find this declaration,
+// it's replaced with N1::f declaration.
+using N1::f;
+
+// `f<int>` is not a qualified-id, so its target scope is N2.
+// `f<int>` is a template-id, so 'f' undergoes (unqualified) lookup.
+// Search performed by unqualified lookup finds N1::f via using-declaration,
+// but this result is not considered, because it's not nominable in N2,
+// which is because its target scope is N1.
+// So unqualified lookup doesn't find anything, making this declaration ill-formed.
+template<> void f<int>( int* );
+// expected-error at -1 {{no function template matches function template specialization 'f'}}
+
+class Test {
+  ~Test() { }
+  // `f<>` is a template-id and not a template declaration,
+  // so its terminal name 'f' undergoes (unqualified) lookup.
+  // Search in N2 performed by unqualified lookup finds
+  // (single) N1::f declaration via using-declaration.
+  // N1::f is replaced with N1::f<> specialization after deduction,
+  // and this is the result of the unqualified lookup.
+  // This friend declaration correspond to the result of the lookup.
+  // All lookup results target the same scope, which is N1,
+  // so target scope of this friend declaration is also N1.
+  // FIXME: This is well-formed.
+  friend void f<>( Test* x );
+  // expected-error at -1 {{no function template matches function template specialization 'f'}}
+};
+}
+} // namespace example1
+
+namespace example2 {
+namespace N1 {
+// Binds name 'f' in N1. Target scope is N1.
+void f(); // #cwg386-ex2-N1-f
+}
+
+namespace N2 {
+// Bind name 'f' in N2. When a single search finds this declaration,
+// it's replaced with N1::f declaration.
+using N1::f; // #cwg386-ex2-using
+class A {
+  // `N2::f` is a qualified-id, so its terminal name 'f' undergoes (qualified) lookup.
+  // Search in N2 performed by qualified lookup finds N1::f via using-declaration,
+  // which is the (only) result of qualified lookup.
+  // This friend declaration corresponds to the result of the lookup.
+  // All lookup results target the same scope, which is N1,
+  // so target scope of this friend declaration is also N1.
+  // FIXME: This is well-formed.
+  friend void N2::f();
+  // expected-error at -1 {{cannot befriend target of using declaration}}
+  //   expected-note@#cwg386-ex2-N1-f {{target of using declaration}}
+  //   expected-note@#cwg386-ex2-using {{using declaration}}
+};
+}
+} // namespace example2
+} // namespace cwg386
+
 namespace cwg387 { // cwg387: 2.8
   namespace old {
     template<typename T> class number {

>From affb324d70a8261e412514a7eb5d5351f56386c7 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Tue, 27 Aug 2024 00:20:30 +0300
Subject: [PATCH 2/2] Add test for CWG1900

---
 clang/test/CXX/drs/cwg19xx.cpp | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/clang/test/CXX/drs/cwg19xx.cpp b/clang/test/CXX/drs/cwg19xx.cpp
index 762787a4368e62..b8fb6e1745a550 100644
--- a/clang/test/CXX/drs/cwg19xx.cpp
+++ b/clang/test/CXX/drs/cwg19xx.cpp
@@ -8,6 +8,17 @@
 
 namespace std { struct type_info; }
 
+namespace cwg1900 { // cwg1900: 2.7
+namespace N {
+struct A {
+  friend int f();
+};
+}
+int N::f() { return 0; }
+int N::g() { return 0; } 
+// expected-error at -1 {{out-of-line definition of 'g' does not match any declaration in namespace 'cwg1900::N'}}
+} // namespace cwg1900
+
 namespace cwg1902 { // cwg1902: 3.7
   struct A {};
   struct B {



More information about the cfe-commits mailing list