Compiler projects using llvm
// Compile with "cl /c /Zi /GR- SimplePaddingTest.cpp"
// Link with "link SimplePaddingTest.obj /debug /nodefaultlib /entry:main"

#include <stdint.h>

extern "C" using at_exit_handler = void();

int atexit(at_exit_handler handler) { return 0; }

struct SimplePadNoPadding {
  int32_t X;
  int32_t Y;
  // No padding anywhere, sizeof(T) = 8
} A;

struct SimplePadUnion {
  union {
    int32_t X;
    int64_t Y;
    struct {
      int32_t X;
      // 4 bytes of padding here
      int64_t Y;
    } Z;
  };
  // Since the padding occurs at a location that is occupied by other storage
  // (namely the Y member), the storage will still be considered used, and so
  // there will be no unused bytes in the larger class.  But in the debug
  // info for the nested struct, we should see padding.
  // sizeof(SimplePadUnion) == sizeof(Z) == 16
} B;

struct SimplePadNoPadding2 {
  bool A;
  bool B;
  bool C;
  bool D;
  // No padding anywhere, sizeof(T) = 4
} C;

struct alignas(4) SimplePadFields1 {
  char A;
  char B;
  char C;
  // 1 byte of padding here, sizeof(T) = 4
} E;

struct SimplePadFields2 {
  int32_t Y;
  char X;
} F;

struct SimplePadBase {
  // Make sure this class is 4 bytes, and the derived class requires 8 byte
  // alignment, so that padding is inserted between base and derived.
  int32_t X;
  // No padding here
} G;

struct SimplePadDerived : public SimplePadBase {
  // 4 bytes of padding here due to Y requiring 8 byte alignment.
  // Thus, sizeof(T) = 16
  int64_t Y;
} H;

struct SimplePadEmptyBase1 {};
struct SimplePadEmptyBase2 {};

struct SimplePadEmpty : public SimplePadEmptyBase1, SimplePadEmptyBase2 {
  // Bases have to occupy at least 1 byte of storage, so this requires
  // 2 bytes of padding, plus 1 byte for each base, yielding sizeof(T) = 8
  int32_t X;
} I;

struct SimplePadVfptr {
  virtual ~SimplePadVfptr() {}
  static void operator delete(void *ptr, size_t sz) {}
  int32_t X;
} J;

struct NonEmptyBase1 {
  bool X;
};

struct NonEmptyBase2 {
  bool Y;
};

struct SimplePadMultiInherit : public NonEmptyBase1, public NonEmptyBase2 {
  // X and Y from the 2 bases will get squished together, leaving 2 bytes
  // of padding necessary for proper alignment of an int32.
  // Therefore, sizeof(T) = 2 + 2 + 4 = 8
  int32_t X;
} K;

struct SimplePadMultiInherit2 : public SimplePadFields1, SimplePadFields2 {
  // There should be 1 byte of padding after the first class, and
  // 3 bytes of padding after the second class.
  int32_t X;
} L;

struct OneLevelInherit : public NonEmptyBase1 {
  short Y;
};

struct SimplePadTwoLevelInherit : public OneLevelInherit {
  // OneLevelInherit has nested padding because of its base,
  // and then padding again because of this class.  So each
  // class should be 4 bytes, yielding sizeof(T) = 12.
  int64_t Z;
} M;

struct SimplePadAggregate {
  NonEmptyBase1 X;
  int32_t Y;
  // the presence of X will cause 3 bytes of padding to be injected.
  SimplePadFields1 Fields;
} N;

struct SimplePadVtable1 {
  static void operator delete(void *ptr, size_t sz) {}
  virtual ~SimplePadVtable1() {}
  virtual void A1() {}
  virtual void B1() {}
} O;

struct SimplePadVtable2 {
  static void operator delete(void *ptr, size_t sz) {}
  virtual ~SimplePadVtable2() {}
  virtual void X2() {}
  virtual void Y2() {}
  virtual void Z2() {}
} P;

struct SimplePadVtable3 {
  static void operator delete(void *ptr, size_t sz) {}
  virtual ~SimplePadVtable3() {}
  virtual void Foo3() {}
  virtual void Bar3() {}
  virtual void Baz3() {}
  virtual void Buzz3() {}
} Q;

struct SimplePadMultiVTables
    : public SimplePadVtable1,
      public SimplePadVtable2,
      public SimplePadVtable3 {

  ~SimplePadMultiVTables() override {}
  static void operator delete(void *ptr, size_t sz) {}

  // SimplePadVtable1 overrides
  void A1() override {}

  // SimplePadVtable2 overrides
  void Y2() override {}
  void Z2() override {}

  // SimplePadVtable3 overrides
  void Bar3() override {}
  void Baz3() override {}
  void Buzz3() override {}
} R;

int main(int argc, char **argv) {

  return 0;
}