|  | // RUN: %clang_cc1 %s -verify -fno-builtin -std=c++14 | 
|  |  | 
|  | #define _diagnose_if(...) __attribute__((diagnose_if(__VA_ARGS__))) | 
|  |  | 
|  | using size_t = decltype(sizeof(int)); | 
|  |  | 
|  | namespace type_dependent { | 
|  | template <typename T> | 
|  | void neverok() _diagnose_if(!T(), "oh no", "error") {} // expected-note 4{{from 'diagnose_if'}} | 
|  |  | 
|  | template <typename T> | 
|  | void alwaysok() _diagnose_if(T(), "oh no", "error") {} | 
|  |  | 
|  | template <typename T> | 
|  | void alwayswarn() _diagnose_if(!T(), "oh no", "warning") {} // expected-note 4{{from 'diagnose_if'}} | 
|  |  | 
|  | template <typename T> | 
|  | void neverwarn() _diagnose_if(T(), "oh no", "warning") {} | 
|  |  | 
|  | void runAll() { | 
|  | alwaysok<int>(); | 
|  | alwaysok<int>(); | 
|  |  | 
|  | { | 
|  | void (*pok)() = alwaysok<int>; | 
|  | pok = &alwaysok<int>; | 
|  | } | 
|  |  | 
|  | neverok<int>(); // expected-error{{oh no}} | 
|  | neverok<short>(); // expected-error{{oh no}} | 
|  |  | 
|  | { | 
|  | void (*pok)() = neverok<int>; // expected-error{{oh no}} | 
|  | } | 
|  | { | 
|  | void (*pok)(); | 
|  | pok = &neverok<int>; // expected-error{{oh no}} | 
|  | } | 
|  |  | 
|  | alwayswarn<int>(); // expected-warning{{oh no}} | 
|  | alwayswarn<short>(); // expected-warning{{oh no}} | 
|  | { | 
|  | void (*pok)() = alwayswarn<int>; // expected-warning{{oh no}} | 
|  | pok = &alwayswarn<int>; // expected-warning{{oh no}} | 
|  | } | 
|  |  | 
|  | neverwarn<int>(); | 
|  | neverwarn<short>(); | 
|  | { | 
|  | void (*pok)() = neverwarn<int>; | 
|  | pok = &neverwarn<int>; | 
|  | } | 
|  | } | 
|  |  | 
|  | template <typename T> | 
|  | void errorIf(T a) _diagnose_if(T() != a, "oh no", "error") {} // expected-note{{from 'diagnose_if'}} | 
|  |  | 
|  | template <typename T> | 
|  | void warnIf(T a) _diagnose_if(T() != a, "oh no", "warning") {} // expected-note{{from 'diagnose_if'}} | 
|  |  | 
|  | void runIf() { | 
|  | errorIf(0); | 
|  | errorIf(1); // expected-error{{oh no}} | 
|  |  | 
|  | warnIf(0); | 
|  | warnIf(1); // expected-warning{{oh no}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace value_dependent { | 
|  | template <int N> | 
|  | void neverok() _diagnose_if(N == 0 || N != 0, "oh no", "error") {} // expected-note 4{{from 'diagnose_if'}} | 
|  |  | 
|  | template <int N> | 
|  | void alwaysok() _diagnose_if(N == 0 && N != 0, "oh no", "error") {} | 
|  |  | 
|  | template <int N> | 
|  | void alwayswarn() _diagnose_if(N == 0 || N != 0, "oh no", "warning") {} // expected-note 4{{from 'diagnose_if'}} | 
|  |  | 
|  | template <int N> | 
|  | void neverwarn() _diagnose_if(N == 0 && N != 0, "oh no", "warning") {} | 
|  |  | 
|  | void runAll() { | 
|  | alwaysok<0>(); | 
|  | alwaysok<1>(); | 
|  |  | 
|  | { | 
|  | void (*pok)() = alwaysok<0>; | 
|  | pok = &alwaysok<0>; | 
|  | } | 
|  |  | 
|  | neverok<0>(); // expected-error{{oh no}} | 
|  | neverok<1>(); // expected-error{{oh no}} | 
|  |  | 
|  | { | 
|  | void (*pok)() = neverok<0>; // expected-error{{oh no}} | 
|  | } | 
|  | { | 
|  | void (*pok)(); | 
|  | pok = &neverok<0>; // expected-error{{oh no}} | 
|  | } | 
|  |  | 
|  | alwayswarn<0>(); // expected-warning{{oh no}} | 
|  | alwayswarn<1>(); // expected-warning{{oh no}} | 
|  | { | 
|  | void (*pok)() = alwayswarn<0>; // expected-warning{{oh no}} | 
|  | pok = &alwayswarn<0>; // expected-warning{{oh no}} | 
|  | } | 
|  |  | 
|  | neverwarn<0>(); | 
|  | neverwarn<1>(); | 
|  | { | 
|  | void (*pok)() = neverwarn<0>; | 
|  | pok = &neverwarn<0>; | 
|  | } | 
|  | } | 
|  |  | 
|  | template <int N> | 
|  | void errorIf(int a) _diagnose_if(N != a, "oh no", "error") {} // expected-note{{from 'diagnose_if'}} | 
|  |  | 
|  | template <int N> | 
|  | void warnIf(int a) _diagnose_if(N != a, "oh no", "warning") {} // expected-note{{from 'diagnose_if'}} | 
|  |  | 
|  | void runIf() { | 
|  | errorIf<0>(0); | 
|  | errorIf<0>(1); // expected-error{{oh no}} | 
|  |  | 
|  | warnIf<0>(0); | 
|  | warnIf<0>(1); // expected-warning{{oh no}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace no_overload_interaction { | 
|  | void foo(int) _diagnose_if(1, "oh no", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | void foo(short); | 
|  |  | 
|  | void bar(int); | 
|  | void bar(short) _diagnose_if(1, "oh no", "error"); | 
|  |  | 
|  | void fooArg(int a) _diagnose_if(a, "oh no", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | void fooArg(short); | 
|  |  | 
|  | void barArg(int); | 
|  | void barArg(short a) _diagnose_if(a, "oh no", "error"); | 
|  |  | 
|  | void runAll() { | 
|  | foo(1); // expected-error{{oh no}} | 
|  | bar(1); | 
|  |  | 
|  | fooArg(1); // expected-error{{oh no}} | 
|  | barArg(1); | 
|  |  | 
|  | auto p = foo; // expected-error{{incompatible initializer of type '<overloaded function type>'}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace with_default_args { | 
|  | void foo(int a = 0) _diagnose_if(a, "oh no", "warning"); // expected-note 1{{from 'diagnose_if'}} | 
|  | void bar(int a = 1) _diagnose_if(a, "oh no", "warning"); // expected-note 2{{from 'diagnose_if'}} | 
|  |  | 
|  | void runAll() { | 
|  | foo(); | 
|  | foo(0); | 
|  | foo(1); // expected-warning{{oh no}} | 
|  |  | 
|  | bar(); // expected-warning{{oh no}} | 
|  | bar(0); | 
|  | bar(1); // expected-warning{{oh no}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace naked_mem_expr { | 
|  | struct Foo { | 
|  | void foo(int a) _diagnose_if(a, "should warn", "warning"); // expected-note{{from 'diagnose_if'}} | 
|  | void bar(int a) _diagnose_if(a, "oh no", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | void runFoo() { | 
|  | Foo().foo(0); | 
|  | Foo().foo(1); // expected-warning{{should warn}} | 
|  |  | 
|  | Foo().bar(0); | 
|  | Foo().bar(1); // expected-error{{oh no}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace class_template { | 
|  | template <typename T> | 
|  | struct Errors { | 
|  | void foo(int i) _diagnose_if(i, "bad i", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | void bar(int i) _diagnose_if(i != T(), "bad i", "error"); // expected-note{{from 'diagnose_if'}} | 
|  |  | 
|  | void fooOvl(int i) _diagnose_if(i, "int bad i", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | void fooOvl(short i) _diagnose_if(i, "short bad i", "error"); // expected-note{{from 'diagnose_if'}} | 
|  |  | 
|  | void barOvl(int i) _diagnose_if(i != T(), "int bad i", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | void barOvl(short i) _diagnose_if(i != T(), "short bad i", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | void runErrors() { | 
|  | Errors<int>().foo(0); | 
|  | Errors<int>().foo(1); // expected-error{{bad i}} | 
|  |  | 
|  | Errors<int>().bar(0); | 
|  | Errors<int>().bar(1); // expected-error{{bad i}} | 
|  |  | 
|  | Errors<int>().fooOvl(0); | 
|  | Errors<int>().fooOvl(1); // expected-error{{int bad i}} | 
|  | Errors<int>().fooOvl(short(0)); | 
|  | Errors<int>().fooOvl(short(1)); // expected-error{{short bad i}} | 
|  |  | 
|  | Errors<int>().barOvl(0); | 
|  | Errors<int>().barOvl(1); // expected-error{{int bad i}} | 
|  | Errors<int>().barOvl(short(0)); | 
|  | Errors<int>().barOvl(short(1)); // expected-error{{short bad i}} | 
|  | } | 
|  |  | 
|  | template <typename T> | 
|  | struct Warnings { | 
|  | void foo(int i) _diagnose_if(i, "bad i", "warning"); // expected-note{{from 'diagnose_if'}} | 
|  | void bar(int i) _diagnose_if(i != T(), "bad i", "warning"); // expected-note{{from 'diagnose_if'}} | 
|  |  | 
|  | void fooOvl(int i) _diagnose_if(i, "int bad i", "warning"); // expected-note{{from 'diagnose_if'}} | 
|  | void fooOvl(short i) _diagnose_if(i, "short bad i", "warning"); // expected-note{{from 'diagnose_if'}} | 
|  |  | 
|  | void barOvl(int i) _diagnose_if(i != T(), "int bad i", "warning"); // expected-note{{from 'diagnose_if'}} | 
|  | void barOvl(short i) _diagnose_if(i != T(), "short bad i", "warning"); // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | void runWarnings() { | 
|  | Warnings<int>().foo(0); | 
|  | Warnings<int>().foo(1); // expected-warning{{bad i}} | 
|  |  | 
|  | Warnings<int>().bar(0); | 
|  | Warnings<int>().bar(1); // expected-warning{{bad i}} | 
|  |  | 
|  | Warnings<int>().fooOvl(0); | 
|  | Warnings<int>().fooOvl(1); // expected-warning{{int bad i}} | 
|  | Warnings<int>().fooOvl(short(0)); | 
|  | Warnings<int>().fooOvl(short(1)); // expected-warning{{short bad i}} | 
|  |  | 
|  | Warnings<int>().barOvl(0); | 
|  | Warnings<int>().barOvl(1); // expected-warning{{int bad i}} | 
|  | Warnings<int>().barOvl(short(0)); | 
|  | Warnings<int>().barOvl(short(1)); // expected-warning{{short bad i}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace template_specialization { | 
|  | template <typename T> | 
|  | struct Foo { | 
|  | void foo() _diagnose_if(1, "override me", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | void bar(int i) _diagnose_if(i, "bad i", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | void baz(int i); | 
|  | }; | 
|  |  | 
|  | template <> | 
|  | struct Foo<int> { | 
|  | void foo(); | 
|  | void bar(int i); | 
|  | void baz(int i) _diagnose_if(i, "bad i", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | void runAll() { | 
|  | Foo<double>().foo(); // expected-error{{override me}} | 
|  | Foo<int>().foo(); | 
|  |  | 
|  | Foo<double>().bar(1); // expected-error{{bad i}} | 
|  | Foo<int>().bar(1); | 
|  |  | 
|  | Foo<double>().baz(1); | 
|  | Foo<int>().baz(1); // expected-error{{bad i}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace late_constexpr { | 
|  | constexpr int foo(); | 
|  | constexpr int foo(int a); | 
|  |  | 
|  | void bar() _diagnose_if(foo(), "bad foo", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | void bar(int a) _diagnose_if(foo(a), "bad foo", "error"); // expected-note{{from 'diagnose_if'}} | 
|  |  | 
|  | void early() { | 
|  | bar(); | 
|  | bar(0); | 
|  | bar(1); | 
|  | } | 
|  |  | 
|  | constexpr int foo() { return 1; } | 
|  | constexpr int foo(int a) { return a; } | 
|  |  | 
|  | void late() { | 
|  | bar(); // expected-error{{bad foo}} | 
|  | bar(0); | 
|  | bar(1); // expected-error{{bad foo}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace late_parsed { | 
|  | struct Foo { | 
|  | int i; | 
|  | constexpr Foo(int i): i(i) {} | 
|  | constexpr bool isFooable() const { return i; } | 
|  |  | 
|  | void go() const _diagnose_if(isFooable(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}} | 
|  | operator int() const _diagnose_if(isFooable(), "oh no", "error") { return 1; } // expected-note{{from 'diagnose_if'}} | 
|  |  | 
|  | void go2() const _diagnose_if(isFooable(), "oh no", "error") // expected-note{{from 'diagnose_if'}} | 
|  | __attribute__((enable_if(true, ""))) {} | 
|  | void go2() const _diagnose_if(isFooable(), "oh no", "error") {} | 
|  |  | 
|  | constexpr int go3() const _diagnose_if(isFooable(), "oh no", "error") | 
|  | __attribute__((enable_if(true, ""))) { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | constexpr int go4() const _diagnose_if(isFooable(), "oh no", "error") { | 
|  | return 1; | 
|  | } | 
|  | constexpr int go4() const _diagnose_if(isFooable(), "oh no", "error") | 
|  | __attribute__((enable_if(true, ""))) { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | // We hope to support emitting these errors in the future. For now, though... | 
|  | constexpr int runGo() const { | 
|  | return go3() + go4(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | void go(const Foo &f) _diagnose_if(f.isFooable(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}} | 
|  |  | 
|  | void run() { | 
|  | Foo(0).go(); | 
|  | Foo(1).go(); // expected-error{{oh no}} | 
|  |  | 
|  | (void)int(Foo(0)); | 
|  | (void)int(Foo(1)); // expected-error{{oh no}} | 
|  |  | 
|  | Foo(0).go2(); | 
|  | Foo(1).go2(); // expected-error{{oh no}} | 
|  |  | 
|  | go(Foo(0)); | 
|  | go(Foo(1)); // expected-error{{oh no}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace member_templates { | 
|  | struct Foo { | 
|  | int i; | 
|  | constexpr Foo(int i): i(i) {} | 
|  | constexpr bool bad() const { return i; } | 
|  |  | 
|  | template <typename T> T getVal() _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}} | 
|  | return T(); | 
|  | } | 
|  |  | 
|  | template <typename T> | 
|  | constexpr T getVal2() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}} | 
|  | return T(); | 
|  | } | 
|  |  | 
|  | template <typename T> | 
|  | constexpr operator T() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}} | 
|  | return T(); | 
|  | } | 
|  |  | 
|  | // We hope to support emitting these errors in the future. | 
|  | int run() { return getVal<int>() + getVal2<int>() + int(*this); } | 
|  | }; | 
|  |  | 
|  | void run() { | 
|  | Foo(0).getVal<int>(); | 
|  | Foo(1).getVal<int>(); // expected-error{{oh no}} | 
|  |  | 
|  | Foo(0).getVal2<int>(); | 
|  | Foo(1).getVal2<int>(); // expected-error{{oh no}} | 
|  |  | 
|  | (void)int(Foo(0)); | 
|  | (void)int(Foo(1)); // expected-error{{oh no}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace special_member_operators { | 
|  | struct Bar { int j; }; | 
|  | struct Foo { | 
|  | int i; | 
|  | constexpr Foo(int i): i(i) {} | 
|  | constexpr bool bad() const { return i; } | 
|  | const Bar *operator->() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}} | 
|  | return nullptr; | 
|  | } | 
|  | void operator()() const _diagnose_if(bad(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | struct ParenOverload { | 
|  | int i; | 
|  | constexpr ParenOverload(int i): i(i) {} | 
|  | constexpr bool bad() const { return i; } | 
|  | void operator()(double) const _diagnose_if(bad(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}} | 
|  | void operator()(int) const _diagnose_if(bad(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | struct ParenTemplate { | 
|  | int i; | 
|  | constexpr ParenTemplate(int i): i(i) {} | 
|  | constexpr bool bad() const { return i; } | 
|  | template <typename T> | 
|  | void operator()(T) const _diagnose_if(bad(), "oh no", "error") {} // expected-note 2{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | void run() { | 
|  | (void)Foo(0)->j; | 
|  | (void)Foo(1)->j; // expected-error{{oh no}} | 
|  |  | 
|  | Foo(0)(); | 
|  | Foo(1)(); // expected-error{{oh no}} | 
|  |  | 
|  | ParenOverload(0)(1); | 
|  | ParenOverload(0)(1.); | 
|  |  | 
|  | ParenOverload(1)(1); // expected-error{{oh no}} | 
|  | ParenOverload(1)(1.); // expected-error{{oh no}} | 
|  |  | 
|  | ParenTemplate(0)(1); | 
|  | ParenTemplate(0)(1.); | 
|  |  | 
|  | ParenTemplate(1)(1); // expected-error{{oh no}} | 
|  | ParenTemplate(1)(1.); // expected-error{{oh no}} | 
|  | } | 
|  |  | 
|  | void runLambda() { | 
|  | auto L1 = [](int i) _diagnose_if(i, "oh no", "error") {}; // expected-note{{from 'diagnose_if'}} | 
|  | L1(0); | 
|  | L1(1); // expected-error{{oh no}} | 
|  | } | 
|  |  | 
|  | struct Brackets { | 
|  | int i; | 
|  | constexpr Brackets(int i): i(i) {} | 
|  | void operator[](int) _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}} | 
|  | _diagnose_if(i == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | void runBrackets(int i) { | 
|  | Brackets{0}[i]; | 
|  | Brackets{1}[i]; // expected-warning{{oh no}} | 
|  | Brackets{2}[i]; // expected-error{{oh no}} | 
|  | } | 
|  |  | 
|  | struct Unary { | 
|  | int i; | 
|  | constexpr Unary(int i): i(i) {} | 
|  | void operator+() _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}} | 
|  | _diagnose_if(i == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | void runUnary() { | 
|  | +Unary{0}; | 
|  | +Unary{1}; // expected-warning{{oh no}} | 
|  | +Unary{2}; // expected-error{{oh no}} | 
|  | } | 
|  |  | 
|  | struct PostInc { | 
|  | void operator++(int i) _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}} | 
|  | _diagnose_if(i == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | void runPostInc() { | 
|  | PostInc{}++; | 
|  | PostInc{}.operator++(1); // expected-warning{{oh no}} | 
|  | PostInc{}.operator++(2); // expected-error{{oh no}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace ctors { | 
|  | struct Foo { | 
|  | int I; | 
|  | constexpr Foo(int I): I(I) {} | 
|  |  | 
|  | constexpr const Foo &operator=(const Foo &) const | 
|  | _diagnose_if(I, "oh no", "error") {  // expected-note{{from 'diagnose_if'}} | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | constexpr const Foo &operator=(const Foo &&) const | 
|  | _diagnose_if(I, "oh no", "error") { // expected-note{{from 'diagnose_if'}} | 
|  | return *this; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct Bar { | 
|  | int I; | 
|  | constexpr Bar(int I) _diagnose_if(I == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}} | 
|  | _diagnose_if(I == 2, "oh no", "error"): I(I) {} // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | void run() { | 
|  | constexpr Foo F{0}; | 
|  | constexpr Foo F2{1}; | 
|  |  | 
|  | F2 = F; // expected-error{{oh no}} | 
|  | F2 = Foo{2}; // expected-error{{oh no}} | 
|  |  | 
|  | Bar{0}; | 
|  | Bar{1}; // expected-warning{{oh no}} | 
|  | Bar{2}; // expected-error{{oh no}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace ref_init { | 
|  | struct Bar {}; | 
|  | struct Baz {}; | 
|  | struct Foo { | 
|  | int i; | 
|  | constexpr Foo(int i): i(i) {} | 
|  | operator const Bar &() const _diagnose_if(i, "oh no", "warning"); // expected-note{{from 'diagnose_if'}} | 
|  | operator const Baz &() const _diagnose_if(i, "oh no", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  | void fooBar(const Bar &b); | 
|  | void fooBaz(const Baz &b); | 
|  |  | 
|  | void run() { | 
|  | fooBar(Foo{0}); | 
|  | fooBar(Foo{1}); // expected-warning{{oh no}} | 
|  | fooBaz(Foo{0}); | 
|  | fooBaz(Foo{1}); // expected-error{{oh no}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace udl { | 
|  | void operator""_fn(char c)_diagnose_if(c == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}} | 
|  | _diagnose_if(c == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}} | 
|  |  | 
|  | void run() { | 
|  | '\0'_fn; | 
|  | '\1'_fn; // expected-warning{{oh no}} | 
|  | '\2'_fn; // expected-error{{oh no}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace PR31638 { | 
|  | struct String { | 
|  | String(char const* __s) _diagnose_if(__s == nullptr, "oh no ptr", "warning"); // expected-note{{from 'diagnose_if'}} | 
|  | String(int __s) _diagnose_if(__s != 0, "oh no int", "warning"); // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | void run() { | 
|  | String s(nullptr); // expected-warning{{oh no ptr}} | 
|  | String ss(42); // expected-warning{{oh no int}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace PR31639 { | 
|  | struct Foo { | 
|  | Foo(int I) __attribute__((diagnose_if(I, "oh no", "error"))); // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | void bar() { Foo f(1); } // expected-error{{oh no}} | 
|  | } | 
|  |  | 
|  | namespace user_defined_conversion { | 
|  | struct Foo { | 
|  | int i; | 
|  | constexpr Foo(int i): i(i) {} | 
|  | operator size_t() const _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}} | 
|  | _diagnose_if(i == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | void run() { | 
|  | // `new T[N]`, where N is implicitly convertible to size_t, calls | 
|  | // PerformImplicitConversion directly. This lets us test the diagnostic logic | 
|  | // in PerformImplicitConversion. | 
|  | new int[Foo{0}]; | 
|  | new int[Foo{1}]; // expected-warning{{oh no}} | 
|  | new int[Foo{2}]; // expected-error{{oh no}} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace std { | 
|  | template <typename T> | 
|  | struct initializer_list { | 
|  | const T *ptr; | 
|  | size_t elems; | 
|  |  | 
|  | constexpr size_t size() const { return elems; } | 
|  | }; | 
|  | } | 
|  |  | 
|  | namespace initializer_lists { | 
|  | struct Foo { | 
|  | Foo(std::initializer_list<int> l) | 
|  | _diagnose_if(l.size() == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}} | 
|  | _diagnose_if(l.size() == 2, "oh no", "error") {} // expected-note{{from 'diagnose_if'}} | 
|  | }; | 
|  |  | 
|  | void run() { | 
|  | Foo{std::initializer_list<int>{}}; | 
|  | Foo{std::initializer_list<int>{1}}; // expected-warning{{oh no}} | 
|  | Foo{std::initializer_list<int>{1, 2}}; // expected-error{{oh no}} | 
|  | Foo{std::initializer_list<int>{1, 2, 3}}; | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace range_for_loop { | 
|  | namespace adl { | 
|  | struct Foo { | 
|  | int i; | 
|  | constexpr Foo(int i): i(i) {} | 
|  | }; | 
|  | void **begin(const Foo &f) _diagnose_if(f.i, "oh no", "warning"); | 
|  | void **end(const Foo &f) _diagnose_if(f.i, "oh no", "warning"); | 
|  |  | 
|  | struct Bar { | 
|  | int i; | 
|  | constexpr Bar(int i): i(i) {} | 
|  | }; | 
|  | void **begin(const Bar &b) _diagnose_if(b.i, "oh no", "error"); | 
|  | void **end(const Bar &b) _diagnose_if(b.i, "oh no", "error"); | 
|  | } | 
|  |  | 
|  | void run() { | 
|  | for (void *p : adl::Foo(0)) {} | 
|  | // FIXME: This should emit diagnostics. It seems that our constexpr | 
|  | // evaluator isn't able to evaluate `adl::Foo(1)` as a constant, though. | 
|  | for (void *p : adl::Foo(1)) {} | 
|  |  | 
|  | for (void *p : adl::Bar(0)) {} | 
|  | // FIXME: Same thing. | 
|  | for (void *p : adl::Bar(1)) {} | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace operator_new { | 
|  | struct Foo { | 
|  | int j; | 
|  | static void *operator new(size_t i) _diagnose_if(i, "oh no", "warning"); | 
|  | }; | 
|  |  | 
|  | struct Bar { | 
|  | int j; | 
|  | static void *operator new(size_t i) _diagnose_if(!i, "oh no", "warning"); | 
|  | }; | 
|  |  | 
|  | void run() { | 
|  | // FIXME: This should emit a diagnostic. | 
|  | new Foo(); | 
|  | // This is here because we sometimes pass a dummy argument `operator new`. We | 
|  | // should ignore this, rather than complaining about it. | 
|  | new Bar(); | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace contextual_implicit_conv { | 
|  | struct Foo { | 
|  | int i; | 
|  | constexpr Foo(int i): i(i) {} | 
|  | constexpr operator int() const _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}} | 
|  | _diagnose_if(i == 2, "oh no", "error") { // expected-note{{from 'diagnose_if'}} | 
|  | return i; | 
|  | } | 
|  | }; | 
|  |  | 
|  | void run() { | 
|  | switch (constexpr Foo i = 0) { default: break; } | 
|  | switch (constexpr Foo i = 1) { default: break; } // expected-warning{{oh no}} | 
|  | switch (constexpr Foo i = 2) { default: break; } // expected-error{{oh no}} | 
|  | } | 
|  | } |