diff options
Diffstat (limited to 'clang/test/CXX')
-rw-r--r-- | clang/test/CXX/drs/dr15xx.cpp | 132 | ||||
-rw-r--r-- | clang/test/CXX/drs/dr5xx.cpp | 11 | ||||
-rw-r--r-- | clang/test/CXX/expr/expr.const/p2-0x.cpp | 18 | ||||
-rw-r--r-- | clang/test/CXX/over/over.built/p15.cpp | 83 | ||||
-rw-r--r-- | clang/test/CXX/over/over.built/p16.cpp | 75 |
5 files changed, 302 insertions, 17 deletions
diff --git a/clang/test/CXX/drs/dr15xx.cpp b/clang/test/CXX/drs/dr15xx.cpp index 5f85a196fd6..2b4c900c766 100644 --- a/clang/test/CXX/drs/dr15xx.cpp +++ b/clang/test/CXX/drs/dr15xx.cpp @@ -3,9 +3,137 @@ // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -#if __cplusplus < 201103L -// expected-no-diagnostics +namespace dr1512 { // dr1512: 4.0 + void f(char *p) { + if (p > 0) {} // expected-error {{ordered comparison between pointer and zero}} +#if __cplusplus >= 201103L + if (p > nullptr) {} // expected-error {{invalid operands}} #endif + } + bool g(int **x, const int **y) { + return x < y; + } + + template<typename T> T val(); + + template<typename A, typename B, typename C> void composite_pointer_type_is_base() { + typedef __typeof(true ? val<A>() : val<B>()) type; + typedef C type; + + typedef __typeof(val<A>() == val<B>()) cmp; + typedef __typeof(val<A>() != val<B>()) cmp; + typedef bool cmp; + } + + template<typename A, typename B, typename C> void composite_pointer_type_is_ord() { + composite_pointer_type_is_base<A, B, C>(); + + typedef __typeof(val<A>() < val<B>()) cmp; + typedef __typeof(val<A>() <= val<B>()) cmp; + typedef __typeof(val<A>() > val<B>()) cmp; + typedef __typeof(val<A>() >= val<B>()) cmp; + typedef bool cmp; + } + + template <typename A, typename B, typename C> + void composite_pointer_type_is_unord(int = 0) { + composite_pointer_type_is_base<A, B, C>(); + } + template <typename A, typename B, typename C> + void composite_pointer_type_is_unord(__typeof(val<A>() < val<B>()) * = 0); + template <typename A, typename B, typename C> + void composite_pointer_type_is_unord(__typeof(val<A>() <= val<B>()) * = 0); + template <typename A, typename B, typename C> + void composite_pointer_type_is_unord(__typeof(val<A>() > val<B>()) * = 0); + template <typename A, typename B, typename C> + void composite_pointer_type_is_unord(__typeof(val<A>() >= val<B>()) * = 0); + + // A call to this is ambiguous if a composite pointer type exists. + template<typename A, typename B> + void no_composite_pointer_type(__typeof((true ? val<A>() : val<B>()), void()) * = 0); + template<typename A, typename B> void no_composite_pointer_type(int = 0); + + struct A {}; + struct B : A {}; + struct C {}; + + void test() { +#if __cplusplus >= 201103L + using nullptr_t = decltype(nullptr); + composite_pointer_type_is_unord<nullptr_t, nullptr_t, nullptr_t>(); + no_composite_pointer_type<nullptr_t, int>(); + + composite_pointer_type_is_unord<nullptr_t, const char**, const char**>(); + composite_pointer_type_is_unord<const char**, nullptr_t, const char**>(); +#endif + + composite_pointer_type_is_ord<const int *, volatile void *, const volatile void*>(); + composite_pointer_type_is_ord<const void *, volatile int *, const volatile void*>(); + + composite_pointer_type_is_ord<const A*, volatile B*, const volatile A*>(); + composite_pointer_type_is_ord<const B*, volatile A*, const volatile A*>(); + + composite_pointer_type_is_unord<const int *A::*, volatile int *B::*, const volatile int *const B::*>(); + composite_pointer_type_is_unord<const int *B::*, volatile int *A::*, const volatile int *const B::*>(); + no_composite_pointer_type<int (A::*)(), int (C::*)()>(); + no_composite_pointer_type<const int (A::*)(), volatile int (C::*)()>(); + +#if __cplusplus > 201402 + composite_pointer_type_is_ord<int (*)() noexcept, int (*)(), int (*)()>(); + composite_pointer_type_is_ord<int (*)(), int (*)() noexcept, int (*)()>(); + composite_pointer_type_is_unord<int (A::*)() noexcept, int (A::*)(), int (A::*)()>(); + composite_pointer_type_is_unord<int (A::*)(), int (A::*)() noexcept, int (A::*)()>(); + // FIXME: This looks like a standard defect; these should probably all have type 'int (B::*)()'. + composite_pointer_type_is_unord<int (B::*)(), int (A::*)() noexcept, int (B::*)()>(); + composite_pointer_type_is_unord<int (A::*)() noexcept, int (B::*)(), int (B::*)()>(); + composite_pointer_type_is_unord<int (B::*)() noexcept, int (A::*)(), int (B::*)()>(); + composite_pointer_type_is_unord<int (A::*)(), int (B::*)() noexcept, int (B::*)()>(); + + // FIXME: It would be reasonable to permit these, with a common type of 'int (*const *)()'. + no_composite_pointer_type<int (**)() noexcept, int (**)()>(); + no_composite_pointer_type<int (**)(), int (**)() noexcept>(); + + // FIXME: It would be reasonable to permit these, with a common type of 'int (A::*)()'. + no_composite_pointer_type<int (A::*)() const, int (A::*)()>(); + no_composite_pointer_type<int (A::*)(), int (A::*)() const>(); + + // FIXME: It would be reasonable to permit these, with a common type of + // 'int (A::*)() &' and 'int (A::*)() &&', respectively. + no_composite_pointer_type<int (A::*)() &, int (A::*)()>(); + no_composite_pointer_type<int (A::*)(), int (A::*)() &>(); + no_composite_pointer_type<int (A::*)() &&, int (A::*)()>(); + no_composite_pointer_type<int (A::*)(), int (A::*)() &&>(); + + no_composite_pointer_type<int (A::*)() &&, int (A::*)() &>(); + no_composite_pointer_type<int (A::*)() &, int (A::*)() &&>(); + + no_composite_pointer_type<int (C::*)(), int (A::*)() noexcept>(); + no_composite_pointer_type<int (A::*)() noexcept, int (C::*)()>(); +#endif + } + + template<typename T> struct Wrap { operator T(); }; + void test_overload() { +#if __cplusplus >= 201103L + using nullptr_t = decltype(nullptr); + void(Wrap<nullptr_t>() == Wrap<nullptr_t>()); + void(Wrap<nullptr_t>() != Wrap<nullptr_t>()); + void(Wrap<nullptr_t>() < Wrap<nullptr_t>()); // expected-error {{invalid operands}} + void(Wrap<nullptr_t>() > Wrap<nullptr_t>()); // expected-error {{invalid operands}} + void(Wrap<nullptr_t>() <= Wrap<nullptr_t>()); // expected-error {{invalid operands}} + void(Wrap<nullptr_t>() >= Wrap<nullptr_t>()); // expected-error {{invalid operands}} + + // The wording change fails to actually disallow this. This is valid + // via the builtin operator<(int*, int*) etc. + void(Wrap<nullptr_t>() == Wrap<int*>()); + void(Wrap<nullptr_t>() != Wrap<int*>()); + void(Wrap<nullptr_t>() < Wrap<int*>()); + void(Wrap<nullptr_t>() > Wrap<int*>()); + void(Wrap<nullptr_t>() <= Wrap<int*>()); + void(Wrap<nullptr_t>() >= Wrap<int*>()); +#endif + } +} namespace dr1550 { // dr1550: yes int f(bool b, int n) { diff --git a/clang/test/CXX/drs/dr5xx.cpp b/clang/test/CXX/drs/dr5xx.cpp index 6461712cf0a..9bac7005797 100644 --- a/clang/test/CXX/drs/dr5xx.cpp +++ b/clang/test/CXX/drs/dr5xx.cpp @@ -863,14 +863,13 @@ namespace dr580 { // dr580: partial // dr582: na -namespace dr583 { // dr583: no +namespace dr583 { // dr583: 4.0 // see n3624 int *p; - // FIXME: These are all ill-formed. - bool b1 = p < 0; - bool b2 = p > 0; - bool b3 = p <= 0; - bool b4 = p >= 0; + bool b1 = p < 0; // expected-error {{ordered comparison between pointer and zero}} + bool b2 = p > 0; // expected-error {{ordered comparison between pointer and zero}} + bool b3 = p <= 0; // expected-error {{ordered comparison between pointer and zero}} + bool b4 = p >= 0; // expected-error {{ordered comparison between pointer and zero}} } // dr584: na diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp index fd15960647c..b9927e49c71 100644 --- a/clang/test/CXX/expr/expr.const/p2-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp @@ -461,14 +461,14 @@ namespace UnspecifiedRelations { constexpr bool u2 = p > q; // expected-error {{constant expression}} constexpr bool u3 = p <= q; // expected-error {{constant expression}} constexpr bool u4 = p >= q; // expected-error {{constant expression}} - constexpr bool u5 = p < 0; // expected-error {{constant expression}} - constexpr bool u6 = p <= 0; // expected-error {{constant expression}} - constexpr bool u7 = p > 0; // expected-error {{constant expression}} - constexpr bool u8 = p >= 0; // expected-error {{constant expression}} - constexpr bool u9 = 0 < q; // expected-error {{constant expression}} - constexpr bool u10 = 0 <= q; // expected-error {{constant expression}} - constexpr bool u11 = 0 > q; // expected-error {{constant expression}} - constexpr bool u12 = 0 >= q; // expected-error {{constant expression}} + constexpr bool u5 = p < (int*)0; // expected-error {{constant expression}} + constexpr bool u6 = p <= (int*)0; // expected-error {{constant expression}} + constexpr bool u7 = p > (int*)0; // expected-error {{constant expression}} + constexpr bool u8 = p >= (int*)0; // expected-error {{constant expression}} + constexpr bool u9 = (int*)0 < q; // expected-error {{constant expression}} + constexpr bool u10 = (int*)0 <= q; // expected-error {{constant expression}} + constexpr bool u11 = (int*)0 > q; // expected-error {{constant expression}} + constexpr bool u12 = (int*)0 >= q; // expected-error {{constant expression}} void f(), g(); constexpr void (*pf)() = &f, (*pg)() = &g; @@ -522,7 +522,7 @@ namespace UnspecifiedRelations { constexpr void *null = 0; constexpr void *pv = (void*)&s.a; constexpr void *qv = (void*)&s.b; - constexpr bool v1 = null < 0; + constexpr bool v1 = null < (int*)0; constexpr bool v2 = null < pv; // expected-error {{constant expression}} constexpr bool v3 = null == pv; // ok constexpr bool v4 = qv == pv; // ok diff --git a/clang/test/CXX/over/over.built/p15.cpp b/clang/test/CXX/over/over.built/p15.cpp new file mode 100644 index 00000000000..64ed3e7b83d --- /dev/null +++ b/clang/test/CXX/over/over.built/p15.cpp @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare + +struct A { operator decltype(nullptr)(); }; +struct B { operator const int *(); }; +void f(A a, B b, volatile int *pi) { + (void)(a == a); + (void)(a != a); + (void)(a < a); // expected-error {{invalid operands}} + (void)(a > a); // expected-error {{invalid operands}} + (void)(a <= a); // expected-error {{invalid operands}} + (void)(a >= a); // expected-error {{invalid operands}} + + (void)(a == b); + (void)(a != b); + // FIXME: These cases were intended to be made ill-formed by N3624, but it + // fails to actually achieve this goal. + (void)(a < b); + (void)(a > b); + (void)(a <= b); + (void)(a >= b); + + (void)(b == a); + (void)(b != a); + // FIXME: These cases were intended to be made ill-formed by N3624, but it + // fails to actually achieve this goal. + (void)(b < a); + (void)(b > a); + (void)(b <= a); + (void)(b >= a); + + (void)(a == pi); + (void)(a != pi); + // FIXME: These cases were intended to be made ill-formed by N3624, but it + // fails to actually achieve this goal. + (void)(a < pi); + (void)(a > pi); + (void)(a <= pi); + (void)(a >= pi); + + (void)(pi == a); + (void)(pi != a); + // FIXME: These cases were intended to be made ill-formed by N3624, but it + // fails to actually achieve this goal. + (void)(pi < a); + (void)(pi > a); + (void)(pi <= a); + (void)(pi >= a); + + (void)(b == pi); + (void)(b != pi); + (void)(b < pi); + (void)(b > pi); + (void)(b <= pi); + (void)(b >= pi); + + (void)(pi == b); + (void)(pi != b); + (void)(pi < b); + (void)(pi > b); + (void)(pi <= b); + (void)(pi >= b); + + (void)(b == b); + (void)(b != b); + (void)(b < b); + (void)(b > b); + (void)(b <= b); + (void)(b >= b); + + (void)(pi == pi); + (void)(pi != pi); + (void)(pi < pi); + (void)(pi > pi); + (void)(pi <= pi); + (void)(pi >= pi); +} + +// FIXME: This is wrong: the type T = 'const volatile int * const * const *' +// would work here, and there exists a builtin candidate for that type. +struct C { operator const int ***(); }; +void g(C c, volatile int ***p) { + (void)(c < p); // expected-error {{invalid operands}} +} diff --git a/clang/test/CXX/over/over.built/p16.cpp b/clang/test/CXX/over/over.built/p16.cpp new file mode 100644 index 00000000000..139e8644752 --- /dev/null +++ b/clang/test/CXX/over/over.built/p16.cpp @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare + +struct A { operator decltype(nullptr)(); }; +struct B { operator int A::*(); }; +void f(A a, B b, int A::*pi) { + (void)(a == a); + (void)(a != a); + (void)(a < a); // expected-error {{invalid operands}} + (void)(a > a); // expected-error {{invalid operands}} + (void)(a <= a); // expected-error {{invalid operands}} + (void)(a >= a); // expected-error {{invalid operands}} + + (void)(a == b); + (void)(a != b); + (void)(a < b); // expected-error {{invalid operands}} + (void)(a > b); // expected-error {{invalid operands}} + (void)(a <= b); // expected-error {{invalid operands}} + (void)(a >= b); // expected-error {{invalid operands}} + + (void)(b == a); + (void)(b != a); + (void)(b < a); // expected-error {{invalid operands}} + (void)(b > a); // expected-error {{invalid operands}} + (void)(b <= a); // expected-error {{invalid operands}} + (void)(b >= a); // expected-error {{invalid operands}} + + (void)(a == pi); + (void)(a != pi); + (void)(a < pi); // expected-error {{invalid operands}} + (void)(a > pi); // expected-error {{invalid operands}} + (void)(a <= pi); // expected-error {{invalid operands}} + (void)(a >= pi); // expected-error {{invalid operands}} + + (void)(pi == a); + (void)(pi != a); + (void)(pi < a); // expected-error {{invalid operands}} + (void)(pi > a); // expected-error {{invalid operands}} + (void)(pi <= a); // expected-error {{invalid operands}} + (void)(pi >= a); // expected-error {{invalid operands}} + + (void)(b == pi); + (void)(b != pi); + (void)(b < pi); // expected-error {{invalid operands}} + (void)(b > pi); // expected-error {{invalid operands}} + (void)(b <= pi); // expected-error {{invalid operands}} + (void)(b >= pi); // expected-error {{invalid operands}} + + (void)(pi == b); + (void)(pi != b); + (void)(pi < b); // expected-error {{invalid operands}} + (void)(pi > b); // expected-error {{invalid operands}} + (void)(pi <= b); // expected-error {{invalid operands}} + (void)(pi >= b); // expected-error {{invalid operands}} + + (void)(b == b); + (void)(b != b); + (void)(b < b); // expected-error {{invalid operands}} + (void)(b > b); // expected-error {{invalid operands}} + (void)(b <= b); // expected-error {{invalid operands}} + (void)(b >= b); // expected-error {{invalid operands}} + + (void)(pi == pi); + (void)(pi != pi); + (void)(pi < pi); // expected-error {{invalid operands}} + (void)(pi > pi); // expected-error {{invalid operands}} + (void)(pi <= pi); // expected-error {{invalid operands}} + (void)(pi >= pi); // expected-error {{invalid operands}} +} + +// FIXME: This is wrong: type T = 'const volatile int * const A::* const B::*' +// would work here, and there exists a builtin candidate for that type. +struct C { operator const int *A::*B::*(); }; +void g(C c, volatile int *A::*B::*p) { + (void)(c == p); // expected-error {{invalid operands}} +} |