conditional-expr.cpp
12.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -Wsign-conversion %s
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++17 -Wsign-conversion %s
// C++ rules for ?: are a lot stricter than C rules, and have to take into
// account more conversion options.
// This test runs in C++11 mode for the contextual conversion of the condition.
struct ToBool { explicit operator bool(); };
struct B;
struct A {
A();
A(const B&); // expected-note 2 {{candidate constructor}}
};
struct B { operator A() const; }; // expected-note 2 {{candidate function}}
struct I { operator int(); };
struct J { operator I(); };
struct K { operator double(); };
typedef void (*vfn)();
struct F { operator vfn(); };
struct G { operator vfn(); };
struct Base {
int trick();
A trick() const;
void fn1();
};
struct Derived : Base {
void fn2();
};
struct Convertible { operator Base&(); };
struct Priv : private Base {}; // expected-note 4 {{declared private here}}
struct Mid : Base {};
struct Fin : Mid, Derived {};
typedef void (Derived::*DFnPtr)();
struct ToMemPtr { operator DFnPtr(); };
struct BadDerived;
struct BadBase { operator BadDerived&(); };
struct BadDerived : BadBase {};
struct Fields {
int i1, i2, b1 : 3, b2 : 3;
};
struct MixedFields {
int i;
volatile int vi;
const int ci;
const volatile int cvi;
};
struct MixedFieldsDerived : MixedFields {
};
enum Enum { EVal };
struct Ambig {
operator short(); // expected-note 2 {{candidate function}}
operator signed char(); // expected-note 2 {{candidate function}}
};
struct Abstract {
virtual ~Abstract() = 0; // expected-note {{unimplemented pure virtual method '~Abstract' in 'Abstract'}}
};
struct Derived1: Abstract {
};
struct Derived2: Abstract {
};
void test()
{
// This function tests C++0x 5.16
// p1 (contextually convert to bool)
int i1 = ToBool() ? 0 : 1;
// p2 (one or both void, and throwing)
Fields flds;
i1 ? throw 0 : throw 1;
i1 ? test() : throw 1;
i1 ? throw 0 : test();
i1 ? test() : test();
i1 = i1 ? throw 0 : 0;
i1 = i1 ? 0 : throw 0;
i1 = i1 ? (throw 0) : 0;
i1 = i1 ? 0 : (throw 0);
i1 ? 0 : test(); // expected-error {{right operand to ? is void, but left operand is of type 'int'}}
i1 ? test() : 0; // expected-error {{left operand to ? is void, but right operand is of type 'int'}}
(i1 ? throw 0 : i1) = 0;
(i1 ? i1 : throw 0) = 0;
(i1 ? (throw 0) : i1) = 0;
(i1 ? i1 : (throw 0)) = 0;
(i1 ? (void)(throw 0) : i1) = 0; // expected-error {{left operand to ? is void, but right operand is of type 'int'}}
(i1 ? i1 : (void)(throw 0)) = 0; // expected-error {{right operand to ? is void, but left operand is of type 'int'}}
int &throwRef1 = (i1 ? flds.i1 : throw 0);
int &throwRef2 = (i1 ? throw 0 : flds.i1);
int &throwRef3 = (i1 ? flds.b1 : throw 0); // expected-error {{non-const reference cannot bind to bit-field}}
int &throwRef4 = (i1 ? throw 0 : flds.b1); // expected-error {{non-const reference cannot bind to bit-field}}
// p3 (one or both class type, convert to each other)
// b1 (lvalues)
Base base;
Derived derived;
Convertible conv;
Base &bar1 = i1 ? base : derived;
Base &bar2 = i1 ? derived : base;
Base &bar3 = i1 ? base : conv;
Base &bar4 = i1 ? conv : base;
// these are ambiguous
BadBase bb;
BadDerived bd;
(void)(i1 ? bb : bd); // expected-error {{conditional expression is ambiguous; 'BadBase' can be converted to 'BadDerived' and vice versa}}
(void)(i1 ? bd : bb); // expected-error {{conditional expression is ambiguous}}
// curiously enough (and a defect?), these are not
// for rvalues, hierarchy takes precedence over other conversions
(void)(i1 ? BadBase() : BadDerived());
(void)(i1 ? BadDerived() : BadBase());
// b2.1 (hierarchy stuff)
extern const Base constret();
extern const Derived constder();
// should use const overload
A a1((i1 ? constret() : Base()).trick());
A a2((i1 ? Base() : constret()).trick());
A a3((i1 ? constret() : Derived()).trick());
A a4((i1 ? Derived() : constret()).trick());
// should use non-const overload
i1 = (i1 ? Base() : Base()).trick();
i1 = (i1 ? Base() : Base()).trick();
i1 = (i1 ? Base() : Derived()).trick();
i1 = (i1 ? Derived() : Base()).trick();
// should fail: const lost
(void)(i1 ? Base() : constder()); // expected-error {{incompatible operand types ('Base' and 'const Derived')}}
(void)(i1 ? constder() : Base()); // expected-error {{incompatible operand types ('const Derived' and 'Base')}}
Priv priv;
Fin fin;
(void)(i1 ? Base() : Priv()); // expected-error{{private base class}}
(void)(i1 ? Priv() : Base()); // expected-error{{private base class}}
(void)(i1 ? Base() : Fin()); // expected-error{{ambiguous conversion from derived class 'Fin' to base class 'Base':}}
(void)(i1 ? Fin() : Base()); // expected-error{{ambiguous conversion from derived class 'Fin' to base class 'Base':}}
(void)(i1 ? base : priv); // expected-error {{private base class}}
(void)(i1 ? priv : base); // expected-error {{private base class}}
(void)(i1 ? base : fin); // expected-error {{ambiguous conversion from derived class 'Fin' to base class 'Base':}}
(void)(i1 ? fin : base); // expected-error {{ambiguous conversion from derived class 'Fin' to base class 'Base':}}
// b2.2 (non-hierarchy)
i1 = i1 ? I() : i1;
i1 = i1 ? i1 : I();
I i2(i1 ? I() : J());
I i3(i1 ? J() : I());
// "the type [it] would have if E2 were converted to an rvalue"
vfn pfn = i1 ? F() : test;
pfn = i1 ? test : F();
(void)(i1 ? A() : B()); // expected-error {{conversion from 'B' to 'A' is ambiguous}}
(void)(i1 ? B() : A()); // expected-error {{conversion from 'B' to 'A' is ambiguous}}
(void)(i1 ? 1 : Ambig()); // expected-error {{conversion from 'Ambig' to 'int' is ambiguous}}
(void)(i1 ? Ambig() : 1); // expected-error {{conversion from 'Ambig' to 'int' is ambiguous}}
// By the way, this isn't an lvalue:
&(i1 ? i1 : i2); // expected-error {{cannot take the address of an rvalue}}
// p4 (lvalue, same type)
int &ir1 = i1 ? flds.i1 : flds.i2;
(i1 ? flds.b1 : flds.i2) = 0;
(i1 ? flds.i1 : flds.b2) = 0;
(i1 ? flds.b1 : flds.b2) = 0;
// p5 (conversion to built-in types)
// GCC 4.3 fails these
double d1 = i1 ? I() : K();
pfn = i1 ? F() : G();
DFnPtr pfm;
pfm = i1 ? DFnPtr() : &Base::fn1;
pfm = i1 ? &Base::fn1 : DFnPtr();
// p6 (final conversions)
i1 = i1 ? i1 : ir1;
int *pi1 = i1 ? &i1 : 0;
pi1 = i1 ? 0 : &i1;
i1 = i1 ? i1 : EVal;
i1 = i1 ? EVal : i1;
d1 = i1 ? 'c' : 4.0;
d1 = i1 ? 4.0 : 'c';
Base *pb = i1 ? (Base*)0 : (Derived*)0;
pb = i1 ? (Derived*)0 : (Base*)0;
pfm = i1 ? &Base::fn1 : &Derived::fn2;
pfm = i1 ? &Derived::fn2 : &Base::fn1;
pfm = i1 ? &Derived::fn2 : 0;
pfm = i1 ? 0 : &Derived::fn2;
const int (MixedFieldsDerived::*mp1) =
i1 ? &MixedFields::ci : &MixedFieldsDerived::i;
const volatile int (MixedFields::*mp2) =
i1 ? &MixedFields::ci : &MixedFields::cvi;
(void)(i1 ? &MixedFields::ci : &MixedFields::vi);
// Conversion of primitives does not result in an lvalue.
&(i1 ? i1 : d1); // expected-error {{cannot take the address of an rvalue}}
(void)&(i1 ? flds.b1 : flds.i1); // expected-error {{address of bit-field requested}}
(void)&(i1 ? flds.i1 : flds.b1); // expected-error {{address of bit-field requested}}
unsigned long test0 = 5;
test0 = test0 ? (long) test0 : test0; // expected-warning {{operand of ? changes signedness: 'long' to 'unsigned long'}}
test0 = test0 ? (int) test0 : test0; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
test0 = test0 ? (short) test0 : test0; // expected-warning {{operand of ? changes signedness: 'short' to 'unsigned long'}}
test0 = test0 ? test0 : (long) test0; // expected-warning {{operand of ? changes signedness: 'long' to 'unsigned long'}}
test0 = test0 ? test0 : (int) test0; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
test0 = test0 ? test0 : (short) test0; // expected-warning {{operand of ? changes signedness: 'short' to 'unsigned long'}}
test0 = test0 ? test0 : (long) 10;
test0 = test0 ? test0 : (int) 10;
test0 = test0 ? test0 : (short) 10;
test0 = test0 ? (long) 10 : test0;
test0 = test0 ? (int) 10 : test0;
test0 = test0 ? (short) 10 : test0;
int test1;
test0 = test0 ? EVal : test0;
test1 = test0 ? EVal : (int) test0;
test0 = test0 ? EVal : test1; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
test0 = test0 ? test1 : EVal; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
test1 = test0 ? EVal : (int) test0;
test1 = test0 ? (int) test0 : EVal;
// Note the thing that this does not test: since DR446, various situations
// *must* create a separate temporary copy of class objects. This can only
// be properly tested at runtime, though.
const Abstract &abstract1 = true ? static_cast<const Abstract&>(Derived1()) : Derived2(); // expected-error {{allocating an object of abstract class type 'const Abstract'}}
const Abstract &abstract2 = true ? static_cast<const Abstract&>(Derived1()) : throw 3;
}
namespace PR6595 {
struct OtherString {
OtherString();
OtherString(const char*);
};
struct String {
String(const char *);
String(const OtherString&);
operator const char*() const;
};
void f(bool Cond, String S, OtherString OS) {
(void)(Cond? S : "");
(void)(Cond? "" : S);
const char a[1] = {'a'};
(void)(Cond? S : a);
(void)(Cond? a : S);
(void)(Cond? OS : S);
}
}
namespace PR6757 {
struct Foo1 {
Foo1();
Foo1(const Foo1&);
};
struct Foo2 { };
struct Foo3 {
Foo3(); // expected-note{{requires 0 arguments}}
Foo3(Foo3&); // expected-note{{would lose const qualifier}}
};
struct Bar {
operator const Foo1&() const;
operator const Foo2&() const;
operator const Foo3&() const;
};
void f() {
(void)(true ? Bar() : Foo1()); // okay
(void)(true ? Bar() : Foo2()); // okay
(void)(true ? Bar() : Foo3()); // expected-error{{no viable constructor copying temporary}}
}
}
// Reduced from selfhost.
namespace test1 {
struct A {
enum Foo {
fa, fb, fc, fd, fe, ff
};
Foo x();
};
void foo(int);
void test(A *a) {
foo(a ? a->x() : 0);
}
}
namespace rdar7998817 {
class X {
X(X&); // expected-note{{declared private here}}
struct ref { };
public:
X();
X(ref);
operator ref();
};
void f(bool B) {
X x;
(void)(B? x // expected-error{{calling a private constructor of class 'rdar7998817::X'}}
: X());
}
}
namespace PR7598 {
enum Enum {
v = 1,
};
const Enum g() {
return v;
}
const volatile Enum g2() {
return v;
}
void f() {
const Enum v2 = v;
Enum e = false ? g() : v;
Enum e2 = false ? v2 : v;
Enum e3 = false ? g2() : v;
}
}
namespace PR9236 {
#define NULL 0L
void f() {
int i;
(void)(true ? A() : NULL); // expected-error{{non-pointer operand type 'A' incompatible with NULL}}
(void)(true ? NULL : A()); // expected-error{{non-pointer operand type 'A' incompatible with NULL}}
(void)(true ? 0 : A()); // expected-error{{incompatible operand types}}
(void)(true ? nullptr : A()); // expected-error{{non-pointer operand type 'A' incompatible with nullptr}}
(void)(true ? nullptr : i); // expected-error{{non-pointer operand type 'int' incompatible with nullptr}}
(void)(true ? __null : A()); // expected-error{{non-pointer operand type 'A' incompatible with NULL}}
(void)(true ? (void*)0 : A()); // expected-error{{incompatible operand types}}
}
}
namespace DR587 {
template<typename T>
const T *f(bool b) {
static T t1 = T();
static const T t2 = T();
return &(b ? t1 : t2);
}
struct S {};
template const int *f(bool);
template const S *f(bool);
extern bool b;
int i = 0;
const int ci = 0;
volatile int vi = 0;
const volatile int cvi = 0;
const int &cir = b ? i : ci;
volatile int &vir = b ? vi : i;
const volatile int &cvir1 = b ? ci : cvi;
const volatile int &cvir2 = b ? cvi : vi;
const volatile int &cvir3 = b ? ci : vi; // expected-error{{volatile lvalue reference to type 'const volatile int' cannot bind to a temporary of type 'int'}}
}
namespace PR17052 {
struct X {
int i_;
bool b_;
int &test() { return b_ ? i_ : throw 1; }
};
}
namespace PR26448 {
struct Base {};
struct Derived : Base {};
Base b;
Derived d;
typedef decltype(true ? static_cast<Base&&>(b) : static_cast<Derived&&>(d)) x;
typedef Base &&x;
}
namespace lifetime_extension {
struct A {};
struct B : A { B(); ~B(); };
struct C : A { C(); ~C(); };
void f(bool b) {
A &&r = b ? static_cast<A&&>(B()) : static_cast<A&&>(C());
}
struct D { A &&a; };
void f_indirect(bool b) {
D d = b ? D{B()} : D{C()};
}
}