blob: a69eb83e591f56ee9f6f78046731ec9aa60e17cc [file]
// RUN: %clang_cc1 %s -Winteger-overflow -Wno-unused-value -fexperimental-overflow-behavior-types -Wconstant-conversion -Woverflow-behavior-conversion -verify -fsyntax-only
// RUN: %clang_cc1 %s -Winteger-overflow -Wno-unused-value -fexperimental-overflow-behavior-types -Wconstant-conversion -Woverflow-behavior-conversion -verify -fsyntax-only -fexperimental-new-constant-interpreter
typedef int __attribute__((overflow_behavior)) bad_arg_count; // expected-error {{'overflow_behavior' attribute takes one argument}}
typedef int __attribute__((overflow_behavior(not_real))) bad_arg_spec; // expected-error {{'not_real' is not a valid argument to attribute 'overflow_behavior'}}
typedef int __attribute__((overflow_behavior("not_real"))) bad_arg_spec_str; // expected-error {{'not_real' is not a valid argument to attribute 'overflow_behavior'}}
typedef char* __attribute__((overflow_behavior("wrap"))) bad_type; // expected-error {{'overflow_behavior' attribute cannot be applied to non-integer type 'char *'}}
typedef int __attribute__((overflow_behavior(wrap))) ok_wrap; // OK
typedef long __attribute__((overflow_behavior(trap))) ok_nowrap; // OK
typedef unsigned long __attribute__((overflow_behavior("wrap"))) str_ok_wrap; // OK
typedef char __attribute__((overflow_behavior("trap"))) str_ok_nowrap; // OK
struct struct_not_allowed {
int i;
} __attribute__((overflow_behavior(wrap))); // expected-warning {{'overflow_behavior' attribute only applies to variables, typedefs, and data members}}
void foo() {
(2147483647 + 100); // expected-warning {{overflow in expression; result is }}
(ok_wrap)2147483647 + 100; // no warn
}
// C++ stuff expects no warns
typedef int __attribute__((overflow_behavior(wrap))) wrap_int;
template <typename T>
T bar(T a) {
return 1UL;
}
void f() {
wrap_int a = 4;
bar(a);
}
class TestOverload {
public:
void operator<<(int other); // expected-note {{candidate function}}
void operator<<(char other); // expected-note {{candidate function}}
};
void test_overload1() {
wrap_int a = 4;
TestOverload TO;
TO << a; // expected-error {{use of overloaded operator '<<' is ambiguous}}
}
// expected-note@+1 {{candidate function}}
int add_one(long a) { // expected-note {{candidate function}}
return (a + 1);
}
// expected-note@+1 {{candidate function}}
int add_one(char a) { // expected-note {{candidate function}}
return (a + 1);
}
// expected-note@+1 {{candidate function}}
int add_one(int a) { // expected-note {{candidate function}}
return (a + 1);
}
void test_overload2(wrap_int a) {
// to be clear, this is the same ambiguity expected when using a non-OBT int type.
add_one(a); // expected-error {{call to 'add_one' is ambiguous}}
long __attribute__((overflow_behavior(trap))) b; // don't consider underlying type an exact match.
add_one(b); // expected-error {{call to 'add_one' is ambiguous}}
}
void func(__ob_trap int i);
void func(int i); // Overload, not invalid redeclaration
template <typename Ty>
void func2(__ob_trap Ty i) {} // expected-error {{__ob_trap specifier cannot be applied to non-integer type 'Ty'}}
template <typename Ty>
struct S {};
template <>
struct S<__ob_trap int> {};
template <>
struct S<int> {};
void ptr(int a) {
int __ob_trap *p = &a; // expected-error-re {{cannot initialize a variable of type '__ob_trap int *' {{.*}}with an rvalue of type 'int *'}}
}
void ptr2(__ob_trap int a) {
int *p = &a; // expected-error-re {{cannot initialize a variable of type 'int *' {{.*}}with an rvalue of type '__ob_trap int *'}}
}
void overloadme(__ob_trap int a); // expected-note {{candidate function}}
void overloadme(short a); // expected-note {{candidate function}}
void test_overload_ambiguity() {
int a;
overloadme(a); // expected-error {{call to 'overloadme' is ambiguous}}
}
void f(void) __attribute__((overflow_behavior(wrap))); // expected-error {{'overflow_behavior' attribute cannot be applied to non-integer type 'void (void)'}}
typedef float __attribute__((overflow_behavior(wrap))) wrap_float; // expected-error {{'overflow_behavior' attribute cannot be applied to non-integer type 'float'}}
void pointer_compatibility(int* i_ptr) {
__ob_trap int* nowrap_ptr;
// static_cast should fail.
nowrap_ptr = static_cast<__ob_trap int*>(i_ptr); // expected-error {{static_cast from 'int *' to '__ob_trap int *' is not allowed}}
// reinterpret_cast should succeed.
nowrap_ptr = reinterpret_cast<__ob_trap int*>(i_ptr);
(void)nowrap_ptr;
}
void cpp_constexpr_bracket_initialization() {
constexpr short cx1 = {(int __ob_wrap)100000}; // expected-error {{constant expression evaluates to 100000 which cannot be narrowed to type 'short'}}
// expected-note@-1 {{insert an explicit cast to silence this issue}}
constexpr short __ob_wrap cx2 = {100000}; // expected-error {{constant expression evaluates to 100000 which cannot be narrowed to type '__ob_wrap short'}}
constexpr short __ob_trap cx3 = {(int)100000}; // expected-error {{constant expression evaluates to 100000 which cannot be narrowed to type '__ob_trap short'}}
// expected-warning@-1 {{implicit conversion from 'int' to '__ob_trap short const' changes value from 100000 to -31072}}
constexpr short cx4 = {(int __ob_trap)100000}; // expected-error {{constant expression evaluates to 100000 which cannot be narrowed to type 'short'}}
// expected-warning@-1 {{implicit conversion from '__ob_trap int' to '__ob_trap const short' changes value from 100000 to -31072}}
// expected-note@-2 {{insert an explicit cast to silence this issue}}
}
// ensure that all qualifier placements result in the same canonical type
void test_qualifier_placements() {
using ConstInt = const int;
using WrapConstInt1 = ConstInt __attribute__((overflow_behavior(wrap)));
using WrapConstInt2 = const int __attribute__((overflow_behavior(wrap)));
typedef const int __ob_wrap const_int_wrap;
typedef int __ob_wrap const int_wrap_const;
typedef int __ob_trap const int_trap_const;
static_assert(__is_same(WrapConstInt1, WrapConstInt2));
static_assert(__is_same(const_int_wrap, int_wrap_const));
static_assert(!__is_same(const_int_wrap, int_trap_const));
}
void test_mixed_specifier_attribute() {
int __ob_wrap __attribute__((overflow_behavior(wrap))) a; // expected-warning {{redundant overflow behavior specification; both specifier and attribute specify 'wrap'}}
int __ob_trap __attribute__((overflow_behavior(trap))) b; // expected-warning {{redundant overflow behavior specification; both specifier and attribute specify 'trap'}}
int __ob_wrap __attribute__((overflow_behavior(trap))) c; // expected-error {{conflicting overflow behavior specification; specifier specifies 'wrap' but attribute specifies 'trap'}}
int __ob_trap __attribute__((overflow_behavior(wrap))) d; // expected-error {{conflicting overflow behavior specification; specifier specifies 'trap' but attribute specifies 'wrap'}}
int __ob_wrap e; // OK
int __attribute__((overflow_behavior(trap))) f; // OK
}
void test_incompatible_obt_initialization() {
int __ob_trap a = 10;
int __ob_wrap b = 20;
int __ob_wrap c = a; // expected-error {{cannot initialize a variable of type '__ob_wrap int' with an lvalue of type '__ob_trap int'}}
int __ob_trap d = b; // expected-error {{cannot initialize a variable of type '__ob_trap int' with an lvalue of type '__ob_wrap int'}}
}
void constant_conversion() {
short x1 = (int __ob_wrap)100000;
short __ob_wrap x2 = (int)100000; // No warning expected
// expected-warning@+1 {{implicit conversion from 'int' to '__ob_trap short' changes value from 100000 to -31072}}
short __ob_trap x3 = (int)100000;
// expected-warning@+1 {{implicit conversion from '__ob_trap int' to '__ob_trap short' changes value from 100000 to -31072}}
short x4 = (int __ob_trap)100000;
unsigned short __ob_wrap ux1 = (unsigned int)100000; // No warning - wrapping expected
unsigned short ux2 = (unsigned int __ob_wrap)100000;
unsigned short __ob_trap ux3 = (unsigned int)100000; // expected-warning {{implicit conversion from 'unsigned int' to '__ob_trap unsigned short' changes value from 100000 to 34464}}
unsigned short __ob_trap ux4 = (unsigned int __ob_trap)100000; // expected-warning {{implicit conversion from '__ob_trap unsigned int' to '__ob_trap unsigned short' changes value from 100000 to 34464}}
unsigned short __ob_trap ux5 = (unsigned int __ob_wrap)100000; // expected-error {{assigning to '__ob_trap unsigned short' from '__ob_wrap unsigned int' with incompatible overflow behavior types ('__ob_trap' and '__ob_wrap')}}
}
// OBT on data members (both static and non-static)
struct DataMembers {
__ob_wrap int nonstatic_specifier;
int __attribute__((overflow_behavior(wrap))) nonstatic_attr;
static __ob_trap int static_specifier;
static int __ob_wrap static_specifier2;
static int __attribute__((overflow_behavior(trap))) static_attr;
};
__ob_trap int DataMembers::static_specifier = 0;
int __ob_wrap DataMembers::static_specifier2 = 0;
int __attribute__((overflow_behavior(trap))) DataMembers::static_attr = 0;