Clang Project

clang_source_code/test/SemaCXX/diagnose_if.cpp
1// RUN: %clang_cc1 %s -verify -fno-builtin -std=c++14
2
3#define _diagnose_if(...) __attribute__((diagnose_if(__VA_ARGS__)))
4
5using size_t = decltype(sizeof(int));
6
7namespace type_dependent {
8template <typename T>
9void neverok() _diagnose_if(!T(), "oh no", "error") {} // expected-note 4{{from 'diagnose_if'}}
10
11template <typename T>
12void alwaysok() _diagnose_if(T(), "oh no", "error") {}
13
14template <typename T>
15void alwayswarn() _diagnose_if(!T(), "oh no", "warning") {} // expected-note 4{{from 'diagnose_if'}}
16
17template <typename T>
18void neverwarn() _diagnose_if(T(), "oh no", "warning") {}
19
20void runAll() {
21  alwaysok<int>();
22  alwaysok<int>();
23
24  {
25    void (*pok)() = alwaysok<int>;
26    pok = &alwaysok<int>;
27  }
28
29  neverok<int>(); // expected-error{{oh no}}
30  neverok<short>(); // expected-error{{oh no}}
31
32  {
33    void (*pok)() = neverok<int>; // expected-error{{oh no}}
34  }
35  {
36    void (*pok)();
37    pok = &neverok<int>; // expected-error{{oh no}}
38  }
39
40  alwayswarn<int>(); // expected-warning{{oh no}}
41  alwayswarn<short>(); // expected-warning{{oh no}}
42  {
43    void (*pok)() = alwayswarn<int>; // expected-warning{{oh no}}
44    pok = &alwayswarn<int>; // expected-warning{{oh no}}
45  }
46
47  neverwarn<int>();
48  neverwarn<short>();
49  {
50    void (*pok)() = neverwarn<int>;
51    pok = &neverwarn<int>;
52  }
53}
54
55template <typename T>
56void errorIf(T a) _diagnose_if(T() != a, "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
57
58template <typename T>
59void warnIf(T a) _diagnose_if(T() != a, "oh no", "warning") {} // expected-note{{from 'diagnose_if'}}
60
61void runIf() {
62  errorIf(0);
63  errorIf(1); // expected-error{{oh no}}
64
65  warnIf(0);
66  warnIf(1); // expected-warning{{oh no}}
67}
68}
69
70namespace value_dependent {
71template <int N>
72void neverok() _diagnose_if(N == 0 || N != 0, "oh no", "error") {} // expected-note 4{{from 'diagnose_if'}}
73
74template <int N>
75void alwaysok() _diagnose_if(N == 0 && N != 0, "oh no", "error") {}
76
77template <int N>
78void alwayswarn() _diagnose_if(N == 0 || N != 0, "oh no", "warning") {} // expected-note 4{{from 'diagnose_if'}}
79
80template <int N>
81void neverwarn() _diagnose_if(N == 0 && N != 0, "oh no", "warning") {}
82
83void runAll() {
84  alwaysok<0>();
85  alwaysok<1>();
86
87  {
88    void (*pok)() = alwaysok<0>;
89    pok = &alwaysok<0>;
90  }
91
92  neverok<0>(); // expected-error{{oh no}}
93  neverok<1>(); // expected-error{{oh no}}
94
95  {
96    void (*pok)() = neverok<0>; // expected-error{{oh no}}
97  }
98  {
99    void (*pok)();
100    pok = &neverok<0>; // expected-error{{oh no}}
101  }
102
103  alwayswarn<0>(); // expected-warning{{oh no}}
104  alwayswarn<1>(); // expected-warning{{oh no}}
105  {
106    void (*pok)() = alwayswarn<0>; // expected-warning{{oh no}}
107    pok = &alwayswarn<0>; // expected-warning{{oh no}}
108  }
109
110  neverwarn<0>();
111  neverwarn<1>();
112  {
113    void (*pok)() = neverwarn<0>;
114    pok = &neverwarn<0>;
115  }
116}
117
118template <int N>
119void errorIf(int a) _diagnose_if(N != a, "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
120
121template <int N>
122void warnIf(int a) _diagnose_if(N != a, "oh no", "warning") {} // expected-note{{from 'diagnose_if'}}
123
124void runIf() {
125  errorIf<0>(0);
126  errorIf<0>(1); // expected-error{{oh no}}
127
128  warnIf<0>(0);
129  warnIf<0>(1); // expected-warning{{oh no}}
130}
131}
132
133namespace no_overload_interaction {
134void foo(int) _diagnose_if(1, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
135void foo(short);
136
137void bar(int);
138void bar(short) _diagnose_if(1, "oh no", "error");
139
140void fooArg(int a) _diagnose_if(a, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
141void fooArg(short);
142
143void barArg(int);
144void barArg(short a) _diagnose_if(a, "oh no", "error");
145
146void runAll() {
147  foo(1); // expected-error{{oh no}}
148  bar(1);
149
150  fooArg(1); // expected-error{{oh no}}
151  barArg(1);
152
153  auto p = foo; // expected-error{{incompatible initializer of type '<overloaded function type>'}}
154}
155}
156
157namespace with_default_args {
158void foo(int a = 0) _diagnose_if(a, "oh no", "warning"); // expected-note 1{{from 'diagnose_if'}}
159void bar(int a = 1) _diagnose_if(a, "oh no", "warning"); // expected-note 2{{from 'diagnose_if'}}
160
161void runAll() {
162  foo();
163  foo(0);
164  foo(1); // expected-warning{{oh no}}
165
166  bar(); // expected-warning{{oh no}}
167  bar(0);
168  bar(1); // expected-warning{{oh no}}
169}
170}
171
172namespace naked_mem_expr {
173struct Foo {
174  void foo(int a) _diagnose_if(a, "should warn", "warning"); // expected-note{{from 'diagnose_if'}}
175  void bar(int a) _diagnose_if(a, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
176};
177
178void runFoo() {
179  Foo().foo(0);
180  Foo().foo(1); // expected-warning{{should warn}}
181
182  Foo().bar(0);
183  Foo().bar(1); // expected-error{{oh no}}
184}
185}
186
187namespace class_template {
188template <typename T>
189struct Errors {
190  void foo(int i) _diagnose_if(i, "bad i", "error"); // expected-note{{from 'diagnose_if'}}
191  void bar(int i) _diagnose_if(i != T(), "bad i", "error"); // expected-note{{from 'diagnose_if'}}
192
193  void fooOvl(int i) _diagnose_if(i, "int bad i", "error"); // expected-note{{from 'diagnose_if'}}
194  void fooOvl(short i) _diagnose_if(i, "short bad i", "error"); // expected-note{{from 'diagnose_if'}}
195
196  void barOvl(int i) _diagnose_if(i != T(), "int bad i", "error"); // expected-note{{from 'diagnose_if'}}
197  void barOvl(short i) _diagnose_if(i != T(), "short bad i", "error"); // expected-note{{from 'diagnose_if'}}
198};
199
200void runErrors() {
201  Errors<int>().foo(0);
202  Errors<int>().foo(1); // expected-error{{bad i}}
203
204  Errors<int>().bar(0);
205  Errors<int>().bar(1); // expected-error{{bad i}}
206
207  Errors<int>().fooOvl(0);
208  Errors<int>().fooOvl(1); // expected-error{{int bad i}}
209  Errors<int>().fooOvl(short(0));
210  Errors<int>().fooOvl(short(1)); // expected-error{{short bad i}}
211
212  Errors<int>().barOvl(0);
213  Errors<int>().barOvl(1); // expected-error{{int bad i}}
214  Errors<int>().barOvl(short(0));
215  Errors<int>().barOvl(short(1)); // expected-error{{short bad i}}
216}
217
218template <typename T>
219struct Warnings {
220  void foo(int i) _diagnose_if(i, "bad i", "warning"); // expected-note{{from 'diagnose_if'}}
221  void bar(int i) _diagnose_if(i != T(), "bad i", "warning"); // expected-note{{from 'diagnose_if'}}
222
223  void fooOvl(int i) _diagnose_if(i, "int bad i", "warning"); // expected-note{{from 'diagnose_if'}}
224  void fooOvl(short i) _diagnose_if(i, "short bad i", "warning"); // expected-note{{from 'diagnose_if'}}
225
226  void barOvl(int i) _diagnose_if(i != T(), "int bad i", "warning"); // expected-note{{from 'diagnose_if'}}
227  void barOvl(short i) _diagnose_if(i != T(), "short bad i", "warning"); // expected-note{{from 'diagnose_if'}}
228};
229
230void runWarnings() {
231  Warnings<int>().foo(0);
232  Warnings<int>().foo(1); // expected-warning{{bad i}}
233
234  Warnings<int>().bar(0);
235  Warnings<int>().bar(1); // expected-warning{{bad i}}
236
237  Warnings<int>().fooOvl(0);
238  Warnings<int>().fooOvl(1); // expected-warning{{int bad i}}
239  Warnings<int>().fooOvl(short(0));
240  Warnings<int>().fooOvl(short(1)); // expected-warning{{short bad i}}
241
242  Warnings<int>().barOvl(0);
243  Warnings<int>().barOvl(1); // expected-warning{{int bad i}}
244  Warnings<int>().barOvl(short(0));
245  Warnings<int>().barOvl(short(1)); // expected-warning{{short bad i}}
246}
247}
248
249namespace template_specialization {
250template <typename T>
251struct Foo {
252  void foo() _diagnose_if(1, "override me", "error"); // expected-note{{from 'diagnose_if'}}
253  void bar(int i) _diagnose_if(i, "bad i", "error"); // expected-note{{from 'diagnose_if'}}
254  void baz(int i);
255};
256
257template <>
258struct Foo<int> {
259  void foo();
260  void bar(int i);
261  void baz(int i) _diagnose_if(i, "bad i", "error"); // expected-note{{from 'diagnose_if'}}
262};
263
264void runAll() {
265  Foo<double>().foo(); // expected-error{{override me}}
266  Foo<int>().foo();
267
268  Foo<double>().bar(1); // expected-error{{bad i}}
269  Foo<int>().bar(1);
270
271  Foo<double>().baz(1);
272  Foo<int>().baz(1); // expected-error{{bad i}}
273}
274}
275
276namespace late_constexpr {
277constexpr int foo();
278constexpr int foo(int a);
279
280void bar() _diagnose_if(foo(), "bad foo", "error"); // expected-note{{from 'diagnose_if'}}
281void bar(int a) _diagnose_if(foo(a), "bad foo", "error"); // expected-note{{from 'diagnose_if'}}
282
283void early() {
284  bar();
285  bar(0);
286  bar(1);
287}
288
289constexpr int foo() { return 1; }
290constexpr int foo(int a) { return a; }
291
292void late() {
293  bar(); // expected-error{{bad foo}}
294  bar(0);
295  bar(1); // expected-error{{bad foo}}
296}
297}
298
299namespace late_parsed {
300struct Foo {
301  int i;
302  constexpr Foo(int i): i(i) {}
303  constexpr bool isFooable() const { return i; }
304
305  void go() const _diagnose_if(isFooable(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
306  operator int() const _diagnose_if(isFooable(), "oh no", "error") { return 1; } // expected-note{{from 'diagnose_if'}}
307
308  void go2() const _diagnose_if(isFooable(), "oh no", "error") // expected-note{{from 'diagnose_if'}}
309      __attribute__((enable_if(true, ""))) {}
310  void go2() const _diagnose_if(isFooable(), "oh no", "error") {}
311
312  constexpr int go3() const _diagnose_if(isFooable(), "oh no", "error")
313      __attribute__((enable_if(true, ""))) {
314    return 1;
315  }
316
317  constexpr int go4() const _diagnose_if(isFooable(), "oh no", "error") {
318    return 1;
319  }
320  constexpr int go4() const _diagnose_if(isFooable(), "oh no", "error")
321      __attribute__((enable_if(true, ""))) {
322    return 1;
323  }
324
325  // We hope to support emitting these errors in the future. For now, though...
326  constexpr int runGo() const {
327    return go3() + go4();
328  }
329};
330
331void go(const Foo &f) _diagnose_if(f.isFooable(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
332
333void run() {
334  Foo(0).go();
335  Foo(1).go(); // expected-error{{oh no}}
336
337  (void)int(Foo(0));
338  (void)int(Foo(1)); // expected-error{{oh no}}
339
340  Foo(0).go2();
341  Foo(1).go2(); // expected-error{{oh no}}
342
343  go(Foo(0));
344  go(Foo(1)); // expected-error{{oh no}}
345}
346}
347
348namespace member_templates {
349struct Foo {
350  int i;
351  constexpr Foo(int i): i(i) {}
352  constexpr bool bad() const { return i; }
353
354  template <typename T> T getVal() _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}}
355    return T();
356  }
357
358  template <typename T>
359  constexpr T getVal2() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}}
360    return T();
361  }
362
363  template <typename T>
364  constexpr operator T() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}}
365    return T();
366  }
367
368  // We hope to support emitting these errors in the future.
369  int run() { return getVal<int>() + getVal2<int>() + int(*this); }
370};
371
372void run() {
373  Foo(0).getVal<int>();
374  Foo(1).getVal<int>(); // expected-error{{oh no}}
375
376  Foo(0).getVal2<int>();
377  Foo(1).getVal2<int>(); // expected-error{{oh no}}
378
379  (void)int(Foo(0));
380  (void)int(Foo(1)); // expected-error{{oh no}}
381}
382}
383
384namespace special_member_operators {
385struct Bar { int j; };
386struct Foo {
387  int i;
388  constexpr Foo(int i): i(i) {}
389  constexpr bool bad() const { return i; }
390  const Bar *operator->() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}}
391    return nullptr;
392  }
393  void operator()() const _diagnose_if(bad(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
394};
395
396struct ParenOverload {
397  int i;
398  constexpr ParenOverload(int i): i(i) {}
399  constexpr bool bad() const { return i; }
400  void operator()(double) const _diagnose_if(bad(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
401  void operator()(int) const _diagnose_if(bad(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
402};
403
404struct ParenTemplate {
405  int i;
406  constexpr ParenTemplate(int i): i(i) {}
407  constexpr bool bad() const { return i; }
408  template <typename T>
409  void operator()(T) const _diagnose_if(bad(), "oh no", "error") {} // expected-note 2{{from 'diagnose_if'}}
410};
411
412void run() {
413  (void)Foo(0)->j;
414  (void)Foo(1)->j; // expected-error{{oh no}}
415
416  Foo(0)();
417  Foo(1)(); // expected-error{{oh no}}
418
419  ParenOverload(0)(1);
420  ParenOverload(0)(1.);
421
422  ParenOverload(1)(1); // expected-error{{oh no}}
423  ParenOverload(1)(1.); // expected-error{{oh no}}
424
425  ParenTemplate(0)(1);
426  ParenTemplate(0)(1.);
427
428  ParenTemplate(1)(1); // expected-error{{oh no}}
429  ParenTemplate(1)(1.); // expected-error{{oh no}}
430}
431
432void runLambda() {
433  auto L1 = [](int i) _diagnose_if(i, "oh no", "error") {}; // expected-note{{from 'diagnose_if'}}
434  L1(0);
435  L1(1); // expected-error{{oh no}}
436}
437
438struct Brackets {
439  int i;
440  constexpr Brackets(int i): i(i) {}
441  void operator[](int) _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
442    _diagnose_if(i == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
443};
444
445void runBrackets(int i) {
446  Brackets{0}[i];
447  Brackets{1}[i]; // expected-warning{{oh no}}
448  Brackets{2}[i]; // expected-error{{oh no}}
449}
450
451struct Unary {
452  int i;
453  constexpr Unary(int i): i(i) {}
454  void operator+() _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
455    _diagnose_if(i == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
456};
457
458void runUnary() {
459  +Unary{0};
460  +Unary{1}; // expected-warning{{oh no}}
461  +Unary{2}; // expected-error{{oh no}}
462}
463
464struct PostInc {
465  void operator++(int i) _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
466    _diagnose_if(i == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
467};
468
469void runPostInc() {
470  PostInc{}++;
471  PostInc{}.operator++(1); // expected-warning{{oh no}}
472  PostInc{}.operator++(2); // expected-error{{oh no}}
473}
474}
475
476namespace ctors {
477struct Foo {
478  int I;
479  constexpr Foo(int I): I(I) {}
480
481  constexpr const Foo &operator=(const Foo &) const
482      _diagnose_if(I, "oh no", "error") {  // expected-note{{from 'diagnose_if'}}
483    return *this;
484  }
485
486  constexpr const Foo &operator=(const Foo &&) const
487      _diagnose_if(I, "oh no", "error") { // expected-note{{from 'diagnose_if'}}
488    return *this;
489  }
490};
491
492struct Bar {
493  int I;
494  constexpr Bar(int I) _diagnose_if(I == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
495    _diagnose_if(I == 2, "oh no", "error"): I(I) {} // expected-note{{from 'diagnose_if'}}
496};
497
498void run() {
499  constexpr Foo F{0};
500  constexpr Foo F2{1};
501
502  F2 = F; // expected-error{{oh no}}
503  F2 = Foo{2}; // expected-error{{oh no}}
504
505  Bar{0};
506  Bar{1}; // expected-warning{{oh no}}
507  Bar{2}; // expected-error{{oh no}}
508}
509}
510
511namespace ref_init {
512struct Bar {};
513struct Baz {};
514struct Foo {
515  int i;
516  constexpr Foo(int i): i(i) {}
517  operator const Bar &() const _diagnose_if(i, "oh no", "warning"); // expected-note{{from 'diagnose_if'}}
518  operator const Baz &() const _diagnose_if(i, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
519};
520void fooBar(const Bar &b);
521void fooBaz(const Baz &b);
522
523void run() {
524  fooBar(Foo{0});
525  fooBar(Foo{1}); // expected-warning{{oh no}}
526  fooBaz(Foo{0});
527  fooBaz(Foo{1}); // expected-error{{oh no}}
528}
529}
530
531namespace udl {
532void operator""_fn(char c)_diagnose_if(c == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
533    _diagnose_if(c == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
534
535void run() {
536  '\0'_fn;
537  '\1'_fn; // expected-warning{{oh no}}
538  '\2'_fn; // expected-error{{oh no}}
539}
540}
541
542namespace PR31638 {
543struct String {
544  String(char const* __s) _diagnose_if(__s == nullptr, "oh no ptr", "warning"); // expected-note{{from 'diagnose_if'}}
545  String(int __s) _diagnose_if(__s != 0, "oh no int", "warning"); // expected-note{{from 'diagnose_if'}}
546};
547
548void run() {
549  String s(nullptr); // expected-warning{{oh no ptr}}
550  String ss(42); // expected-warning{{oh no int}}
551}
552}
553
554namespace PR31639 {
555struct Foo {
556  Foo(int I) __attribute__((diagnose_if(I, "oh no", "error"))); // expected-note{{from 'diagnose_if'}}
557};
558
559void bar() { Foo f(1); } // expected-error{{oh no}}
560}
561
562namespace user_defined_conversion {
563struct Foo {
564  int i;
565  constexpr Foo(int i): i(i) {}
566  operator size_t() const _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
567      _diagnose_if(i == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
568};
569
570void run() {
571  // `new T[N]`, where N is implicitly convertible to size_t, calls
572  // PerformImplicitConversion directly. This lets us test the diagnostic logic
573  // in PerformImplicitConversion.
574  new int[Foo{0}];
575  new int[Foo{1}]; // expected-warning{{oh no}}
576  new int[Foo{2}]; // expected-error{{oh no}}
577}
578}
579
580namespace std {
581  template <typename T>
582  struct initializer_list {
583    const T *ptr;
584    size_t elems;
585
586    constexpr size_t size() const { return elems; }
587  };
588}
589
590namespace initializer_lists {
591struct Foo {
592  Foo(std::initializer_list<int> l)
593    _diagnose_if(l.size() == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
594    _diagnose_if(l.size() == 2, "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
595};
596
597void run() {
598  Foo{std::initializer_list<int>{}};
599  Foo{std::initializer_list<int>{1}}; // expected-warning{{oh no}}
600  Foo{std::initializer_list<int>{1, 2}}; // expected-error{{oh no}}
601  Foo{std::initializer_list<int>{1, 2, 3}};
602}
603}
604
605namespace range_for_loop {
606  namespace adl {
607    struct Foo {
608      int i;
609      constexpr Foo(int i): i(i) {}
610    };
611    void **begin(const Foo &f) _diagnose_if(f.i, "oh no", "warning");
612    void **end(const Foo &f) _diagnose_if(f.i, "oh no", "warning");
613
614    struct Bar {
615      int i;
616      constexpr Bar(int i): i(i) {}
617    };
618    void **begin(const Bar &b) _diagnose_if(b.i, "oh no", "error");
619    void **end(const Bar &b) _diagnose_if(b.i, "oh no", "error");
620  }
621
622  void run() {
623    for (void *p : adl::Foo(0)) {}
624    // FIXME: This should emit diagnostics. It seems that our constexpr
625    // evaluator isn't able to evaluate `adl::Foo(1)` as a constant, though.
626    for (void *p : adl::Foo(1)) {}
627
628    for (void *p : adl::Bar(0)) {}
629    // FIXME: Same thing.
630    for (void *p : adl::Bar(1)) {}
631  }
632}
633
634namespace operator_new {
635struct Foo {
636  int j;
637  static void *operator new(size_t i) _diagnose_if(i, "oh no", "warning");
638};
639
640struct Bar {
641  int j;
642  static void *operator new(size_t i) _diagnose_if(!i, "oh no", "warning");
643};
644
645void run() {
646  // FIXME: This should emit a diagnostic.
647  new Foo();
648  // This is here because we sometimes pass a dummy argument `operator new`. We
649  // should ignore this, rather than complaining about it.
650  new Bar();
651}
652}
653
654namespace contextual_implicit_conv {
655struct Foo {
656  int i;
657  constexpr Foo(int i): i(i) {}
658  constexpr operator int() const _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
659      _diagnose_if(i == 2, "oh no", "error") { // expected-note{{from 'diagnose_if'}}
660    return i;
661  }
662};
663
664void run() {
665  switch (constexpr Foo i = 0) { default: break; }
666  switch (constexpr Foo i = 1) { default: break; } // expected-warning{{oh no}}
667  switch (constexpr Foo i = 2) { default: break; } // expected-error{{oh no}}
668}
669}
670