// RUN: %clang_analyze_cc1 -analyzer-checker=optin.performance -analyzer-config optin.performance.Padding:AllowedPad=2 -verify %s

#if __has_include(<stdalign.h>)
#include <stdalign.h>
#endif

#if __has_include(<stdalign.h>) || defined(__cplusplus)
// expected-warning@+1{{Excessive padding in 'struct FieldAttrAlign' (6 padding}}
struct FieldAttrAlign {
  char c1;
  alignas(4) int i;
  char c2;
};

// expected-warning@+1{{Excessive padding in 'struct FieldAttrOverAlign' (10 padding}}
struct FieldAttrOverAlign {
  char c1;
  alignas(8) int i;
  char c2;
};

#endif // __has_include(<stdalign.h>) || defined(__cplusplus)

// Re-ordering members of these structs won't reduce padding, so don't warn
struct LeadingChar { // no-warning
  char c;
  int i;
};

struct TrailingChar { // no-warning
  int i;
  char c;
};

struct Helpless { // no-warning
  struct TrailingChar i1;
  struct LeadingChar i2;
  char c;
};

#pragma pack(push)
#pragma pack(1)
struct SquishedIntSandwich { // no-warning
  char c1;
  int i;
  char c2;
};
#pragma pack(pop)

// Re-ordering members of these structs will reduce padding, so warn
struct IntSandwich { // expected-warning{{Excessive padding in 'struct IntSandwich'}}
  char c1;
  int i;
  char c2;
};

struct TurDuckHen { // expected-warning{{Excessive padding in 'struct TurDuckHen'}}
  char c1;
  struct IntSandwich i;
  char c2;
};

#pragma pack(push)
#pragma pack(2)
struct SmallIntSandwich { // expected-warning{{Excessive padding in 'struct SmallIntSandwich'}}
  char c1;
  int i1;
  char c2;
  int i2;
  char c3;
  int i3;
  char c4;
};
#pragma pack(pop)

union SomeUnion { // no-warning
  char c;
  short s;
  int i;
};

struct HoldsAUnion { // expected-warning{{Excessive padding in 'struct HoldsAUnion'}}
  char c1;
  union SomeUnion u;
  char c2;
};

struct BigCharArray { // no-warning
  char c[129];
};

struct SmallCharArray { // no-warning
  char c[5];
};

struct MediumIntArray { // no-warning
  int i[5];
};

struct LargeSizeToSmallSize { // expected-warning{{Excessive padding in 'struct LargeSizeToSmallSize'}}
  struct BigCharArray b;
  struct MediumIntArray m;
  struct SmallCharArray s;
};

struct LargeAlignToSmallAlign { // no-warning
  struct MediumIntArray m;
  struct BigCharArray b;
  struct SmallCharArray s;
};

// Currently ignoring VLA padding problems.  Still need to make sure we don't
// choke on VLAs though
struct HoldsVLA { // no-warning
  char c1;
  int x;
  char c2;
  int vla[];
};

// Currently ignoring bitfield padding problems.  Still need to make sure we
// don't choke on bitfields though
struct HoldsBitfield { // no-warning
  char c1;
  int x;
  char c2;
  unsigned char b1 : 3;
  unsigned char b2 : 3;
  unsigned char b3 : 2;
};

typedef struct { // expected-warning{{Excessive padding in 'TypedefSandwich'}}
  char c1;
  int i;
  char c2;
} TypedefSandwich;

// expected-warning@+1{{Excessive padding in 'struct StructAttrAlign' (10 padding}}
struct StructAttrAlign {
  char c1;
  int i;
  char c2;
} __attribute__((aligned(8)));

struct CorrectOverlyAlignedChar { // no-warning
  char c __attribute__((aligned(4096)));
  char c1;
  int x1;
  char c2;
  int x2;
  char c3;
};

struct OverlyAlignedChar { // expected-warning{{Excessive padding in 'struct OverlyAlignedChar'}}
  char c1;
  int x;
  char c2;
  char c __attribute__((aligned(4096)));
};

struct HoldsOverlyAlignedChar { // expected-warning{{Excessive padding in 'struct HoldsOverlyAlignedChar'}}
  char c1;
  struct OverlyAlignedChar o;
  char c2;
};

void internalStructFunc() {
  struct X { // expected-warning{{Excessive padding in 'struct X'}}
    char c1;
    int t;
    char c2;
  };
  struct X obj;
}

void typedefStructFunc() {
  typedef struct { // expected-warning{{Excessive padding in 'S'}}
    char c1;
    int t;
    char c2;
  } S;
  S obj;
}

void anonStructFunc() {
  struct { // expected-warning{{Excessive padding in 'struct (anonymous}}
    char c1;
    int t;
    char c2;
  } obj;
}

struct CorrectDefaultAttrAlign { // no-warning
  long long i;
  char c1;
  char c2;
} __attribute__((aligned));

struct TooSmallShortSandwich { // no-warning
  char c1;
  short s;
  char c2;
};

// expected-warning@+1{{Excessive padding in 'struct SmallArrayShortSandwich'}}
struct SmallArrayShortSandwich {
  char c1;
  short s;
  char c2;
} ShortArray[20];

// expected-warning@+1{{Excessive padding in 'struct SmallArrayInFunc'}}
struct SmallArrayInFunc {
  char c1;
  short s;
  char c2;
};

void arrayHolder() {
  struct SmallArrayInFunc Arr[15];
}

// xxxexpected-warning@+1{{Excessive padding in 'struct SmallArrayInStruct'}}
struct SmallArrayInStruct {
  char c1;
  short s;
  char c2;
};

struct HoldsSmallArray {
  struct SmallArrayInStruct Field[20];
} HoldsSmallArrayElt;

void nestedPadding() {
  struct HoldsSmallArray Arr[15];
}
