// 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 void neverok() _diagnose_if(!T(), "oh no", "error") {} // expected-note 4{{from 'diagnose_if'}} template void alwaysok() _diagnose_if(T(), "oh no", "error") {} template void alwayswarn() _diagnose_if(!T(), "oh no", "warning") {} // expected-note 4{{from 'diagnose_if'}} template void neverwarn() _diagnose_if(T(), "oh no", "warning") {} void runAll() { alwaysok(); alwaysok(); { void (*pok)() = alwaysok; pok = &alwaysok; } neverok(); // expected-error{{oh no}} neverok(); // expected-error{{oh no}} { void (*pok)() = neverok; // expected-error{{oh no}} } { void (*pok)(); pok = &neverok; // expected-error{{oh no}} } alwayswarn(); // expected-warning{{oh no}} alwayswarn(); // expected-warning{{oh no}} { void (*pok)() = alwayswarn; // expected-warning{{oh no}} pok = &alwayswarn; // expected-warning{{oh no}} } neverwarn(); neverwarn(); { void (*pok)() = neverwarn; pok = &neverwarn; } } template void errorIf(T a) _diagnose_if(T() != a, "oh no", "error") {} // expected-note{{from 'diagnose_if'}} template 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 void neverok() _diagnose_if(N == 0 || N != 0, "oh no", "error") {} // expected-note 4{{from 'diagnose_if'}} template void alwaysok() _diagnose_if(N == 0 && N != 0, "oh no", "error") {} template void alwayswarn() _diagnose_if(N == 0 || N != 0, "oh no", "warning") {} // expected-note 4{{from 'diagnose_if'}} template 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 void errorIf(int a) _diagnose_if(N != a, "oh no", "error") {} // expected-note{{from 'diagnose_if'}} template 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 ''}} } } 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 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().foo(0); Errors().foo(1); // expected-error{{bad i}} Errors().bar(0); Errors().bar(1); // expected-error{{bad i}} Errors().fooOvl(0); Errors().fooOvl(1); // expected-error{{int bad i}} Errors().fooOvl(short(0)); Errors().fooOvl(short(1)); // expected-error{{short bad i}} Errors().barOvl(0); Errors().barOvl(1); // expected-error{{int bad i}} Errors().barOvl(short(0)); Errors().barOvl(short(1)); // expected-error{{short bad i}} } template 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().foo(0); Warnings().foo(1); // expected-warning{{bad i}} Warnings().bar(0); Warnings().bar(1); // expected-warning{{bad i}} Warnings().fooOvl(0); Warnings().fooOvl(1); // expected-warning{{int bad i}} Warnings().fooOvl(short(0)); Warnings().fooOvl(short(1)); // expected-warning{{short bad i}} Warnings().barOvl(0); Warnings().barOvl(1); // expected-warning{{int bad i}} Warnings().barOvl(short(0)); Warnings().barOvl(short(1)); // expected-warning{{short bad i}} } } namespace template_specialization { template 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 { void foo(); void bar(int i); void baz(int i) _diagnose_if(i, "bad i", "error"); // expected-note{{from 'diagnose_if'}} }; void runAll() { Foo().foo(); // expected-error{{override me}} Foo().foo(); Foo().bar(1); // expected-error{{bad i}} Foo().bar(1); Foo().baz(1); Foo().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 T getVal() _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}} return T(); } template constexpr T getVal2() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}} return T(); } template 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() + getVal2() + int(*this); } }; void run() { Foo(0).getVal(); Foo(1).getVal(); // expected-error{{oh no}} Foo(0).getVal2(); Foo(1).getVal2(); // 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 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 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 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{}}; Foo{std::initializer_list{1}}; // expected-warning{{oh no}} Foo{std::initializer_list{1, 2}}; // expected-error{{oh no}} Foo{std::initializer_list{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}} } }