// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 -pedantic %s
// C++ [expr.const]p1:
//   In several places, C++ requires expressions that evaluate to an integral
//   or enumeration constant: as array bounds, as case expressions, as
//   bit-field lengths, as enumerator initializers, as static member
//   initializers, and as integral or enumeration non-type template arguments.
//   An integral constant-expression can involve only literals, enumerators,
//   const variables or static data members of integral or enumeration types
//   initialized with constant expressions, and sizeof expressions. Floating
//   literals can appear only if they are cast to integral or enumeration types.

enum Enum { eval = 1 };
const int cval = 2;
const Enum ceval = eval;
struct Struct {
  static const int sval = 3;
  static const Enum seval = eval;
};

template <int itval, Enum etval> struct C {
  enum E {
    v1 = 1,
    v2 = eval,
    v3 = cval,
    v4 = ceval,
    v5 = Struct::sval,
    v6 = Struct::seval,
    v7 = itval,
    v8 = etval,
    v9 = (int)1.5,
    v10 = sizeof(Struct),
    v11 = true? 1 + cval * Struct::sval ^ itval / (int)1.5 - sizeof(Struct) : 0
  };
  unsigned
    b1 : 1,
    b2 : eval,
    b3 : cval,
    b4 : ceval,
    b5 : Struct::sval,
    b6 : Struct::seval,
    b7 : itval,
    b8 : etval,
    b9 : (int)1.5,
    b10 : sizeof(Struct),
    b11 : true? 1 + cval * Struct::sval ^ itval / (int)1.5 - sizeof(Struct) : 0
    ;
  static const int
    i1 = 1,
    i2 = eval,
    i3 = cval,
    i4 = ceval,
    i5 = Struct::sval,
    i6 = Struct::seval,
    i7 = itval,
    i8 = etval,
    i9 = (int)1.5,
    i10 = sizeof(Struct),
    i11 = true? 1 + cval * Struct::sval ^ itval / (int)1.5 - sizeof(Struct) : 0
    ;
  void f(int cond) {
    switch(cond) {
    case    0 + 1:
    case  100 + eval:
    case  200 + cval:
    case  300 + ceval:
    case  400 + Struct::sval:
    case  500 + Struct::seval:
    case  600 + itval:
    case  700 + etval:
    case  800 + (int)1.5:
    case  900 + sizeof(Struct):
    case 1000 + (true? 1 + cval * Struct::sval ^
                 itval / (int)1.5 - sizeof(Struct) : 0):
      ;
    }
  }
  typedef C<itval, etval> T0;
};

template struct C<1, eval>;
template struct C<cval, ceval>;
template struct C<Struct::sval, Struct::seval>;

enum {
  a = sizeof(int) == 8,
  b = a? 8 : 4
};

void diags(int n) {
  switch (n) {
    case (1/0, 1): // expected-error {{not an integral constant expression}} expected-note {{division by zero}}
    case (int)(1/0, 2.0): // expected-error {{not an integral constant expression}} expected-note {{division by zero}}
    case __imag(1/0): // expected-error {{not an integral constant expression}} expected-note {{division by zero}}
    case (int)__imag((double)(1/0)): // expected-error {{not an integral constant expression}} expected-note {{division by zero}}
      ;
  }
}

namespace IntOrEnum {
  const int k = 0;
  const int &p = k;
  template<int n> struct S {};
  S<p> s; // expected-error {{not an integral constant expression}}
}

extern const int recurse1;
// recurse2 cannot be used in a constant expression because it is not
// initialized by a constant expression. The same expression appearing later in
// the TU would be a constant expression, but here it is not.
const int recurse2 = recurse1;
const int recurse1 = 1;
int array1[recurse1]; // ok
int array2[recurse2]; // expected-warning {{variable length array}} expected-warning {{integer constant expression}}

namespace FloatConvert {
  typedef int a[(int)42.3];
  typedef int a[(int)42.997];
  typedef int b[(long long)4e20]; // expected-warning {{variable length}} expected-error {{variable length}} expected-warning {{'long long' is a C++11 extension}}
}

// PR12626
namespace test3 {
  struct X; // expected-note {{forward declaration of 'test3::X'}}
  struct Y { bool b; X x; }; // expected-error {{field has incomplete type 'test3::X'}}
  int f() { return Y().b; }
}

// PR18283
namespace test4 {
  template <int> struct A {};
  int const i = { 42 };
  // i can be used as non-type template-parameter as "const int x = { 42 };" is
  // equivalent to "const int x = 42;" as per C++03 8.5/p13.
  typedef A<i> Ai; // ok
}

// rdar://16064952
namespace rdar16064952 {
  template < typename T > void fn1() {
   T b;
   unsigned w = ({int a = b.val[sizeof(0)]; 0; }); // expected-warning {{use of GNU statement expression extension}}
  }
}
