Xiangling_L created this revision.
Xiangling_L added reviewers: jasonliu, hubert.reinterpretcast, efriedma,
jyknight, rnk, rsmith, aaron.ballman.
Herald added subscribers: cfe-commits, dang.
Herald added a project: clang.
Xiangling_L requested review of this revision.
1. Implementing the natural align for AIX
2. Sort out pragma pack stack effect
3. Add -faix-pragma-stack option to enable AIX pragma stack effect
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D87702
Files:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/LangOptions.def
clang/include/clang/Driver/Options.td
clang/include/clang/Sema/Sema.h
clang/include/clang/Serialization/ASTReader.h
clang/lib/AST/RecordLayoutBuilder.cpp
clang/lib/Driver/ToolChains/Clang.cpp
clang/lib/Frontend/CompilerInvocation.cpp
clang/lib/Parse/ParsePragma.cpp
clang/lib/Sema/Sema.cpp
clang/lib/Sema/SemaAttr.cpp
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/test/Driver/aix-pragma-pack.c
clang/test/Layout/aix-power-natural-interaction.cpp
clang/test/Sema/aix-pragma-pack-and-align.c
Index: clang/test/Sema/aix-pragma-pack-and-align.c
===================================================================
--- /dev/null
+++ clang/test/Sema/aix-pragma-pack-and-align.c
@@ -0,0 +1,212 @@
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \
+// RUN: -faix-pragma-pack -verify -fsyntax-only -x c++ %s | \
+// RUN: FileCheck %s
+
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \
+// RUN: -faix-pragma-pack -verify -fsyntax-only -x c++ %s | \
+// RUN: FileCheck %s
+
+namespace test1 {
+#pragma align(natural)
+#pragma pack(4)
+#pragma pack(2)
+struct A {
+ int i;
+ double d;
+};
+
+int a = sizeof(A);
+#pragma pack()
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 4}}
+#pragma pack(pop)
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}}
+struct B {
+ int i;
+ double d;
+};
+#pragma align(reset)
+
+int b = sizeof(B);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test1::A
+// CHECK-NEXT: 0 | int i
+// CHECK-NEXT: 4 | double d
+// CHECK-NEXT: | [sizeof=12, dsize=12, align=2, preferredalign=2,
+// CHECK-NEXT: | nvsize=12, nvalign=2, preferrednvalign=2]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test1::B
+// CHECK-NEXT: 0 | int i
+// CHECK-NEXT: 8 | double d
+// CHECK-NEXT: | [sizeof=16, dsize=16, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=16, nvalign=4, preferrednvalign=8]
+
+} // namespace test1
+
+namespace test2 {
+#pragma align(natural)
+#pragma pack(2)
+struct A {
+ int i;
+ double d;
+};
+
+int a = sizeof(A);
+#pragma align(reset)
+
+struct B {
+ int i;
+ double d;
+};
+
+int b = sizeof(B);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test2::A
+// CHECK-NEXT: 0 | int i
+// CHECK-NEXT: 4 | double d
+// CHECK-NEXT: | [sizeof=12, dsize=12, align=2, preferredalign=2,
+// CHECK-NEXT: | nvsize=12, nvalign=2, preferrednvalign=2]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test2::B
+// 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 test2
+
+namespace test3 {
+#pragma pack(2)
+#pragma align(natural)
+struct A {
+ double d;
+};
+#pragma align(reset)
+#pragma pack(pop)
+
+int a = sizeof(A);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test3::A
+// CHECK-NEXT: 0 | double d
+// CHECK-NEXT: | [sizeof=8, dsize=8, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=8, nvalign=4, preferrednvalign=8]
+
+} // namespace test3
+
+namespace test4 {
+#pragma pack(2)
+#pragma align(natural)
+#pragma pack(pop)
+
+struct A {
+ int i;
+ double d;
+} a;
+#pragma align(reset)
+#pragma pack(pop)
+
+int i = sizeof(A);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test4::A
+// CHECK-NEXT: 0 | int i
+// CHECK-NEXT: 8 | double d
+// CHECK-NEXT: | [sizeof=16, dsize=16, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=16, nvalign=4, preferrednvalign=8]
+
+} // namespace test4
+
+namespace test5 {
+#pragma align(power)
+#pragma align(natural)
+#pragma pack(2)
+#pragma align(reset)
+struct A {
+ int i;
+ double d;
+};
+#pragma align(reset)
+
+int a = sizeof(A);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test5::A
+// 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 {
+#pragma align(natural)
+#pragma pack(0) // expected-error {{expected #pragma pack parameter to be '1', '2', '4', '8', or '16'}}
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}}
+
+struct A {
+ int i;
+ double d;
+} a;
+#pragma align(reset)
+
+int i = sizeof(a);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test6::A
+// CHECK-NEXT: 0 | int i
+// CHECK-NEXT: 8 | double d
+// CHECK-NEXT: | [sizeof=16, dsize=16, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=16, nvalign=4, preferrednvalign=8]
+
+} // namespace test6
+
+namespace test7 {
+#pragma align = natural // expected-warning {{missing '(' after '#pragma align' - ignoring}}
+#pragma align(reset) // expected-warning {{#pragma options align=reset failed: stack empty}}
+} // namespace test7
+
+namespace test8 {
+#pragma align(packed)
+#pragma pack(2)
+#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 2}}
+struct A {
+ int i;
+ double d;
+};
+#pragma align(reset)
+
+int a = sizeof(A);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test8::A
+// CHECK-NEXT: 0 | int i
+// CHECK-NEXT: 4 | double d
+// CHECK-NEXT: | [sizeof=12, dsize=12, align=2, preferredalign=2,
+// CHECK-NEXT: | nvsize=12, nvalign=2, preferrednvalign=2]
+
+} // namespace test8
+
+namespace test9 {
+#pragma pack(push, r1, 2) // expected-warning {{specifying an identifier within pragma pack is not supported, identifier is ignored}}
+struct A {
+ int i;
+ double d;
+};
+#pragma pack(pop)
+
+int a = sizeof(A);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test9::A
+// CHECK-NEXT: 0 | int i
+// CHECK-NEXT: 4 | double d
+// CHECK-NEXT: | [sizeof=12, dsize=12, align=2, preferredalign=2,
+// CHECK-NEXT: | nvsize=12, nvalign=2, preferrednvalign=2]
+
+} // namespace test9
+
+// expected-no-warning
Index: clang/test/Layout/aix-power-natural-interaction.cpp
===================================================================
--- /dev/null
+++ clang/test/Layout/aix-power-natural-interaction.cpp
@@ -0,0 +1,146 @@
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \
+// RUN: -faix-pragma-pack -fsyntax-only %s | \
+// RUN: FileCheck %s
+
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \
+// RUN: -faix-pragma-pack -fsyntax-only %s | \
+// RUN: FileCheck %s
+
+namespace test1 {
+#pragma align(natural)
+struct A {
+ int i1;
+};
+
+struct B {
+ double d1;
+};
+#pragma align(reset)
+
+struct C : A, B {
+ double d2;
+};
+
+int a = sizeof(C);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test1::A
+// CHECK-NEXT: 0 | int i1
+// 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 test1::B
+// CHECK-NEXT: 0 | double d1
+// 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 test1::C
+// CHECK-NEXT: 0 | struct test1::A (base)
+// CHECK-NEXT: 0 | int i1
+// CHECK-NEXT: 4 | struct test1::B (base)
+// CHECK-NEXT: 4 | double d1
+// CHECK-NEXT: 12 | double d2
+// CHECK-NEXT: | [sizeof=20, dsize=20, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=20, nvalign=4, preferrednvalign=4]
+
+} // namespace test1
+
+namespace test2 {
+struct A {
+ int i1;
+ double d;
+};
+
+#pragma align(natural)
+struct B : A {
+ int i2;
+};
+#pragma align(reset)
+
+int b = sizeof(B);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test2::A
+// CHECK-NEXT: 0 | int i1
+// CHECK-NEXT: 4 | double d
+// CHECK-NEXT: | [sizeof=12, dsize=12, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=12, nvalign=4, preferrednvalign=4]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test2::B
+// CHECK-NEXT: 0 | struct test2::A (base)
+// CHECK-NEXT: 0 | int i1
+// CHECK-NEXT: 4 | double d
+// CHECK-NEXT: 12 | int i2
+// CHECK-NEXT: | [sizeof=16, dsize=16, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=16, nvalign=4, preferrednvalign=4]
+
+} // namespace test2
+
+namespace test3 {
+#pragma align(natural)
+struct A {
+ int i1;
+ double d;
+};
+#pragma align(reset)
+
+struct B {
+ struct A a;
+ int i2;
+};
+
+int c = sizeof(B);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test3::A
+// CHECK-NEXT: 0 | int i1
+// CHECK-NEXT: 8 | double d
+// 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 test3::B
+// CHECK-NEXT: 0 | struct test3::A a
+// CHECK-NEXT: 0 | int i1
+// CHECK-NEXT: 8 | double d
+// CHECK-NEXT: 16 | int i2
+// CHECK-NEXT: | [sizeof=24, dsize=24, align=4, preferredalign=8,
+// CHECK-NEXT: | nvsize=24, nvalign=4, preferrednvalign=8]
+
+} // namespace test3
+
+namespace test4 {
+struct A {
+ int i1;
+ double d;
+};
+
+#pragma align(natural)
+struct B {
+ int i2;
+ struct A a;
+};
+#pragma align(reset)
+
+int d = sizeof(B);
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test4::A
+// CHECK-NEXT: 0 | int i1
+// CHECK-NEXT: 4 | double d
+// CHECK-NEXT: | [sizeof=12, dsize=12, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=12, nvalign=4, preferrednvalign=4]
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct test4::B
+// CHECK-NEXT: 0 | int i2
+// CHECK-NEXT: 4 | struct test4::A a
+// CHECK-NEXT: 4 | int i1
+// CHECK-NEXT: 8 | double d
+// CHECK-NEXT: | [sizeof=16, dsize=16, align=4, preferredalign=4,
+// CHECK-NEXT: | nvsize=16, nvalign=4, preferrednvalign=4]
+
+} // namespace test4
Index: clang/test/Driver/aix-pragma-pack.c
===================================================================
--- /dev/null
+++ clang/test/Driver/aix-pragma-pack.c
@@ -0,0 +1,4 @@
+// RUN: %clang -### -target powerpc-ibm-aix-xcoff -c %s -o /dev/null 2>&1 | FileCheck %s
+// RUN: %clang -### -target powerpc64-ibm-aix-xcoff -c %s -o /dev/null 2>&1 | FileCheck %s
+
+// CHECK: "-faix-pragma-pack"
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -4159,11 +4159,11 @@
return;
RecordData Record;
- Record.push_back(SemaRef.PackStack.CurrentValue);
+ Record.push_back(SemaRef.PackStack.CurrentValue.getPackNumber());
AddSourceLocation(SemaRef.PackStack.CurrentPragmaLocation, Record);
Record.push_back(SemaRef.PackStack.Stack.size());
for (const auto &StackEntry : SemaRef.PackStack.Stack) {
- Record.push_back(StackEntry.Value);
+ Record.push_back(StackEntry.Value.getPackNumber());
AddSourceLocation(StackEntry.PragmaLocation, Record);
AddSourceLocation(StackEntry.PragmaPushLocation, Record);
AddString(StackEntry.StackSlotLabel, Record);
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -7899,7 +7899,8 @@
bool DropFirst = false;
if (!PragmaPackStack.empty() &&
PragmaPackStack.front().Location.isInvalid()) {
- assert(PragmaPackStack.front().Value == SemaObj->PackStack.DefaultValue &&
+ assert(PragmaPackStack.front().Value ==
+ SemaObj->PackStack.DefaultValue.getPackNumber() &&
"Expected a default alignment value");
SemaObj->PackStack.Stack.emplace_back(
PragmaPackStack.front().SlotLabel, SemaObj->PackStack.CurrentValue,
@@ -7908,15 +7909,23 @@
DropFirst = true;
}
for (const auto &Entry :
- llvm::makeArrayRef(PragmaPackStack).drop_front(DropFirst ? 1 : 0))
- SemaObj->PackStack.Stack.emplace_back(Entry.SlotLabel, Entry.Value,
+ llvm::makeArrayRef(PragmaPackStack).drop_front(DropFirst ? 1 : 0)) {
+ Sema::AlignPackInfo Info =
+ Sema::AlignPackInfo(SemaObj->PackStack.CurrentValue.getAlignMode(),
+ Entry.Value, PP.getLangOpts().AIXPragmaPack);
+ SemaObj->PackStack.Stack.emplace_back(Entry.SlotLabel, Info,
Entry.Location, Entry.PushLocation);
+ }
if (PragmaPackCurrentLocation.isInvalid()) {
- assert(*PragmaPackCurrentValue == SemaObj->PackStack.DefaultValue &&
+ assert(*PragmaPackCurrentValue ==
+ SemaObj->PackStack.DefaultValue.getPackNumber() &&
"Expected a default alignment value");
// Keep the current values.
} else {
- SemaObj->PackStack.CurrentValue = *PragmaPackCurrentValue;
+ Sema::AlignPackInfo Info = Sema::AlignPackInfo(
+ SemaObj->PackStack.CurrentValue.getAlignMode(),
+ *PragmaPackCurrentValue, PP.getLangOpts().AIXPragmaPack);
+ SemaObj->PackStack.CurrentValue = Info;
SemaObj->PackStack.CurrentPragmaLocation = PragmaPackCurrentLocation;
}
}
Index: clang/lib/Sema/SemaAttr.cpp
===================================================================
--- clang/lib/Sema/SemaAttr.cpp
+++ clang/lib/Sema/SemaAttr.cpp
@@ -48,18 +48,27 @@
}
void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
- // If there is no pack value, we don't need any attributes.
- if (!PackStack.CurrentValue)
+ AlignPackInfo InfoVal = PackStack.CurrentValue;
+ AlignPackInfo::Mode M = InfoVal.getAlignMode();
+ bool IsPackSet = InfoVal.IsPackSet();
+
+ // If we are not under mac68k/natural alignment mode and also there is no pack
+ // value, we don't need any attributes.
+ if (!IsPackSet && M != AlignPackInfo::Mac68k && M != AlignPackInfo::Natural)
return;
- // Otherwise, check to see if we need a max field alignment attribute.
- if (unsigned Alignment = PackStack.CurrentValue) {
- if (Alignment == Sema::kMac68kAlignmentSentinel)
- RD->addAttr(AlignMac68kAttr::CreateImplicit(Context));
- else
- RD->addAttr(MaxFieldAlignmentAttr::CreateImplicit(Context,
- Alignment * 8));
+ if (M == AlignPackInfo::Mac68k) {
+ RD->addAttr(AlignMac68kAttr::CreateImplicit(Context));
+ } else if (IsPackSet) {
+ // Check to see if we need a max field alignment attribute.
+ RD->addAttr(MaxFieldAlignmentAttr::CreateImplicit(
+ Context, InfoVal.getPackNumber() * 8));
+ }
+
+ if (getLangOpts().AIXPragmaPack && M == AlignPackInfo::Natural) {
+ RD->addAttr(AlignNaturalAttr::CreateImplicit(Context));
}
+
if (PackIncludeStack.empty())
return;
// The #pragma pack affected a record in an included file, so Clang should
@@ -205,23 +214,27 @@
void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
SourceLocation PragmaLoc) {
PragmaMsStackAction Action = Sema::PSK_Reset;
- unsigned Alignment = 0;
+ AlignPackInfo::Mode ModeVal = AlignPackInfo::Native;
switch (Kind) {
- // For all targets we support native and natural are the same.
+ // For most of the platforms we support, native and natural are the same.
+ // On AIX, native is the same as power, natural means something else.
//
// FIXME: This is not true on Darwin/PPC.
case POAK_Native:
case POAK_Power:
+ Action = Sema::PSK_Push_Set;
+ break;
case POAK_Natural:
Action = Sema::PSK_Push_Set;
- Alignment = 0;
+ if (getLangOpts().AIXPragmaPack)
+ ModeVal = AlignPackInfo::Natural;
break;
// Note that '#pragma options align=packed' is not equivalent to attribute
// packed, it has a different precedence relative to attribute aligned.
case POAK_Packed:
Action = Sema::PSK_Push_Set;
- Alignment = 1;
+ ModeVal = AlignPackInfo::Packed;
break;
case POAK_Mac68k:
@@ -231,7 +244,7 @@
return;
}
Action = Sema::PSK_Push_Set;
- Alignment = Sema::kMac68kAlignmentSentinel;
+ ModeVal = AlignPackInfo::Mac68k;
break;
case POAK_Reset:
@@ -239,7 +252,8 @@
// default.
Action = Sema::PSK_Pop;
if (PackStack.Stack.empty()) {
- if (PackStack.CurrentValue) {
+ if (PackStack.CurrentValue.getAlignMode() != AlignPackInfo::Native ||
+ PackStack.CurrentValue.IsPackAttr()) {
Action = Sema::PSK_Reset;
} else {
Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
@@ -250,7 +264,9 @@
break;
}
- PackStack.Act(PragmaLoc, Action, StringRef(), Alignment);
+ AlignPackInfo Info(ModeVal, getLangOpts().AIXPragmaPack);
+
+ PackStack.Act(PragmaLoc, Action, StringRef(), Info);
}
void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionAction Action,
@@ -299,28 +315,36 @@
// If specified then alignment must be a "small" power of two.
unsigned AlignmentVal = 0;
+ AlignPackInfo::Mode ModeVal = PackStack.CurrentValue.getAlignMode();
+
if (Alignment) {
Optional<llvm::APSInt> Val;
+ Val = Alignment->getIntegerConstantExpr(Context);
// pack(0) is like pack(), which just works out since that is what
// we use 0 for in PackAttr.
- if (Alignment->isTypeDependent() || Alignment->isValueDependent() ||
- !(Val = Alignment->getIntegerConstantExpr(Context)) ||
+ if (Alignment->isTypeDependent() || Alignment->isValueDependent() || !Val ||
!(*Val == 0 || Val->isPowerOf2()) || Val->getZExtValue() > 16) {
Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment);
return; // Ignore
}
+ if (getLangOpts().AIXPragmaPack && *Val == 0) {
+ // pack(0) does not work out on AIX.
+ Diag(PragmaLoc, diag::err_pragma_pack_invalid_alignment);
+ return; // Ignore
+ }
+
AlignmentVal = (unsigned)Val->getZExtValue();
}
if (Action == Sema::PSK_Show) {
// Show the current alignment, making sure to show the right value
// for the default.
// FIXME: This should come from the target.
- AlignmentVal = PackStack.CurrentValue;
- if (AlignmentVal == 0)
+ AlignmentVal = PackStack.CurrentValue.getPackNumber();
+ if (!PackStack.CurrentValue.IsPackSet())
AlignmentVal = 8;
- if (AlignmentVal == Sema::kMac68kAlignmentSentinel)
+ if (ModeVal == AlignPackInfo::Mac68k)
Diag(PragmaLoc, diag::warn_pragma_pack_show) << "mac68k";
else
Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal;
@@ -330,11 +354,22 @@
if (Action & Sema::PSK_Pop) {
if (Alignment && !SlotLabel.empty())
Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifier_and_alignment);
- if (PackStack.Stack.empty())
+ if (PackStack.Stack.empty()) {
+ assert(PackStack.CurrentValue.getAlignMode() == AlignPackInfo::Native &&
+ "Empty pack stack can only be at Native alignment mode.");
Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "pack" << "stack empty";
+ }
}
- PackStack.Act(PragmaLoc, Action, SlotLabel, AlignmentVal);
+ AlignPackInfo Info(ModeVal, AlignmentVal, getLangOpts().AIXPragmaPack);
+
+ // AIX pragma pack does not support identifier syntax.
+ if (getLangOpts().AIXPragmaPack && !SlotLabel.empty()) {
+ Diag(PragmaLoc, diag::warn_pragma_pack_identifer_not_supported);
+ PackStack.Act(PragmaLoc, Action, StringRef(), Info);
+ return;
+ }
+ PackStack.Act(PragmaLoc, Action, SlotLabel, Info);
}
void Sema::DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind,
@@ -481,6 +516,64 @@
VtorDispStack.Act(PragmaLoc, Action, StringRef(), Mode);
}
+template <>
+void Sema::PragmaStack<Sema::AlignPackInfo>::Act(SourceLocation PragmaLocation,
+ PragmaMsStackAction Action,
+ llvm::StringRef StackSlotLabel,
+ AlignPackInfo Value) {
+ if (Action == PSK_Reset) {
+ CurrentValue = DefaultValue;
+ CurrentPragmaLocation = PragmaLocation;
+ return;
+ }
+ if (Action & PSK_Push)
+ Stack.emplace_back(Slot(StackSlotLabel, CurrentValue, CurrentPragmaLocation,
+ PragmaLocation));
+ else if (Action & PSK_Pop) {
+ if (!StackSlotLabel.empty()) {
+ // If we've got a label, try to find it and jump there.
+ auto I = llvm::find_if(llvm::reverse(Stack), [&](const Slot &x) {
+ return x.StackSlotLabel == StackSlotLabel;
+ });
+ // If we found the label so pop from there.
+ if (I != Stack.rend()) {
+ CurrentValue = I->Value;
+ CurrentPragmaLocation = I->PragmaLocation;
+ Stack.erase(std::prev(I.base()), Stack.end());
+ }
+ } else if (Value.IsAIXStack() && Value.IsAlignAttr() &&
+ CurrentValue.IsPackAttr()) {
+ // AIX '#pragma align(reset)' would pop the stack until
+ // a current in effect pragma align is popped.
+ auto I = llvm::find_if(llvm::reverse(Stack), [&](const Slot &x) {
+ return x.Value.IsAlignAttr();
+ });
+ // If we found pragma align so pop from there.
+ if (I != Stack.rend()) {
+ Stack.erase(std::prev(I.base()), Stack.end());
+ CurrentValue = Stack.back().Value;
+ CurrentPragmaLocation = Stack.back().PragmaLocation;
+ Stack.pop_back();
+ }
+ } else if (!Stack.empty()) {
+ // AIX '#pragma align' sets the base line,
+ // and pragma pack cannot pop over the base line.
+ if (Value.IsAIXStack() && Value.IsPackAttr() &&
+ CurrentValue.IsAlignAttr())
+ return;
+
+ // We don't have a label, just pop the last entry.
+ CurrentValue = Stack.back().Value;
+ CurrentPragmaLocation = Stack.back().PragmaLocation;
+ Stack.pop_back();
+ }
+ }
+ if (Action & PSK_Set) {
+ CurrentValue = Value;
+ CurrentPragmaLocation = PragmaLocation;
+ }
+}
+
bool Sema::UnifySection(StringRef SectionName,
int SectionFlags,
DeclaratorDecl *Decl) {
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -157,7 +157,7 @@
OriginalLexicalContext(nullptr), MSStructPragmaOn(false),
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
- VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0),
+ VtorDispStack(LangOpts.getVtorDispMode()), PackStack(AlignPackInfo()),
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
CodeSegStack(nullptr), FpPragmaStack(FPOptionsOverride()),
CurInitSeg(nullptr), VisContext(nullptr),
Index: clang/lib/Parse/ParsePragma.cpp
===================================================================
--- clang/lib/Parse/ParsePragma.cpp
+++ clang/lib/Parse/ParsePragma.cpp
@@ -1734,9 +1734,11 @@
// In MSVC/gcc, #pragma pack(4) sets the alignment without affecting
// the push/pop stack.
- // In Apple gcc, #pragma pack(4) is equivalent to #pragma pack(push, 4)
+ // In Apple gcc/AIX, #pragma pack(4) is equivalent to #pragma pack(push, 4)
Action =
- PP.getLangOpts().ApplePragmaPack ? Sema::PSK_Push_Set : Sema::PSK_Set;
+ (PP.getLangOpts().ApplePragmaPack || PP.getLangOpts().AIXPragmaPack)
+ ? Sema::PSK_Push_Set
+ : Sema::PSK_Set;
} else if (Tok.is(tok::identifier)) {
const IdentifierInfo *II = Tok.getIdentifierInfo();
if (II->isStr("show")) {
@@ -1784,10 +1786,11 @@
}
}
}
- } else if (PP.getLangOpts().ApplePragmaPack) {
+ } else if (PP.getLangOpts().ApplePragmaPack ||
+ PP.getLangOpts().AIXPragmaPack) {
// In MSVC/gcc, #pragma pack() resets the alignment without affecting
// the push/pop stack.
- // In Apple gcc #pragma pack() is equivalent to #pragma pack(pop).
+ // In Apple gcc and AIX, #pragma pack() is equivalent to #pragma pack(pop).
Action = Sema::PSK_Pop;
}
@@ -1916,6 +1919,7 @@
// #pragma 'align' '=' {'native','natural','mac68k','power','reset'}
// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'}
+// #pragma 'align' '(' {'native','natural','mac68k','power','reset'} ')'
static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok,
bool IsOptions) {
Token Tok;
@@ -1930,7 +1934,12 @@
}
PP.Lex(Tok);
- if (Tok.isNot(tok::equal)) {
+ if (PP.getLangOpts().AIXPragmaPack) {
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "align";
+ return;
+ }
+ } else if (Tok.isNot(tok::equal)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_align_expected_equal)
<< IsOptions;
return;
@@ -1963,6 +1972,14 @@
return;
}
+ if (PP.getLangOpts().AIXPragmaPack) {
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "align";
+ return;
+ }
+ }
+
SourceLocation EndLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -2999,6 +2999,7 @@
Opts.DebuggerSupport = Args.hasArg(OPT_fdebugger_support);
Opts.DebuggerCastResultToId = Args.hasArg(OPT_fdebugger_cast_result_to_id);
Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal);
+ Opts.AIXPragmaPack = Args.hasArg(OPT_faix_pragma_pack);
Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack);
Opts.ModuleName = std::string(Args.getLastArgValue(OPT_fmodule_name_EQ));
Opts.CurrentModule = Opts.ModuleName;
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -5891,6 +5891,10 @@
options::OPT_fno_apple_pragma_pack, false))
CmdArgs.push_back("-fapple-pragma-pack");
+ if (Args.hasFlag(options::OPT_faix_pragma_pack,
+ options::OPT_fno_aix_pragma_pack, RawTriple.isOSAIX()))
+ CmdArgs.push_back("-faix-pragma-pack");
+
// Remarks can be enabled with any of the `-f.*optimization-record.*` flags.
if (willEmitRemarks(Args) && checkRemarksOptions(D, Args, Triple))
renderRemarksOptions(Args, CmdArgs, Triple, Input, Output, JA);
Index: clang/lib/AST/RecordLayoutBuilder.cpp
===================================================================
--- clang/lib/AST/RecordLayoutBuilder.cpp
+++ clang/lib/AST/RecordLayoutBuilder.cpp
@@ -615,6 +615,8 @@
unsigned IsMac68kAlign : 1;
+ unsigned IsNaturalAlign : 1;
+
unsigned IsMsStruct : 1;
/// UnfilledBitsInLastUnit - If the last field laid out was a bitfield,
@@ -692,9 +694,10 @@
UnpackedAlignment(CharUnits::One()),
UnadjustedAlignment(CharUnits::One()), UseExternalLayout(false),
InferAlignment(false), Packed(false), IsUnion(false),
- IsMac68kAlign(false), IsMsStruct(false), UnfilledBitsInLastUnit(0),
- LastBitfieldTypeSize(0), MaxFieldAlignment(CharUnits::Zero()),
- DataSize(0), NonVirtualSize(CharUnits::Zero()),
+ IsMac68kAlign(false), IsNaturalAlign(false), IsMsStruct(false),
+ UnfilledBitsInLastUnit(0), LastBitfieldTypeSize(0),
+ MaxFieldAlignment(CharUnits::Zero()), DataSize(0),
+ NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()),
PreferredNVAlignment(CharUnits::One()),
PaddedFieldSize(CharUnits::Zero()), PrimaryBase(nullptr),
@@ -1242,7 +1245,7 @@
// By handling a base class that is not empty, we're handling the
// "first (inherited) member".
HandledFirstNonOverlappingEmptyField = true;
- } else {
+ } else if (!IsNaturalAlign) {
UnpackedPreferredBaseAlign = UnpackedBaseAlign;
PreferredBaseAlign = BaseAlign;
}
@@ -1313,7 +1316,7 @@
Packed = D->hasAttr<PackedAttr>();
HandledFirstNonOverlappingEmptyField =
- !Context.getTargetInfo().defaultsToAIXPowerAlignment();
+ !Context.getTargetInfo().defaultsToAIXPowerAlignment() || IsNaturalAlign;
// Honor the default struct packing maximum alignment flag.
if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct) {
@@ -1325,11 +1328,17 @@
// allude to additional (more complicated) semantics, especially with regard
// to bit-fields, but gcc appears not to follow that.
if (D->hasAttr<AlignMac68kAttr>()) {
+ assert(
+ !D->hasAttr<AlignNaturalAttr>() &&
+ "Having both mac68k and natural alignment on a decl is not allowed.");
IsMac68kAlign = true;
MaxFieldAlignment = CharUnits::fromQuantity(2);
Alignment = CharUnits::fromQuantity(2);
PreferredAlignment = CharUnits::fromQuantity(2);
} else {
+ if (D->hasAttr<AlignNaturalAttr>())
+ IsNaturalAlign = true;
+
if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>())
MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment());
@@ -1919,7 +1928,7 @@
// types marked `no_unique_address` are not considered to be prior members.
CharUnits PreferredAlign = FieldAlign;
if (DefaultsToAIXPowerAlignment && !AlignIsRequired &&
- FoundFirstNonOverlappingEmptyFieldForAIX) {
+ (FoundFirstNonOverlappingEmptyFieldForAIX || IsNaturalAlign)) {
auto performBuiltinTypeAlignmentUpgrade = [&](const BuiltinType *BTy) {
if (BTy->getKind() == BuiltinType::Double ||
BTy->getKind() == BuiltinType::LongDouble) {
Index: clang/include/clang/Serialization/ASTReader.h
===================================================================
--- clang/include/clang/Serialization/ASTReader.h
+++ clang/include/clang/Serialization/ASTReader.h
@@ -25,6 +25,7 @@
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/IdentifierResolver.h"
+#include "clang/Sema/Sema.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ContinuousRangeMap.h"
#include "clang/Serialization/ModuleFile.h"
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -58,11 +58,12 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallBitVector.h"
-#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include <cmath>
#include <deque>
#include <memory>
#include <string>
@@ -477,6 +478,65 @@
PSK_Pop_Set = PSK_Pop | PSK_Set, // #pragma (pop[, id], value)
};
+ // #pragma pack and align.
+ class AlignPackInfo {
+ public:
+ enum Mode : unsigned char { Native, Natural, Packed, Mac68k };
+
+ // #pragma pack info constructor
+ AlignPackInfo(AlignPackInfo::Mode M, int Num, bool IsAIX)
+ : PackAttr(true), AlignMode(M), PackNumber(Num), AIXStack(IsAIX) {}
+
+ // #pragma align info constructor
+ AlignPackInfo(AlignPackInfo::Mode M, bool IsAIX)
+ : PackAttr(false), AlignMode(M),
+ PackNumber(M == Packed ? 1 : UninitPackVal), AIXStack(IsAIX) {}
+
+ AlignPackInfo() : AlignPackInfo(Native, false) {}
+
+ bool IsPackAttr() const { return PackAttr; }
+
+ bool IsAlignAttr() const { return !PackAttr; }
+
+ Mode getAlignMode() const { return AlignMode; }
+
+ unsigned getPackNumber() const { return PackNumber; }
+ void setPackNumber(int Num) { PackNumber = Num; }
+
+ bool IsPackSet() const {
+ // #pragma align, #pragma pack(), and #pragma pack(0) do not set the pack
+ // attriute on a decl.
+ return PackNumber != UninitPackVal && PackNumber != 0;
+ }
+
+ bool IsAIXStack() const { return AIXStack; }
+
+ bool operator==(AlignPackInfo Info) const {
+ return AlignMode == Info.AlignMode && PackNumber == Info.PackNumber;
+ }
+
+ bool operator!=(AlignPackInfo Info) const {
+ return AlignMode != Info.AlignMode || PackNumber != Info.PackNumber;
+ }
+
+ private:
+ /// \brief True if this is a pragma pack attribute,
+ // not a pragma align attribute.
+ bool PackAttr;
+
+ /// \brief The alignment mode that is in effect.
+ Mode AlignMode;
+
+ /// \brief The pack number of the stack.
+ unsigned char PackNumber;
+
+ /// \brief True if it is a AIX #pragma align/pack stack.
+ bool AIXStack;
+
+ /// \brief Uninitialized pack value.
+ constexpr static unsigned char UninitPackVal = -1;
+ };
+
template<typename ValueType>
struct PragmaStack {
struct Slot {
@@ -569,13 +629,10 @@
/// 2: Always insert vtordisps to support RTTI on partially constructed
/// objects
PragmaStack<MSVtorDispMode> VtorDispStack;
- // #pragma pack.
- // Sentinel to represent when the stack is set to mac68k alignment.
- static const unsigned kMac68kAlignmentSentinel = ~0U;
- PragmaStack<unsigned> PackStack;
+ PragmaStack<AlignPackInfo> PackStack;
// The current #pragma pack values and locations at each #include.
struct PackIncludeState {
- unsigned CurrentValue;
+ AlignPackInfo CurrentValue;
SourceLocation CurrentPragmaLocation;
bool HasNonDefaultValue, ShouldWarnOnInclude;
};
@@ -12652,6 +12709,13 @@
/// The template function declaration to be late parsed.
Decl *D;
};
+
+template <>
+void Sema::PragmaStack<Sema::AlignPackInfo>::Act(SourceLocation PragmaLocation,
+ PragmaMsStackAction Action,
+ llvm::StringRef StackSlotLabel,
+ AlignPackInfo Value);
+
} // end namespace clang
namespace llvm {
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -721,6 +721,8 @@
HelpText<"Use Apple's kernel extensions ABI">;
def fapple_pragma_pack : Flag<["-"], "fapple-pragma-pack">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable Apple gcc-compatible #pragma pack handling">;
+def faix_pragma_pack : Flag<["-"], "faix-pragma-pack">, Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Enable AIX #pragma pack handling">;
def shared_libsan : Flag<["-"], "shared-libsan">,
HelpText<"Dynamically link the sanitizer runtime">;
def static_libsan : Flag<["-"], "static-libsan">,
@@ -1507,6 +1509,7 @@
def fnested_functions : Flag<["-"], "fnested-functions">, Group<f_Group>;
def fnext_runtime : Flag<["-"], "fnext-runtime">, Group<f_Group>;
def fno_apple_pragma_pack : Flag<["-"], "fno-apple-pragma-pack">, Group<f_Group>;
+def fno_aix_pragma_pack : Flag<["-"], "fno-aix-pragma-pack">, Group<f_Group>;
def fno_asm : Flag<["-"], "fno-asm">, Group<f_Group>;
def fno_asynchronous_unwind_tables : Flag<["-"], "fno-asynchronous-unwind-tables">, Group<f_Group>;
def fno_assume_sane_operator_new : Flag<["-"], "fno-assume-sane-operator-new">, Group<f_Group>,
Index: clang/include/clang/Basic/LangOptions.def
===================================================================
--- clang/include/clang/Basic/LangOptions.def
+++ clang/include/clang/Basic/LangOptions.def
@@ -337,6 +337,8 @@
LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling")
+LANGOPT(AIXPragmaPack, 1, 0, "AIX #pragma pack handling")
+
LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST")
LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan "
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -844,6 +844,8 @@
def warn_pragma_pack_invalid_alignment : Warning<
"expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">,
InGroup<IgnoredPragmas>;
+def err_pragma_pack_invalid_alignment : Error<
+ "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">;
def warn_pragma_pack_non_default_at_include : Warning<
"non-default #pragma pack value changes the alignment of struct or union "
"members in the included file">, InGroup<PragmaPackSuspiciousInclude>,
@@ -877,6 +879,9 @@
Warning<"ms_struct may not produce Microsoft-compatible layouts for classes "
"with base classes or virtual functions">,
DefaultError, InGroup<IncompatibleMSStruct>;
+def warn_pragma_pack_identifer_not_supported : Warning<
+ "specifying an identifier within pragma pack is not supported, identifier is ignored">,
+ InGroup<PragmaPack>;
def err_section_conflict : Error<"%0 causes a section type conflict with %1">;
def err_no_base_classes : Error<"invalid use of '__super', %0 has no base classes">;
def err_invalid_super_scope : Error<"invalid use of '__super', "
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -672,6 +672,13 @@
let Documentation = [Undocumented];
}
+def AlignNatural : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let SemaHandler = 0;
+ let Documentation = [Undocumented];
+}
+
def AlwaysInline : InheritableAttr {
let Spellings = [GCC<"always_inline">, Keyword<"__forceinline">];
let Subjects = SubjectList<[Function]>;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits