Files
clang-p2996/clang/test/AST/Interp/shifts.cpp
Timm Bäder 39fd3fcd45 [clang][Interp] Don't fail on shifts greater than type bitwidth
We need to limit the shift width to the type bitwidth, then do the
shift and report success, but still diagnose what we limited the
shiftwidth.
2024-02-20 11:32:37 +01:00

201 lines
12 KiB
C++

// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=cxx17 %s
// RUN: %clang_cc1 -std=c++20 -verify=ref %s
// RUN: %clang_cc1 -std=c++17 -verify=ref-cxx17 %s
#define INT_MIN (~__INT_MAX__)
namespace shifts {
constexpr void test() { // ref-error {{constexpr function never produces a constant expression}} \
// ref-cxx17-error {{constexpr function never produces a constant expression}} \
// expected-error {{constexpr function never produces a constant expression}} \
// cxx17-error {{constexpr function never produces a constant expression}} \
char c; // cxx17-warning {{uninitialized variable}} \
// ref-cxx17-warning {{uninitialized variable}}
c = 0 << 0;
c = 0 << 1;
c = 1 << 0;
c = 1 << -0;
c = 1 >> -0;
c = 1 << -1; // expected-warning {{shift count is negative}} \
// expected-note {{negative shift count -1}} \
// cxx17-note {{negative shift count -1}} \
// cxx17-warning {{shift count is negative}} \
// ref-warning {{shift count is negative}} \
// ref-note {{negative shift count -1}} \
// ref-cxx17-warning {{shift count is negative}} \
// ref-cxx17-note {{negative shift count -1}}
c = 1 >> -1; // expected-warning {{shift count is negative}} \
// cxx17-warning {{shift count is negative}} \
// ref-warning {{shift count is negative}} \
// ref-cxx17-warning {{shift count is negative}}
c = 1 << (unsigned)-1; // expected-warning {{shift count >= width of type}} \
// expected-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} \
// cxx17-warning {{shift count >= width of type}} \
// cxx17-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} \
// ref-warning {{shift count >= width of type}} \
// ref-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} \
// ref-cxx17-warning {{shift count >= width of type}} \
// ref-cxx17-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}}
c = 1 >> (unsigned)-1; // expected-warning {{shift count >= width of type}} \
// cxx17-warning {{shift count >= width of type}} \
// ref-warning {{shift count >= width of type}} \
// ref-cxx17-warning {{shift count >= width of type}}
c = 1 << c;
c <<= 0;
c >>= 0;
c <<= 1;
c >>= 1;
c <<= -1; // expected-warning {{shift count is negative}} \
// cxx17-warning {{shift count is negative}} \
// ref-warning {{shift count is negative}} \
// ref-cxx17-warning {{shift count is negative}}
c >>= -1; // expected-warning {{shift count is negative}} \
// cxx17-warning {{shift count is negative}} \
// ref-warning {{shift count is negative}} \
// ref-cxx17-warning {{shift count is negative}}
c <<= 999999; // expected-warning {{shift count >= width of type}} \
// cxx17-warning {{shift count >= width of type}} \
// ref-warning {{shift count >= width of type}} \
// ref-cxx17-warning {{shift count >= width of type}}
c >>= 999999; // expected-warning {{shift count >= width of type}} \
// cxx17-warning {{shift count >= width of type}} \
// ref-warning {{shift count >= width of type}} \
// ref-cxx17-warning {{shift count >= width of type}}
c <<= __CHAR_BIT__; // expected-warning {{shift count >= width of type}} \
// cxx17-warning {{shift count >= width of type}} \
// ref-warning {{shift count >= width of type}} \
// ref-cxx17-warning {{shift count >= width of type}}
c >>= __CHAR_BIT__; // expected-warning {{shift count >= width of type}} \
// cxx17-warning {{shift count >= width of type}} \
// ref-warning {{shift count >= width of type}} \
// ref-cxx17-warning {{shift count >= width of type}}
c <<= __CHAR_BIT__+1; // expected-warning {{shift count >= width of type}} \
// cxx17-warning {{shift count >= width of type}} \
// ref-warning {{shift count >= width of type}} \
// ref-cxx17-warning {{shift count >= width of type}}
c >>= __CHAR_BIT__+1; // expected-warning {{shift count >= width of type}} \
// cxx17-warning {{shift count >= width of type}} \
// ref-warning {{shift count >= width of type}} \
// ref-cxx17-warning {{shift count >= width of type}}
(void)((long)c << __CHAR_BIT__);
int i; // cxx17-warning {{uninitialized variable}} \
// ref-cxx17-warning {{uninitialized variable}}
i = 1 << (__INT_WIDTH__ - 2);
i = 2 << (__INT_WIDTH__ - 1); // cxx17-warning {{bits to represent, but 'int' only has}} \
// ref-cxx17-warning {{bits to represent, but 'int' only has}}
i = 1 << (__INT_WIDTH__ - 1); // cxx17-warning-not {{sets the sign bit of the shift expression}}
i = -1 << (__INT_WIDTH__ - 1); // cxx17-warning {{shifting a negative signed value is undefined}} \
// ref-cxx17-warning {{shifting a negative signed value is undefined}}
i = -1 << 0; // cxx17-warning {{shifting a negative signed value is undefined}} \
// ref-cxx17-warning {{shifting a negative signed value is undefined}}
i = 0 << (__INT_WIDTH__ - 1);
i = (char)1 << (__INT_WIDTH__ - 2);
unsigned u; // cxx17-warning {{uninitialized variable}} \
// ref-cxx17-warning {{uninitialized variable}}
u = 1U << (__INT_WIDTH__ - 1);
u = 5U << (__INT_WIDTH__ - 1);
long long int lli; // cxx17-warning {{uninitialized variable}} \
// ref-cxx17-warning {{uninitialized variable}}
lli = INT_MIN << 2; // cxx17-warning {{shifting a negative signed value is undefined}} \
// ref-cxx17-warning {{shifting a negative signed value is undefined}}
lli = 1LL << (sizeof(long long) * __CHAR_BIT__ - 2);
}
static_assert(1 << 4 == 16, "");
constexpr unsigned m = 2 >> 1;
static_assert(m == 1, "");
constexpr unsigned char c = 0 << 8;
static_assert(c == 0, "");
static_assert(true << 1, "");
static_assert(1 << (__INT_WIDTH__ +1) == 0, ""); // expected-error {{not an integral constant expression}} \
// expected-note {{>= width of type 'int'}} \
// cxx17-error {{not an integral constant expression}} \
// cxx17-note {{>= width of type 'int'}} \
// ref-error {{not an integral constant expression}} \
// ref-note {{>= width of type 'int'}} \
// ref-cxx17-error {{not an integral constant expression}} \
// ref-cxx17-note {{>= width of type 'int'}}
constexpr int i1 = 1 << -1; // expected-error {{must be initialized by a constant expression}} \
// expected-note {{negative shift count -1}} \
// cxx17-error {{must be initialized by a constant expression}} \
// cxx17-note {{negative shift count -1}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{negative shift count -1}} \
// ref-cxx17-error {{must be initialized by a constant expression}} \
// ref-cxx17-note {{negative shift count -1}}
constexpr int i2 = 1 << (__INT_WIDTH__ + 1); // expected-error {{must be initialized by a constant expression}} \
// expected-note {{>= width of type}} \
// cxx17-error {{must be initialized by a constant expression}} \
// cxx17-note {{>= width of type}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{>= width of type}} \
// ref-cxx17-error {{must be initialized by a constant expression}} \
// ref-cxx17-note {{>= width of type}}
constexpr char c2 = 1;
constexpr int i3 = c2 << (__CHAR_BIT__ + 1); // Not ill-formed
/// The purpose of these few lines is to test that we can shift more bits
/// than an unsigned *of the host* has. There was a bug where we casted
/// to host-unsigned. However, we cannot query what a host-unsigned even is
/// here, so only test this on platforms where `sizeof(long long) > sizeof(unsigned)`.
constexpr long long int L = 1;
constexpr signed int R = (sizeof(unsigned) * 8) + 1;
constexpr decltype(L) M = (R > 32 && R < 64) ? L << R : 0;
constexpr decltype(L) M2 = (R > 32 && R < 64) ? L >> R : 0;
constexpr int signedShift() { // cxx17-error {{never produces a constant expression}} \
// ref-cxx17-error {{never produces a constant expression}}
return 1024 << 31; // cxx17-warning {{signed shift result}} \
// ref-cxx17-warning {{signed shift result}} \
// cxx17-note {{signed left shift discards bits}} \
// ref-cxx17-note {{signed left shift discards bits}}
}
constexpr int negativeShift() { // cxx17-error {{never produces a constant expression}} \
// ref-cxx17-error {{never produces a constant expression}}
return -1 << 2; // cxx17-warning {{shifting a negative signed value is undefined}} \
// ref-cxx17-warning {{shifting a negative signed value is undefined}} \
// cxx17-note {{left shift of negative value -1}} \
// ref-cxx17-note {{left shift of negative value -1}}
}
constexpr int foo(int a) {
return -a << 2; // cxx17-note {{left shift of negative value -10}} \
// ref-cxx17-note {{left shift of negative value -10}} \
// cxx17-note {{left shift of negative value -2}} \
// ref-cxx17-note {{left shift of negative value -2}}
}
static_assert(foo(10)); // cxx17-error {{not an integral constant expression}} \
// cxx17-note {{in call to 'foo(10)'}} \
// ref-cxx17-error {{not an integral constant expression}} \
// ref-cxx17-note {{in call to 'foo(10)'}}
constexpr int a = -2;
static_assert(foo(a));
static_assert(foo(-a)); // cxx17-error {{not an integral constant expression}} \
// cxx17-note {{in call to 'foo(2)'}} \
// ref-cxx17-error {{not an integral constant expression}} \
// ref-cxx17-note {{in call to 'foo(2)'}}
};
namespace LongInt {
constexpr int f() {
int a = 1;
a <<= (long)0;
return 1;
}
static_assert(f() == 1, "");
};