Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions clang/test/CXX/drs/cwg14xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,28 @@ 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.
// (_N4988_.[dcl.meaning]/2.1, [basic.scope.scope]/7,
// [basic.lookup.general]/3)
friend int f();
};
}
// Corresponds to the friend declaration,
// because it's nominable in N,
// and binds name 'f' in N.
// (_N4988_.[dcl.meaning]/3.4, [basic.scope.scope]/2.5)
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);
Expand Down
12 changes: 12 additions & 0 deletions clang/test/CXX/drs/cwg19xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@

namespace std { struct type_info; }

namespace cwg1900 { // cwg1900: 2.7
// See the test for CWG1477 for detailed analysis
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 {
Expand Down
74 changes: 74 additions & 0 deletions clang/test/CXX/drs/cwg1xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Comment on lines +586 to +588
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to try to fix this one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has that good first issue feel, so I'll refrain for now. But I'll get to all name lookup issues when I'm done with writing tests for P1787R6.

};
}
} // 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
Expand Down
72 changes: 72 additions & 0 deletions clang/test/CXX/drs/cwg3xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,78 @@ 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;

// According to _N4988_.[dcl.meaning]/3.3:
// `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() { }
// According to _N4988_.[dcl.meaning]/2.2:
// `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'}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly, it's confused by the namespaces - or more likely, the using declarations
https://compiler-explorer.com/z/oP6Er4e4j

};
}
} // 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 {
// According to _N4988_.[dcl.meaning]/2.2:
// `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 {
Expand Down
8 changes: 4 additions & 4 deletions clang/www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/138.html">138</a></td>
<td>CD6</td>
<td>Friend declaration name lookup</td>
<td class="unknown" align="center">Unknown</td>
<td class="partial" align="center">Partial</td>
</tr>
<tr id="139">
<td><a href="https://cplusplus.github.io/CWG/issues/139.html">139</a></td>
Expand Down Expand Up @@ -2363,7 +2363,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/386.html">386</a></td>
<td>CD6</td>
<td>Friend declaration of name brought in by <I>using-declaration</I></td>
<td class="unknown" align="center">Unknown</td>
<td class="none" align="center">No</td>
</tr>
<tr id="387">
<td><a href="https://cplusplus.github.io/CWG/issues/387.html">387</a></td>
Expand Down Expand Up @@ -8677,7 +8677,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/1477.html">1477</a></td>
<td>CD3</td>
<td>Definition of a <TT>friend</TT> outside its namespace</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 2.7</td>
</tr>
<tr id="1478">
<td><a href="https://cplusplus.github.io/CWG/issues/1478.html">1478</a></td>
Expand Down Expand Up @@ -11215,7 +11215,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/1900.html">1900</a></td>
<td>CD6</td>
<td>Do <TT>friend</TT> declarations count as &#8220;previous declarations&#8221;?</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 2.7</td>
</tr>
<tr class="open" id="1901">
<td><a href="https://cplusplus.github.io/CWG/issues/1901.html">1901</a></td>
Expand Down
Loading