// clang-format off
// REQUIRES: lld, x86

// Test that we can display tag types.
// RUN: %clang_cl --target=x86_64-windows-msvc -Od -Z7 \
// RUN:   -Xclang -fkeep-static-consts -c /Fo%t.obj -- %s
// RUN: lld-link -debug:full -nodefaultlib -entry:main %t.obj -out:%t.exe -pdb:%t.pdb
// RUN: %lldb -f %t.exe -s \
// RUN:     %p/Inputs/globals-classes.lldbinit | FileCheck %s

enum class EnumType : unsigned {
  A = 1,
  B = 2
};

class ClassNoPadding {
  /* [ 0] */ unsigned char a = 86;
  /* [ 1] */ char b = 'a';
  /* [ 2] */ bool c = false;
  /* [ 3] */ bool d = true;
  /* [ 4] */ short e = -1234;
  /* [ 6] */ unsigned short f = 8123;
  /* [ 8] */ unsigned int g = 123908;
  /* [12] */ int h = -890234;
  /* [16] */ unsigned long i = 2908234;
  /* [20] */ long j = 7234890;
  /* [24] */ float k = 908234.12392;
  /* [28] */ EnumType l = EnumType::A;
  /* [32] */ double m = 23890.897423;
  /* [40] */ unsigned long long n = 23490782;
  /* [48] */ long long o = -923409823;
  /* [56] */ int p[5] = { 2, 3, 5, 8, 13 };
};

class ClassWithPadding {
  /* [ 0] */ char a = '0';
  //         char padding[1];
  /* [ 2] */ short b = 50;
  /* [ 4] */ char c[2] = { '0', '1' };
  //         char padding[2];
  /* [ 8] */ int d = 100;
  /* [12] */ char e = '0';
  //         char padding[3];
  /* [16] */ int f = 200;
  //         char padding[4];
  /* [24] */ long long g = 300;
  /* [32] */ char h[3] = { '0', '1', '2' };
  //         char padding[5];
  /* [40] */ long long i = 400;
  /* [48] */ char j[2] = { '0', '1' };
  //         char padding[6];
  /* [56] */ long long k = 500;
  /* [64] */ char l = '0';
  //         char padding[7];
  /* [72] */ long long m = 600;
} ;

struct EmptyBase {};

template<typename T>
struct BaseClass {
  constexpr BaseClass(int N)
    : BaseMember(N) {}

  int BaseMember;
};

struct DerivedClass : public BaseClass<int> {
  constexpr DerivedClass(int Base, int Derived)
    : BaseClass(Base), DerivedMember(Derived) {}

  int DerivedMember;
};

struct EBO : public EmptyBase {
  constexpr EBO(int N) : Member(N) {}
  int Member;
};

struct PaddedBases : public BaseClass<char>, public BaseClass<short>, BaseClass<int> {
  constexpr PaddedBases(char CH, short S, int N, long long D)
    : BaseClass<char>(CH), BaseClass<short>(S), BaseClass<int>(N), DerivedMember(D) {}
  long long DerivedMember;
};

struct Statics {
  static char a;
  static bool b;
  static short c;
  static unsigned short d;
  static unsigned int e;
  static int f;
  static unsigned long g;
  static long h;
  static float i;
  static EnumType j;
  static double k;
  static unsigned long long l;
  static long long m;
};

char Statics::a = 'a';
bool Statics::b = true;
short Statics::c = 1234;
unsigned short Statics::d = 2345;
unsigned int Statics::e = 3456;
int Statics::f = 4567;
unsigned long Statics::g = 5678;
long Statics::h = 6789;
float Statics::i = 7890.1234;
EnumType Statics::j = EnumType::A;
double Statics::k = 8901.2345;
unsigned long long Statics::l = 9012345;
long long Statics::m = 1234567;


struct Pointers {
  void *a = nullptr;
  char *b = &Statics::a;
  bool *c = &Statics::b;
  short *e = &Statics::c;
  unsigned short *f = &Statics::d;
  unsigned int *g = &Statics::e;
  int *h = &Statics::f;
  unsigned long *i = &Statics::g;
  long *j = &Statics::h;
  float *k = &Statics::i;
  EnumType *l = &Statics::j;
  double *m = &Statics::k;
  unsigned long long *n = &Statics::l;
  long long *o = &Statics::m;
};

struct References {
  char &a = Statics::a;
  bool &b = Statics::b;
  short &c = Statics::c;
  unsigned short &d = Statics::d;
  unsigned int &e = Statics::e;
  int &f = Statics::f;
  unsigned long &g = Statics::g;
  long &h = Statics::h;
  float &i = Statics::i;
  EnumType &j = Statics::j;
  double &k = Statics::k;
  unsigned long long &l = Statics::l;
  long long &m = Statics::m;
};


constexpr ClassWithPadding ClassWithPaddingInstance;
// CHECK:      (lldb) target variable -T ClassWithPaddingInstance
// CHECK-NEXT: (const ClassWithPadding) ClassWithPaddingInstance = {
// CHECK-NEXT:   (char) a = '0'
// CHECK-NEXT:   (short) b = 50
// CHECK-NEXT:   (char[2]) c = "01"
// CHECK-NEXT:   (int) d = 100
// CHECK-NEXT:   (char) e = '0'
// CHECK-NEXT:   (int) f = 200
// CHECK-NEXT:   (long long) g = 300
// CHECK-NEXT:   (char[3]) h = "012"
// CHECK-NEXT:   (long long) i = 400
// CHECK-NEXT:   (char[2]) j = "01"
// CHECK-NEXT:   (long long) k = 500
// CHECK-NEXT:   (char) l = '0'
// CHECK-NEXT:   (long long) m = 600
// CHECK-NEXT: }

constexpr ClassNoPadding ClassNoPaddingInstance;
// CHECK:      (lldb) target variable -T ClassNoPaddingInstance
// CHECK-NEXT: (const ClassNoPadding) ClassNoPaddingInstance = {
// CHECK-NEXT:   (unsigned char) a = 'V'
// CHECK-NEXT:   (char) b = 'a'
// CHECK-NEXT:   (bool) c = false
// CHECK-NEXT:   (bool) d = true
// CHECK-NEXT:   (short) e = -1234
// CHECK-NEXT:   (unsigned short) f = 8123
// CHECK-NEXT:   (unsigned int) g = 123908
// CHECK-NEXT:   (int) h = -890234
// CHECK-NEXT:   (unsigned long) i = 2908234
// CHECK-NEXT:   (long) j = 7234890
// CHECK-NEXT:   (float) k = 908234.125
// CHECK-NEXT:   (EnumType) l = A
// CHECK-NEXT:   (double) m = 23890.897422999999
// CHECK-NEXT:   (unsigned long long) n = 23490782
// CHECK-NEXT:     (long long) o = -923409823
// CHECK-NEXT:     (int[5]) p = {
// CHECK-NEXT:       (int) [0] = 2
// CHECK-NEXT:       (int) [1] = 3
// CHECK-NEXT:       (int) [2] = 5
// CHECK-NEXT:       (int) [3] = 8
// CHECK-NEXT:       (int) [4] = 13
// CHECK-NEXT:     }
// CHECK-NEXT:   }

constexpr DerivedClass DC(10, 20);
// CHECK:      (lldb) target variable -T DC
// CHECK-NEXT: (const DerivedClass) DC = {
// CHECK-NEXT:   (BaseClass<int>) BaseClass<int> = {
// CHECK-NEXT:     (int) BaseMember = 10
// CHECK-NEXT:   }
// CHECK-NEXT:   (int) DerivedMember = 20
// CHECK-NEXT: }

constexpr EBO EBOC(20);
// CHECK:      (lldb) target variable -T EBOC
// CHECK-NEXT: (const EBO) EBOC = {
// CHECK-NEXT:   (int) Member = 20
// CHECK-NEXT: }

constexpr PaddedBases PBC('a', 12, 120, 1200);
// CHECK:      (lldb) target variable -T PBC
// CHECK-NEXT: (const PaddedBases) PBC = {
// CHECK-NEXT:   (BaseClass<char>) BaseClass<char> = {
// CHECK-NEXT:     (int) BaseMember = 97
// CHECK-NEXT:   }
// CHECK-NEXT:   (BaseClass<short>) BaseClass<short> = {
// CHECK-NEXT:     (int) BaseMember = 12
// CHECK-NEXT:   }
// CHECK-NEXT:   (BaseClass<int>) BaseClass<int> = {
// CHECK-NEXT:     (int) BaseMember = 120
// CHECK-NEXT:   }
// CHECK-NEXT:   (long long) DerivedMember = 1200
// CHECK-NEXT: }

constexpr struct {
  int x = 12;
  EBO EBOC{ 42 };
} UnnamedClassInstance;
// CHECK:      (lldb) target variable -T UnnamedClassInstance
// CHECK-NEXT: (const <unnamed-type-UnnamedClassInstance>) UnnamedClassInstance = {
// CHECK-NEXT:   (int) x = 12
// CHECK-NEXT:   (EBO) EBOC = {
// CHECK-NEXT:     (int) Member = 42
// CHECK-NEXT:   }
// CHECK-NEXT: }

constexpr Pointers PointersInstance;
// CHECK:      (lldb) target variable -T PointersInstance
// CHECK-NEXT: (const Pointers) PointersInstance = {
// CHECK-NEXT:   (void *) a = {{.*}}
// CHECK-NEXT:   (char *) b = {{.*}}
// CHECK-NEXT:   (bool *) c = {{.*}}
// CHECK-NEXT:   (short *) e = {{.*}}
// CHECK-NEXT:   (unsigned short *) f = {{.*}}
// CHECK-NEXT:   (unsigned int *) g = {{.*}}
// CHECK-NEXT:   (int *) h = {{.*}}
// CHECK-NEXT:   (unsigned long *) i = {{.*}}
// CHECK-NEXT:   (long *) j = {{.*}}
// CHECK-NEXT:   (float *) k = {{.*}}
// CHECK-NEXT:   (EnumType *) l = {{.*}}
// CHECK-NEXT:   (double *) m = {{.*}}
// CHECK-NEXT:   (unsigned long long *) n = {{.*}}
// CHECK-NEXT:   (long long *) o = {{.*}}
// CHECK-NEXT: }
constexpr References ReferencesInstance;
// CHECK:      (lldb) target variable -T ReferencesInstance
// CHECK-NEXT: (const References) ReferencesInstance = {
// CHECK-NEXT:   (char &) a = {{.*}}
// CHECK-NEXT:   (bool &) b = {{.*}}
// CHECK-NEXT:   (short &) c = {{.*}}
// CHECK-NEXT:   (unsigned short &) d = {{.*}}
// CHECK-NEXT:   (unsigned int &) e = {{.*}}
// CHECK-NEXT:   (int &) f = {{.*}}
// CHECK-NEXT:   (unsigned long &) g = {{.*}}
// CHECK-NEXT:   (long &) h = {{.*}}
// CHECK-NEXT:   (float &) i = {{.*}}
// CHECK-NEXT:   (EnumType &) j = {{.*}}
// CHECK-NEXT:   (double &) k = {{.*}}
// CHECK-NEXT:   (unsigned long long &) l = {{.*}}
// CHECK-NEXT:   (long long &) m = {{.*}}
// CHECK-NEXT: }

// CHECK: Dumping clang ast for 1 modules.
// CHECK: TranslationUnitDecl {{.*}}
// CHECK: |-CXXRecordDecl {{.*}} class ClassWithPadding definition
// CHECK: | |-FieldDecl {{.*}} a 'char'
// CHECK: | |-FieldDecl {{.*}} b 'short'
// CHECK: | |-FieldDecl {{.*}} c 'char[2]'
// CHECK: | |-FieldDecl {{.*}} d 'int'
// CHECK: | |-FieldDecl {{.*}} e 'char'
// CHECK: | |-FieldDecl {{.*}} f 'int'
// CHECK: | |-FieldDecl {{.*}} g 'long long'
// CHECK: | |-FieldDecl {{.*}} h 'char[3]'
// CHECK: | |-FieldDecl {{.*}} i 'long long'
// CHECK: | |-FieldDecl {{.*}} j 'char[2]'
// CHECK: | |-FieldDecl {{.*}} k 'long long'
// CHECK: | |-FieldDecl {{.*}} l 'char'
// CHECK: | `-FieldDecl {{.*}} m 'long long'
// CHECK: |-VarDecl {{.*}} ClassWithPaddingInstance 'const ClassWithPadding'
// CHECK: |-CXXRecordDecl {{.*}} class ClassNoPadding definition
// CHECK: | |-FieldDecl {{.*}} a 'unsigned char'
// CHECK: | |-FieldDecl {{.*}} b 'char'
// CHECK: | |-FieldDecl {{.*}} c 'bool'
// CHECK: | |-FieldDecl {{.*}} d 'bool'
// CHECK: | |-FieldDecl {{.*}} e 'short'
// CHECK: | |-FieldDecl {{.*}} f 'unsigned short'
// CHECK: | |-FieldDecl {{.*}} g 'unsigned int'
// CHECK: | |-FieldDecl {{.*}} h 'int'
// CHECK: | |-FieldDecl {{.*}} i 'unsigned long'
// CHECK: | |-FieldDecl {{.*}} j 'long'
// CHECK: | |-FieldDecl {{.*}} k 'float'
// CHECK: | |-FieldDecl {{.*}} l 'EnumType'
// CHECK: | |-FieldDecl {{.*}} m 'double'
// CHECK: | |-FieldDecl {{.*}} n 'unsigned long long'
// CHECK: | |-FieldDecl {{.*}} o 'long long'
// CHECK: | `-FieldDecl {{.*}} p 'int[5]'
// CHECK: |-VarDecl {{.*}} ClassNoPaddingInstance 'const ClassNoPadding'
// CHECK: |-EnumDecl {{.*}} EnumType
// CHECK: | |-EnumConstantDecl {{.*}} A 'EnumType'
// CHECK: | `-EnumConstantDecl {{.*}} B 'EnumType'
// CHECK: |-CXXRecordDecl {{.*}} struct DerivedClass definition
// CHECK: | |-public 'BaseClass<int>'
// CHECK: | |-CXXConstructorDecl {{.*}} DerivedClass 'void (int, int)'
// CHECK: | | |-ParmVarDecl {{.*}} 'int'
// CHECK: | | `-ParmVarDecl {{.*}} 'int'
// CHECK: | `-FieldDecl {{.*}} DerivedMember 'int'
// CHECK: |-VarDecl {{.*}} DC 'const DerivedClass'
// CHECK: |-CXXRecordDecl {{.*}} struct BaseClass<int> definition
// CHECK: | |-CXXMethodDecl {{.*}} BaseClass 'void (int)'
// CHECK: | | `-ParmVarDecl {{.*}} 'int'
// CHECK: | `-FieldDecl {{.*}} BaseMember 'int'
// CHECK: |-CXXRecordDecl {{.*}} struct EBO definition
// CHECK: | |-public 'EmptyBase'
// CHECK: | |-CXXConstructorDecl {{.*}} EBO 'void (int)'
// CHECK: | | `-ParmVarDecl {{.*}} 'int'
// CHECK: | `-FieldDecl {{.*}} Member 'int'
// CHECK: |-VarDecl {{.*}} EBOC 'const EBO'
// CHECK: |-CXXRecordDecl {{.*}} struct EmptyBase definition
// CHECK: |-CXXRecordDecl {{.*}} struct PaddedBases definition
// CHECK: | |-public 'BaseClass<char>'
// CHECK: | |-public 'BaseClass<short>'
// CHECK: | |-public 'BaseClass<int>'
// CHECK: | |-CXXConstructorDecl {{.*}} PaddedBases 'void (char, short, int, long long)'
// CHECK: | | |-ParmVarDecl {{.*}} 'char'
// CHECK: | | |-ParmVarDecl {{.*}} 'short'
// CHECK: | | |-ParmVarDecl {{.*}} 'int'
// CHECK: | | `-ParmVarDecl {{.*}} 'long long'
// CHECK: | `-FieldDecl {{.*}} DerivedMember 'long long'
// CHECK: |-VarDecl {{.*}} PBC 'const PaddedBases'
// CHECK: |-CXXRecordDecl {{.*}} struct BaseClass<char> definition
// CHECK: | |-CXXMethodDecl {{.*}} BaseClass 'void (int)'
// CHECK: | | `-ParmVarDecl {{.*}} 'int'
// CHECK: | `-FieldDecl {{.*}} BaseMember 'int'
// CHECK: |-CXXRecordDecl {{.*}} struct BaseClass<short> definition
// CHECK: | |-CXXMethodDecl {{.*}} BaseClass 'void (int)'
// CHECK: | | `-ParmVarDecl {{.*}} 'int'
// CHECK: | `-FieldDecl {{.*}} BaseMember 'int'
// CHECK: |-CXXRecordDecl {{.*}} struct <unnamed-type-UnnamedClassInstance> definition
// CHECK: | |-FieldDecl {{.*}} x 'int'
// CHECK: | `-FieldDecl {{.*}} EBOC 'EBO'
// CHECK: |-VarDecl {{.*}} UnnamedClassInstance 'const <unnamed-type-UnnamedClassInstance>'
// CHECK: |-CXXRecordDecl {{.*}} struct Pointers definition
// CHECK: | |-FieldDecl {{.*}} a 'void *'
// CHECK: | |-FieldDecl {{.*}} b 'char *'
// CHECK: | |-FieldDecl {{.*}} c 'bool *'
// CHECK: | |-FieldDecl {{.*}} e 'short *'
// CHECK: | |-FieldDecl {{.*}} f 'unsigned short *'
// CHECK: | |-FieldDecl {{.*}} g 'unsigned int *'
// CHECK: | |-FieldDecl {{.*}} h 'int *'
// CHECK: | |-FieldDecl {{.*}} i 'unsigned long *'
// CHECK: | |-FieldDecl {{.*}} j 'long *'
// CHECK: | |-FieldDecl {{.*}} k 'float *'
// CHECK: | |-FieldDecl {{.*}} l 'EnumType *'
// CHECK: | |-FieldDecl {{.*}} m 'double *'
// CHECK: | |-FieldDecl {{.*}} n 'unsigned long long *'
// CHECK: | `-FieldDecl {{.*}} o 'long long *'
// CHECK: |-VarDecl {{.*}} PointersInstance 'const Pointers'
// CHECK: |-CXXRecordDecl {{.*}} struct References definition
// CHECK: | |-FieldDecl {{.*}} a 'char &'
// CHECK: | |-FieldDecl {{.*}} b 'bool &'
// CHECK: | |-FieldDecl {{.*}} c 'short &'
// CHECK: | |-FieldDecl {{.*}} d 'unsigned short &'
// CHECK: | |-FieldDecl {{.*}} e 'unsigned int &'
// CHECK: | |-FieldDecl {{.*}} f 'int &'
// CHECK: | |-FieldDecl {{.*}} g 'unsigned long &'
// CHECK: | |-FieldDecl {{.*}} h 'long &'
// CHECK: | |-FieldDecl {{.*}} i 'float &'
// CHECK: | |-FieldDecl {{.*}} j 'EnumType &'
// CHECK: | |-FieldDecl {{.*}} k 'double &'
// CHECK: | |-FieldDecl {{.*}} l 'unsigned long long &'
// CHECK: | `-FieldDecl {{.*}} m 'long long &'
// CHECK: `-VarDecl {{.*}} ReferencesInstance 'const References'

int main(int argc, char **argv) {
  return 0;
}
