// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \
// RUN:     -fsyntax-only -fxl-pragma-pack %s | \
// RUN:   FileCheck %s

// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \
// RUN:     -fsyntax-only -fxl-pragma-pack %s | \
// RUN:   FileCheck %s

namespace test1 {
// Test the class layout when having a double which is/is not the first struct
// member.
struct D {
  double d1;
  int i1;
};

struct DoubleFirst {
  struct D d2;
  int i2;
};

struct IntFirst {
  int i3;
  struct D d3;
};

int a = sizeof(DoubleFirst);
int b = sizeof(IntFirst);

// CHECK:     *** Dumping AST Record Layout
// CHECK-NEXT:         0 | struct test1::D
// CHECK-NEXT:         0 |   double d1
// CHECK-NEXT:         8 |   int i1
// CHECK-NEXT:           | [sizeof=16, dsize=16, align=4, preferredalign=8,
// CHECK-NEXT:           |  nvsize=16, nvalign=4, preferrednvalign=8]

// CHECK:     *** Dumping AST Record Layout
// CHECK-NEXT:         0 | struct test1::DoubleFirst
// CHECK-NEXT:         0 |   struct test1::D d2
// CHECK-NEXT:         0 |     double d1
// CHECK-NEXT:         8 |     int i1
// CHECK-NEXT:        16 |   int i2
// CHECK-NEXT:           | [sizeof=24, dsize=24, align=4, preferredalign=8,
// CHECK-NEXT:           |  nvsize=24, nvalign=4, preferrednvalign=8]

// CHECK:     *** Dumping AST Record Layout
// CHECK-NEXT:         0 | struct test1::IntFirst
// CHECK-NEXT:         0 |   int i3
// CHECK-NEXT:         4 |   struct test1::D d3
// CHECK-NEXT:         4 |     double d1
// CHECK-NEXT:        12 |     int i1
// CHECK-NEXT:           | [sizeof=20, dsize=20, align=4, preferredalign=4,
// CHECK-NEXT:           |  nvsize=20, nvalign=4, preferrednvalign=4]
} // namespace test1

namespace test2 {
// Test the class layout when having a zero-sized bitfield followed by double.
struct Double {
  int : 0;
  double d;
};

int a = sizeof(Double);

// CHECK:     *** Dumping AST Record Layout
// CHECK-NEXT:         0 | struct test2::Double
// CHECK-NEXT:       0:- |   int
// CHECK-NEXT:         0 |   double d
// CHECK-NEXT:           | [sizeof=8, dsize=8, align=4, preferredalign=4,
// CHECK-NEXT:           |  nvsize=8, nvalign=4, preferrednvalign=4]
} // namespace test2

namespace test3 {
// Test the class layout when having a double member in union.
union A {
  int b;
  double d;
};

struct UnionStruct {
  union A a;
  int i;
};

int a = sizeof(UnionStruct);

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | union test3::A
// CHECK-NEXT:          0 |   int b
// CHECK-NEXT:          0 |   double d
// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=8,
// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=8]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test3::UnionStruct
// CHECK-NEXT:          0 |   union test3::A a
// CHECK-NEXT:          0 |     int b
// CHECK-NEXT:          0 |     double d
// CHECK-NEXT:          8 |   int i
// CHECK-NEXT:            | [sizeof=16, dsize=16, align=4, preferredalign=8,
// CHECK-NEXT:            |  nvsize=16, nvalign=4, preferrednvalign=8]

} // namespace test3

namespace test4 {
// Test the class layout when having multiple base classes.
struct A {
  int a;
};

struct B {
  double d;
};

class S : A, B {
};

int a = sizeof(S);

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test4::A
// CHECK-NEXT:          0 |   int a
// CHECK-NEXT:            | [sizeof=4, dsize=4, align=4, preferredalign=4,
// CHECK-NEXT:            |  nvsize=4, nvalign=4, preferrednvalign=4]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test4::B
// CHECK-NEXT:          0 |   double d
// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=8,
// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=8]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | class test4::S
// CHECK-NEXT:          0 |   struct test4::A (base)
// CHECK-NEXT:          0 |     int a
// CHECK-NEXT:          4 |   struct test4::B (base)
// CHECK-NEXT:          4 |     double d
// CHECK-NEXT:            | [sizeof=12, dsize=12, align=4, preferredalign=4,
// CHECK-NEXT:            |  nvsize=12, nvalign=4, preferrednvalign=4]
} // namespace test4

namespace test5 {
struct Empty {
};

struct EmptyDer : Empty {
  double d;
};

struct NonEmpty {
  int i;
};

struct NonEmptyDer : NonEmpty {
  double d;
};

int a = sizeof(EmptyDer);
int b = sizeof(NonEmptyDer);

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test5::Empty (empty)
// CHECK-NEXT:            | [sizeof=1, dsize=1, align=1, preferredalign=1,
// CHECK-NEXT:            |  nvsize=1, nvalign=1, preferrednvalign=1]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test5::EmptyDer
// CHECK-NEXT:          0 |   struct test5::Empty (base) (empty)
// CHECK-NEXT:          0 |   double d
// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=8,
// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=8]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test5::NonEmpty
// CHECK-NEXT:          0 |   int i
// CHECK-NEXT:            | [sizeof=4, dsize=4, align=4, preferredalign=4,
// CHECK-NEXT:            |  nvsize=4, nvalign=4, preferrednvalign=4]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test5::NonEmptyDer
// CHECK-NEXT:          0 |   struct test5::NonEmpty (base)
// CHECK-NEXT:          0 |     int i
// CHECK-NEXT:          4 |   double d
// CHECK-NEXT:            | [sizeof=12, dsize=12, align=4, preferredalign=4,
// CHECK-NEXT:            |  nvsize=12, nvalign=4, preferrednvalign=4]
} // namespace test5

namespace test6 {
struct A {
  struct B {
    double d[3];
  } b;
};

int a = sizeof(A);

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test6::A::B
// CHECK-NEXT:          0 |   double[3] d
// CHECK-NEXT:            | [sizeof=24, dsize=24, align=4, preferredalign=8,
// CHECK-NEXT:            |  nvsize=24, nvalign=4, preferrednvalign=8]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test6::A
// CHECK-NEXT:          0 |   struct test6::A::B b
// CHECK-NEXT:          0 |     double[3] d
// CHECK-NEXT:            | [sizeof=24, dsize=24, align=4, preferredalign=8,
// CHECK-NEXT:            |  nvsize=24, nvalign=4, preferrednvalign=8]

} // namespace test6

namespace test7 {
struct A {
  struct B {
    long double _Complex d[3];
  } b;
};

int a = sizeof(A);

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test7::A::B
// CHECK-NEXT:          0 |   _Complex long double[3] d
// CHECK-NEXT:            | [sizeof=48, dsize=48, align=4, preferredalign=8,
// CHECK-NEXT:            |  nvsize=48, nvalign=4, preferrednvalign=8]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test7::A
// CHECK-NEXT:          0 |   struct test7::A::B b
// CHECK-NEXT:          0 |     _Complex long double[3] d
// CHECK-NEXT:            | [sizeof=48, dsize=48, align=4, preferredalign=8,
// CHECK-NEXT:            |  nvsize=48, nvalign=4, preferrednvalign=8]

} // namespace test7

namespace test8 {
struct Emp {};

struct Y : Emp {
  double d;
};

struct Z : Emp {
  Y y;
};

int a = sizeof(Z);

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test8::Emp (empty)
// CHECK-NEXT:            | [sizeof=1, dsize=1, align=1, preferredalign=1,
// CHECK-NEXT:            |  nvsize=1, nvalign=1, preferrednvalign=1]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test8::Y
// CHECK-NEXT:          0 |   struct test8::Emp (base) (empty)
// CHECK-NEXT:          0 |   double d
// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=8,
// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=8]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test8::Z
// CHECK-NEXT:          0 |   struct test8::Emp (base) (empty)
// CHECK-NEXT:          8 |   struct test8::Y y
// CHECK-NEXT:          8 |     struct test8::Emp (base) (empty)
// CHECK-NEXT:          8 |     double d
// CHECK-NEXT:            | [sizeof=16, dsize=16, align=4, preferredalign=8,
// CHECK-NEXT:            |  nvsize=16, nvalign=4, preferrednvalign=8]

} // namespace test8

namespace test9 {
// Test the class layout when having a zero-extent array in a base class, which
// renders the base class not empty.
struct A { char zea[0]; };

struct B : A { double d; };

struct C { double d; };
struct D : A, C { char x; };

int a = sizeof(B);
int b = sizeof(D);

// CHECK:               0 | struct test9::B
// CHECK-NEXT:          0 |   struct test9::A (base)
// CHECK-NEXT:          0 |     char[0] zea
// CHECK-NEXT:          0 |   double d
// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=4,
// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=4]

// CHECK:               0 | struct test9::D
// CHECK-NEXT:          0 |   struct test9::A (base)
// CHECK-NEXT:          0 |     char[0] zea
// CHECK-NEXT:          0 |   struct test9::C (base)
// CHECK-NEXT:          0 |     double d
// CHECK-NEXT:          8 |   char x
// CHECK-NEXT:            | [sizeof=12, dsize=9, align=4, preferredalign=4,
// CHECK-NEXT:            |  nvsize=9, nvalign=4, preferrednvalign=4]

} // namespace test9

namespace test10 {
struct A { double x; };
struct B : A {};

int a = sizeof(B);

// CHECK:               0 | struct test10::B
// CHECK-NEXT:          0 |   struct test10::A (base)
// CHECK-NEXT:          0 |     double x
// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=8,
// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=8]

} // namespace test10

namespace test11 {
// Test how #pragma pack and align attribute interacts with AIX `power`
// alignment rules.
struct A {
  char a;
  double __attribute__((aligned(16))) d;
  int i;
};

struct B {
  double __attribute__((aligned(4))) d1;
  char a;
  double d2;
};

#pragma pack(2)
struct C {
  int i;
  short j;
  double k;
};
#pragma pack(pop)

#pragma pack(2)
struct D {
  double d;
  short j;
  int i;
};
#pragma pack(pop)

#pragma pack(8)
struct E {
  double __attribute__((aligned(4))) d;
  short s;
};
#pragma pack(pop)

#pragma pack(4)
struct F : public D {
  double d;
};
#pragma pack(pop)

#pragma pack(2)
struct G : public E {
  int i;
};
#pragma pack(pop)

int a = sizeof(A);
int b = sizeof(B);
int c = sizeof(C);
int d = sizeof(D);
int e = sizeof(E);
int f = sizeof(F);
int g = sizeof(G);

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test11::A
// CHECK-NEXT:          0 |   char a
// CHECK-NEXT:         16 |   double d
// CHECK-NEXT:         24 |   int i
// CHECK-NEXT:            | [sizeof=32, dsize=32, align=16, preferredalign=16,
// CHECK-NEXT:            |  nvsize=32, nvalign=16, preferrednvalign=16]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test11::B
// CHECK-NEXT:          0 |   double d1
// CHECK-NEXT:          8 |   char a
// CHECK-NEXT:         12 |   double d2
// CHECK-NEXT:            | [sizeof=24, dsize=24, align=4, preferredalign=8,
// CHECK-NEXT:            |  nvsize=24, nvalign=4, preferrednvalign=8]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test11::C
// CHECK-NEXT:          0 |   int i
// CHECK-NEXT:          4 |   short j
// CHECK-NEXT:          6 |   double k
// CHECK-NEXT:            | [sizeof=14, dsize=14, align=2, preferredalign=2,
// CHECK-NEXT:            |  nvsize=14, nvalign=2, preferrednvalign=2]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test11::D
// CHECK-NEXT:          0 |   double d
// CHECK-NEXT:          8 |   short j
// CHECK-NEXT:         10 |   int i
// CHECK-NEXT:            | [sizeof=14, dsize=14, align=2, preferredalign=2,
// CHECK-NEXT:            |  nvsize=14, nvalign=2, preferrednvalign=2]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test11::E
// CHECK-NEXT:          0 |   double d
// CHECK-NEXT:          8 |   short s
// CHECK-NEXT:            | [sizeof=16, dsize=16, align=4, preferredalign=8,
// CHECK-NEXT:            |  nvsize=16, nvalign=4, preferrednvalign=8]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test11::F
// CHECK-NEXT:          0 |   struct test11::D (base)
// CHECK-NEXT:          0 |     double d
// CHECK-NEXT:          8 |     short j
// CHECK-NEXT:         10 |     int i
// CHECK-NEXT:         16 |   double d
// CHECK-NEXT:            | [sizeof=24, dsize=24, align=4, preferredalign=4,
// CHECK-NEXT:            |  nvsize=24, nvalign=4, preferrednvalign=4]

// CHECK:      *** Dumping AST Record Layout
// CHECK-NEXT:          0 | struct test11::G
// CHECK-NEXT:          0 |   struct test11::E (base)
// CHECK-NEXT:          0 |     double d
// CHECK-NEXT:          8 |     short s
// CHECK-NEXT:         16 |   int i
// CHECK-NEXT:            | [sizeof=20, dsize=20, align=2, preferredalign=2,
// CHECK-NEXT:            |  nvsize=20, nvalign=2, preferrednvalign=2]

} // namespace test11
