Skip to content

Commit 10fb5d2

Browse files
authored
[clang] Add test for CWG203 "Type of address-of-member expression" (#121687)
This patch adds test for [CWG203](https://cplusplus.github.io/CWG/issues/203.html). Author was asking to change the type of pointer-to-member expression to be closer to how it's written as opposed to where the resulting member belongs to, but was turned down due to backwards compatibility concerns, so we're testing the status quo. There are a total of 6 examples in the filing, so I decided to just throw all of them into the test. I had to turn example 2 into `constexpr` test that unfortunately requires C++20. Outcomes in example 5 that Tomasz expected are not in line with implementation behavior and my reading of the Standard. I think he got confused by the fact that unlike regular pointers, pointers-to-members can be implicitly _downcasted_, but not upcasted. I left comments in the example.
1 parent df67e37 commit 10fb5d2

File tree

2 files changed

+139
-4
lines changed

2 files changed

+139
-4
lines changed

clang/test/CXX/drs/cwg2xx.cpp

Lines changed: 138 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
// RUN: %clang_cc1 -std=c++11 %s -verify=expected,since-cxx11,cxx98-11,cxx98-14,cxx98-17 -fexceptions -fcxx-exceptions -pedantic-errors
33
// RUN: %clang_cc1 -std=c++14 %s -verify=expected,since-cxx11,since-cxx14,cxx98-14,cxx98-17 -fexceptions -fcxx-exceptions -pedantic-errors
44
// RUN: %clang_cc1 -std=c++17 %s -verify=expected,since-cxx11,since-cxx14,since-cxx17,cxx98-17 -fexceptions -fcxx-exceptions -pedantic-errors
5-
// RUN: %clang_cc1 -std=c++20 %s -verify=expected,since-cxx11,since-cxx14,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors
6-
// RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11,since-cxx14,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors
7-
// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11,since-cxx14,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors
5+
// RUN: %clang_cc1 -std=c++20 %s -verify=expected,since-cxx11,since-cxx14,since-cxx17,since-cxx20 -fexceptions -fcxx-exceptions -pedantic-errors
6+
// RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11,since-cxx14,since-cxx17,since-cxx20 -fexceptions -fcxx-exceptions -pedantic-errors
7+
// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11,since-cxx14,since-cxx17,since-cxx20 -fexceptions -fcxx-exceptions -pedantic-errors
88

99
// FIXME: diagnostic above is emitted only on Windows platforms
1010
// PR13819 -- __SIZE_TYPE__ is incompatible.
@@ -42,6 +42,141 @@ namespace cwg202 { // cwg202: 3.1
4242
template struct X<f>;
4343
} // namespace cwg202
4444

45+
namespace cwg203 { // cwg203: 3.0
46+
namespace ex1 {
47+
struct B {
48+
int i;
49+
};
50+
struct D1 : B {};
51+
struct D2 : B {};
52+
53+
int(D1::*pmD1) = &D2::i;
54+
} // namespace ex1
55+
56+
#if __cplusplus >= 202002L
57+
namespace ex2 {
58+
struct A {
59+
int i;
60+
virtual void f() = 0; // #cwg203-ex2-A-f
61+
};
62+
63+
struct B : A {
64+
int j;
65+
constexpr B() : j(5) {}
66+
virtual void f();
67+
};
68+
69+
struct C : B {
70+
constexpr C() { j = 10; }
71+
};
72+
73+
template <class T>
74+
constexpr int DefaultValue(int(T::*m)) {
75+
return T().*m;
76+
// since-cxx20-error@-1 {{allocating an object of abstract class type 'cwg203::ex2::A'}}
77+
// since-cxx20-note@#cwg203-ex2-a {{in instantiation of function template specialization 'cwg203::ex2::DefaultValue<cwg203::ex2::A>' requested here}}
78+
// since-cxx20-note@#cwg203-ex2-A-f {{unimplemented pure virtual method 'f' in 'A'}}
79+
} // #cwg203-ex2-DefaultValue
80+
81+
int a = DefaultValue(&B::i); // #cwg203-ex2-a
82+
static_assert(DefaultValue(&C::j) == 5, "");
83+
} // namespace ex2
84+
#endif
85+
86+
namespace ex3 {
87+
class Base {
88+
public:
89+
int func() const;
90+
};
91+
92+
class Derived : public Base {};
93+
94+
template <class T> class Templ { // #cwg203-ex3-Templ
95+
public:
96+
template <class S> Templ(S (T::*ptmf)() const); // #cwg203-ex3-Templ-ctor
97+
};
98+
99+
void foo() { Templ<Derived> x(&Derived::func); }
100+
// expected-error@-1 {{no matching constructor for initialization of 'Templ<Derived>'}}
101+
// expected-note@#cwg203-ex3-Templ {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int (cwg203::ex3::Base::*)() const' to 'const Templ<Derived>' for 1st argument}}
102+
// since-cxx11-note@#cwg203-ex3-Templ {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int (cwg203::ex3::Base::*)() const' to 'Templ<Derived>' for 1st argument}}
103+
// expected-note@#cwg203-ex3-Templ-ctor {{candidate template ignored: could not match 'cwg203::ex3::Derived' against 'cwg203::ex3::Base'}}
104+
} // namespace ex3
105+
106+
namespace ex4 {
107+
struct Very_base {
108+
int a;
109+
};
110+
struct Base1 : Very_base {};
111+
struct Base2 : Very_base {};
112+
struct Derived : Base1, Base2 {
113+
};
114+
115+
int f() {
116+
Derived d;
117+
// FIXME: in the diagnostic below, Very_base is fully qualified, but Derived is not
118+
int Derived::*a_ptr = &Derived::Base1::a;
119+
/* expected-error@-1
120+
{{ambiguous conversion from pointer to member of base class 'cwg203::ex4::Very_base' to pointer to member of derived class 'Derived':
121+
struct cwg203::ex4::Derived -> Base1 -> Very_base
122+
struct cwg203::ex4::Derived -> Base2 -> Very_base}}*/
123+
}
124+
} // namespace ex4
125+
126+
namespace ex5 {
127+
struct Base {
128+
int a;
129+
};
130+
struct Derived : Base {
131+
int b;
132+
};
133+
134+
template <typename Class, typename Member_type, Member_type Base::*ptr>
135+
Member_type get(Class &c) {
136+
return c.*ptr;
137+
}
138+
139+
void call(int (*f)(Derived &)); // #cwg203-ex5-call
140+
141+
int f() {
142+
// ill-formed, contrary to Core issue filing:
143+
// `&Derived::b` yields `int Derived::*`, which can't initialize NTTP of type `int Base::*`,
144+
// because (implicit) pointer-to-member conversion doesn't upcast.
145+
call(&get<Derived, int, &Derived::b>);
146+
// expected-error@-1 {{no matching function for call to 'call'}}
147+
// expected-note@#cwg203-ex5-call {{candidate function not viable: no overload of 'get' matching 'int (*)(Derived &)' for 1st argument}}
148+
149+
// well-formed, contrary to Core issue filing:
150+
// `&Derived::a` yields `int Base::*`,
151+
// which can initialize NTTP of type `int Base::*`.
152+
call(&get<Derived, int, &Derived::a>);
153+
154+
call(&get<Base, int, &Derived::a>);
155+
// expected-error@-1 {{no matching function for call to 'call'}}
156+
// expected-note@#cwg203-ex5-call {{candidate function not viable: no overload of 'get' matching 'int (*)(Derived &)' for 1st argument}}
157+
}
158+
} // namespace ex5
159+
160+
namespace ex6 {
161+
struct Base {
162+
int a;
163+
};
164+
struct Derived : private Base { // #cwg203-ex6-Derived
165+
public:
166+
using Base::a; // make `a` accessible
167+
};
168+
169+
int f() {
170+
Derived d;
171+
int b = d.a;
172+
// FIXME: in the diagnostic below, Base is fully qualified, but Derived is not
173+
int Derived::*ptr = &Derived::a;
174+
// expected-error@-1 {{cannot cast private base class 'cwg203::ex6::Base' to 'Derived'}}
175+
// expected-note@#cwg203-ex6-Derived {{declared private here}}
176+
}
177+
} // namespace ex6
178+
} // namespace cwg203
179+
45180
// cwg204: sup 820
46181

47182
namespace cwg206 { // cwg206: 2.7

clang/www/cxx_dr_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1263,7 +1263,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
12631263
<td><a href="https://cplusplus.github.io/CWG/issues/203.html">203</a></td>
12641264
<td>NAD</td>
12651265
<td>Type of address-of-member expression</td>
1266-
<td class="unknown" align="center">Unknown</td>
1266+
<td class="full" align="center">Clang 3.0</td>
12671267
</tr>
12681268
<tr id="204">
12691269
<td><a href="https://cplusplus.github.io/CWG/issues/204.html">204</a></td>

0 commit comments

Comments
 (0)