diff options
Diffstat (limited to 'test/SemaCXX/diagnose_if.cpp')
-rw-r--r-- | test/SemaCXX/diagnose_if.cpp | 313 |
1 files changed, 261 insertions, 52 deletions
diff --git a/test/SemaCXX/diagnose_if.cpp b/test/SemaCXX/diagnose_if.cpp index f97b79d03529..02b3620e7692 100644 --- a/test/SemaCXX/diagnose_if.cpp +++ b/test/SemaCXX/diagnose_if.cpp @@ -2,6 +2,8 @@ #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'}} @@ -51,14 +53,14 @@ void runAll() { } template <typename T> -void errorIf(T a) _diagnose_if(T() != a, "oh no", "error") {} // expected-note {{candidate disabled: oh no}} +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 warnIf(T a) _diagnose_if(T() != a, "oh no", "warning") {} // expected-note{{from 'diagnose_if'}} void runIf() { errorIf(0); - errorIf(1); // expected-error{{call to unavailable function}} + errorIf(1); // expected-error{{oh no}} warnIf(0); warnIf(1); // expected-warning{{oh no}} @@ -114,14 +116,14 @@ void runAll() { } template <int N> -void errorIf(int a) _diagnose_if(N != a, "oh no", "error") {} // expected-note {{candidate disabled: oh no}} +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 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{{call to unavailable function}} + errorIf<0>(1); // expected-error{{oh no}} warnIf<0>(0); warnIf<0>(1); // expected-warning{{oh no}} @@ -135,8 +137,8 @@ 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{{candidate disabled: oh no}} -void fooArg(short); // expected-note{{candidate function}} +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"); @@ -145,7 +147,7 @@ void runAll() { foo(1); // expected-error{{oh no}} bar(1); - fooArg(1); // expected-error{{call to unavailable function}} + fooArg(1); // expected-error{{oh no}} barArg(1); auto p = foo; // expected-error{{incompatible initializer of type '<overloaded function type>'}} @@ -188,11 +190,11 @@ 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 2{{int bad i}} - void fooOvl(short i) _diagnose_if(i, "short bad i", "error"); // expected-note 2{{short bad i}} + 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 2{{int bad i}} - void barOvl(short i) _diagnose_if(i != T(), "short bad i", "error"); // expected-note 2{{short bad i}} + 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() { @@ -203,14 +205,14 @@ void runErrors() { Errors<int>().bar(1); // expected-error{{bad i}} Errors<int>().fooOvl(0); - Errors<int>().fooOvl(1); // expected-error{{call to unavailable}} + Errors<int>().fooOvl(1); // expected-error{{int bad i}} Errors<int>().fooOvl(short(0)); - Errors<int>().fooOvl(short(1)); // expected-error{{call to unavailable}} + Errors<int>().fooOvl(short(1)); // expected-error{{short bad i}} Errors<int>().barOvl(0); - Errors<int>().barOvl(1); // expected-error{{call to unavailable}} + Errors<int>().barOvl(1); // expected-error{{int bad i}} Errors<int>().barOvl(short(0)); - Errors<int>().barOvl(short(1)); // expected-error{{call to unavailable}} + Errors<int>().barOvl(short(1)); // expected-error{{short bad i}} } template <typename T> @@ -275,8 +277,8 @@ namespace late_constexpr { constexpr int foo(); constexpr int foo(int a); -void bar() _diagnose_if(foo(), "bad foo", "error"); // expected-note{{from 'diagnose_if'}} expected-note{{not viable: requires 0 arguments}} -void bar(int a) _diagnose_if(foo(a), "bad foo", "error"); // expected-note{{bad foo}} +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(); @@ -290,7 +292,7 @@ constexpr int foo(int a) { return a; } void late() { bar(); // expected-error{{bad foo}} bar(0); - bar(1); // expected-error{{call to unavailable function}} + bar(1); // expected-error{{bad foo}} } } @@ -301,11 +303,11 @@ struct Foo { 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{{oh no}} + 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{{oh no}} + 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") {} // expected-note{{oh no}} + void go2() const _diagnose_if(isFooable(), "oh no", "error") {} constexpr int go3() const _diagnose_if(isFooable(), "oh no", "error") __attribute__((enable_if(true, ""))) { @@ -326,20 +328,20 @@ struct Foo { } }; -void go(const Foo &f) _diagnose_if(f.isFooable(), "oh no", "error") {} // expected-note{{oh no}} +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{{uses deleted function}} + (void)int(Foo(1)); // expected-error{{oh no}} Foo(0).go2(); - Foo(1).go2(); // expected-error{{call to unavailable member function}} + Foo(1).go2(); // expected-error{{oh no}} go(Foo(0)); - go(Foo(1)); // expected-error{{call to unavailable function}} + go(Foo(1)); // expected-error{{oh no}} } } @@ -349,17 +351,17 @@ struct Foo { 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{{oh no}} + 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{{oh no}} + 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{{oh no}} + constexpr operator T() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}} return T(); } @@ -369,13 +371,13 @@ struct Foo { void run() { Foo(0).getVal<int>(); - Foo(1).getVal<int>(); // expected-error{{call to unavailable member function}} + Foo(1).getVal<int>(); // expected-error{{oh no}} Foo(0).getVal2<int>(); - Foo(1).getVal2<int>(); // expected-error{{call to unavailable member function}} + Foo(1).getVal2<int>(); // expected-error{{oh no}} (void)int(Foo(0)); - (void)int(Foo(1)); // expected-error{{uses deleted function}} + (void)int(Foo(1)); // expected-error{{oh no}} } } @@ -385,18 +387,18 @@ 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{{oh no}} + 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{{oh no}} + 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 2{{oh no}} - void operator()(int) const _diagnose_if(bad(), "oh no", "error") {} // expected-note 2{{oh no}} + 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 { @@ -404,33 +406,70 @@ struct ParenTemplate { 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{{oh no}} + 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{{selected unavailable operator '->'}} + (void)Foo(1)->j; // expected-error{{oh no}} Foo(0)(); - Foo(1)(); // expected-error{{unavailable function call operator}} + Foo(1)(); // expected-error{{oh no}} ParenOverload(0)(1); ParenOverload(0)(1.); - ParenOverload(1)(1); // expected-error{{unavailable function call operator}} - ParenOverload(1)(1.); // expected-error{{unavailable function call operator}} + 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{{unavailable function call operator}} - ParenTemplate(1)(1.); // expected-error{{unavailable function call operator}} + 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{{oh no}} expected-note{{conversion candidate}} + auto L1 = [](int i) _diagnose_if(i, "oh no", "error") {}; // expected-note{{from 'diagnose_if'}} L1(0); - L1(1); // expected-error{{call to unavailable function call}} + 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}} } } @@ -439,22 +478,192 @@ struct Foo { int I; constexpr Foo(int I): I(I) {} - constexpr const Foo &operator=(const Foo &) const // expected-note 2{{disabled: oh no}} - _diagnose_if(I, "oh no", "error") { + 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 // expected-note{{disabled: oh no}} expected-note{{no known conversion}} - _diagnose_if(I, "oh no", "error") { + 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{{selected unavailable operator}} - F2 = Foo{2}; // expected-error{{selected unavailable operator}} + 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}} } } |