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.vladis...@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@-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@-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@-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@-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@-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.vladis...@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@-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 { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits