llvm/clang/test/AST/ByteCode/shifts.cpp

// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify=expected,all %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=cxx17,all %s
// RUN: %clang_cc1 -std=c++20 -verify=ref,all %s
// RUN: %clang_cc1 -std=c++17 -verify=ref-cxx17,all %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, "");
};

enum shiftof {
    X = (1<<-29), // all-error {{expression is not an integral constant expression}} \
                  // all-note {{negative shift count -29}}

    X2 = (-1<<29), // cxx17-error {{expression is not an integral constant expression}} \
                   // cxx17-note {{left shift of negative value -1}} \
                   // ref-cxx17-error {{expression is not an integral constant expression}} \
                   // ref-cxx17-note {{left shift of negative value -1}}

    X3 = (1<<32) // all-error {{expression is not an integral constant expression}} \
                 // all-note {{shift count 32 >= width of type 'int'}}
};