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]>; 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; +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, @@ -877,6 +879,9 @@ Warning<"ms_struct may not produce Microsoft-compatible layouts for classes " "with base classes or virtual functions">, DefaultError, InGroup; +def warn_pragma_pack_identifer_not_supported : Warning< + "specifying an identifier within pragma pack is not supported, identifier is ignored">, + InGroup; 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/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/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, Flags<[CC1Option]>, HelpText<"Enable Apple gcc-compatible #pragma pack handling">; +def faix_pragma_pack : Flag<["-"], "faix-pragma-pack">, 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; def fnext_runtime : Flag<["-"], "fnext-runtime">, Group; def fno_apple_pragma_pack : Flag<["-"], "fno-apple-pragma-pack">, Group; +def fno_aix_pragma_pack : Flag<["-"], "fno-aix-pragma-pack">, Group; def fno_asm : Flag<["-"], "fno-asm">, Group; def fno_asynchronous_unwind_tables : Flag<["-"], "fno-asynchronous-unwind-tables">, Group; def fno_assume_sane_operator_new : Flag<["-"], "fno-assume-sane-operator-new">, Group, Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -477,6 +477,71 @@ 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 + : (M == Mac68k ? Mac68kAlignmentSentinel + : 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; } + + 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==(const AlignPackInfo Info) const { + if (!AIXStack) + return PackNumber == Info.PackNumber; + + return AlignMode == Info.AlignMode && PackNumber == Info.PackNumber; + } + + bool operator!=(const AlignPackInfo Info) const { return !(*this == Info); } + + 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. + static constexpr unsigned char UninitPackVal = -1; + + /// Sentinel to represent when the stack is set to mac68k alignment. + static constexpr unsigned char Mac68kAlignmentSentinel = -2; + }; + template struct PragmaStack { struct Slot { @@ -569,13 +634,10 @@ /// 2: Always insert vtordisps to support RTTI on partially constructed /// objects PragmaStack VtorDispStack; - // #pragma pack. - // Sentinel to represent when the stack is set to mac68k alignment. - static const unsigned kMac68kAlignmentSentinel = ~0U; - PragmaStack PackStack; + PragmaStack PackStack; // The current #pragma pack values and locations at each #include. struct PackIncludeState { - unsigned CurrentValue; + AlignPackInfo CurrentValue; SourceLocation CurrentPragmaLocation; bool HasNonDefaultValue, ShouldWarnOnInclude; }; @@ -12652,6 +12714,13 @@ /// The template function declaration to be late parsed. Decl *D; }; + +template <> +void Sema::PragmaStack::Act(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + AlignPackInfo Value); + } // end namespace clang namespace llvm { 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,12 @@ 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(!Context.getTargetInfo().getTriple().isOSAIX() ? true + : 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 +1247,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 +1318,7 @@ Packed = D->hasAttr(); HandledFirstNonOverlappingEmptyField = - !Context.getTargetInfo().defaultsToAIXPowerAlignment(); + !Context.getTargetInfo().defaultsToAIXPowerAlignment() || IsNaturalAlign; // Honor the default struct packing maximum alignment flag. if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct) { @@ -1325,11 +1330,17 @@ // allude to additional (more complicated) semantics, especially with regard // to bit-fields, but gcc appears not to follow that. if (D->hasAttr()) { + assert( + !D->hasAttr() && + "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()) + IsNaturalAlign = true; + if (const MaxFieldAlignmentAttr *MFAA = D->getAttr()) MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment()); @@ -1919,7 +1930,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/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/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/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/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/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 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, @@ -365,7 +400,8 @@ Diag(PrevPackState.CurrentPragmaLocation, diag::note_pragma_pack_here); } // Warn about modified alignment after #includes. - if (PrevPackState.CurrentValue != PackStack.CurrentValue) { + if (PrevPackState.CurrentValue.getPackNumber() != + PackStack.CurrentValue.getPackNumber()) { Diag(IncludeLoc, diag::warn_pragma_pack_modified_after_include); Diag(PackStack.CurrentPragmaLocation, diag::note_pragma_pack_here); } @@ -481,6 +517,69 @@ VtorDispStack.Act(PragmaLoc, Action, StringRef(), Mode); } +template <> +void Sema::PragmaStack::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()); + if (Stack.empty()) { + CurrentValue = DefaultValue; + CurrentPragmaLocation = PragmaLocation; + } else { + 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/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/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/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/test/Layout/aix-double-struct-member.cpp =================================================================== --- clang/test/Layout/aix-double-struct-member.cpp +++ clang/test/Layout/aix-double-struct-member.cpp @@ -1,9 +1,9 @@ // RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \ -// RUN: -fsyntax-only %s | \ +// RUN: -fsyntax-only -faix-pragma-pack %s | \ // RUN: FileCheck %s // RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \ -// RUN: -fsyntax-only %s | \ +// RUN: -fsyntax-only -faix-pragma-pack %s | \ // RUN: FileCheck %s namespace test1 { @@ -335,6 +335,7 @@ short j; double k; }; +#pragma pack(pop) #pragma pack(2) struct D { @@ -342,22 +343,26 @@ 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); 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/Sema/aix-pragma-pack-and-align.c =================================================================== --- /dev/null +++ clang/test/Sema/aix-pragma-pack-and-align.c @@ -0,0 +1,231 @@ +// 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 + +namespace test10 { +#pragma pack(2) +#pragma align(reset) +struct A { + int i; + double d; +}; + +int a = sizeof(A); + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct test10::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 test10 + +// expected-no-warning