Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -675,6 +675,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 @@ -847,6 +847,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, @@ -880,6 +882,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 @@ -352,6 +352,8 @@ LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling") +LANGOPT(XLPragmaPack, 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 @@ -774,6 +774,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">, @@ -1592,6 +1594,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,113 @@ PSK_Pop_Set = PSK_Pop | PSK_Set, // #pragma (pop[, id], value) }; + // #pragma pack and align. + class AlignPackInfo { + public: + // `Native` represents default align mode, which may vary based on the + // platform. + 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) { + assert(Num == PackNumber && "Unexpected value."); + } + + // #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(bool IsAIX) : AlignPackInfo(Native, IsAIX) {} + + AlignPackInfo() : AlignPackInfo(Native, false) {} + + // When a AlignPackInfo itself cannot be used, this returns an 32-bit + // integer encoding for it. This should only be passed to + // AlignPackInfo::getFromRawEncoding, it should not be inspected directly. + uint32_t getRawEncoding(const AlignPackInfo &Info) const { + std::uint32_t Encoding{}; + if (Info.IsAIXStack()) + Encoding |= IsAIXMask; + + Encoding |= static_cast(Info.getAlignMode()) << 1; + + if (Info.IsPackAttr()) + Encoding |= PackAttrMask; + + Encoding |= static_cast(Info.getPackNumber()) << 4; + + return Encoding; + } + + static AlignPackInfo getFromRawEncoding(unsigned Encoding) { + bool IsAIX = static_cast(Encoding & IsAIXMask); + AlignPackInfo::Mode M = + static_cast((Encoding & AlignModeMask) >> 1); + int PackNumber = (Encoding & PackNumMask) >> 4; + + if (Encoding & PackAttrMask) + return AlignPackInfo(M, PackNumber, IsAIX); + else + return AlignPackInfo(M, IsAIX); + } + + bool IsPackAttr() const { return PackAttr; } + + bool IsAlignAttr() const { return !PackAttr; } + + Mode getAlignMode() const { return AlignMode; } + + unsigned char 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; + + // Masks to encode and decode an AlignPackInfo. + static constexpr uint32_t IsAIXMask{0x0000'0001}; + static constexpr uint32_t AlignModeMask{0x0000'0006}; + static constexpr uint32_t PackAttrMask{0x00000'0008}; + static constexpr uint32_t PackNumMask{0x0000'01F0}; + }; + template struct PragmaStack { struct Slot { @@ -569,13 +676,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; }; @@ -12768,6 +12872,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/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" @@ -870,10 +871,10 @@ llvm::SmallVector FpPragmaStrings; /// The pragma pack state. - Optional PragmaPackCurrentValue; + Optional PragmaPackCurrentValue; SourceLocation PragmaPackCurrentLocation; struct PragmaPackStackEntry { - unsigned Value; + Sema::AlignPackInfo Value; SourceLocation Location; SourceLocation PushLocation; StringRef SlotLabel; @@ -2117,6 +2118,11 @@ /// Read the contents of a CXXCtorInitializer array. CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override; + /// Read a AlignPackInfo from raw form. + Sema::AlignPackInfo ReadAlignPackInfo(uint32_t Raw) const { + return Sema::AlignPackInfo::getFromRawEncoding(Raw); + } + /// Read a source location from raw form and return it in its /// originating module file's source location space. SourceLocation ReadUntranslatedSourceLocation(uint32_t Raw) const { Index: clang/include/clang/Serialization/ASTWriter.h =================================================================== --- clang/include/clang/Serialization/ASTWriter.h +++ clang/include/clang/Serialization/ASTWriter.h @@ -19,6 +19,7 @@ #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Sema.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ASTDeserializationListener.h" @@ -584,6 +585,10 @@ /// Emit a token. void AddToken(const Token &Tok, RecordDataImpl &Record); + /// Emit a AlignPackInfo. + void AddAlignPackInfo(const Sema::AlignPackInfo &Info, + RecordDataImpl &Record); + /// Emit a source location. void AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record); 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, @@ -693,7 +695,10 @@ UnpackedAlignment(CharUnits::One()), UnadjustedAlignment(CharUnits::One()), UseExternalLayout(false), InferAlignment(false), Packed(false), IsUnion(false), - IsMac68kAlign(false), IsMsStruct(false), UnfilledBitsInLastUnit(0), + IsMac68kAlign(false), + IsNaturalAlign(!Context.getTargetInfo().getTriple().isOSAIX() ? true + : false), + IsMsStruct(false), UnfilledBitsInLastUnit(0), LastBitfieldStorageUnitSize(0), MaxFieldAlignment(CharUnits::Zero()), DataSize(0), NonVirtualSize(CharUnits::Zero()), NonVirtualAlignment(CharUnits::One()), @@ -1243,7 +1248,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; } @@ -1314,7 +1319,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) { @@ -1326,11 +1331,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()); @@ -1921,7 +1932,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 @@ -6035,6 +6035,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 @@ -3087,6 +3087,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.XLPragmaPack = 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 @@ -1736,9 +1736,10 @@ // 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) - Action = - PP.getLangOpts().ApplePragmaPack ? Sema::PSK_Push_Set : Sema::PSK_Set; + // In Apple gcc/AIX, #pragma pack(4) is equivalent to #pragma pack(push, 4) + Action = (PP.getLangOpts().ApplePragmaPack || PP.getLangOpts().XLPragmaPack) + ? Sema::PSK_Push_Set + : Sema::PSK_Set; } else if (Tok.is(tok::identifier)) { const IdentifierInfo *II = Tok.getIdentifierInfo(); if (II->isStr("show")) { @@ -1786,10 +1787,11 @@ } } } - } else if (PP.getLangOpts().ApplePragmaPack) { + } else if (PP.getLangOpts().ApplePragmaPack || + PP.getLangOpts().XLPragmaPack) { // 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; } @@ -1918,6 +1920,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; @@ -1932,7 +1935,12 @@ } PP.Lex(Tok); - if (Tok.isNot(tok::equal)) { + if (PP.getLangOpts().XLPragmaPack) { + 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; @@ -1965,6 +1973,14 @@ return; } + if (PP.getLangOpts().XLPragmaPack) { + 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,8 @@ OriginalLexicalContext(nullptr), MSStructPragmaOn(false), MSPointerToMemberRepresentationMethod( LangOpts.getMSPointerToMemberRepresentationMethod()), - VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0), + VtorDispStack(LangOpts.getVtorDispMode()), + PackStack(AlignPackInfo(getLangOpts().XLPragmaPack)), 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().XLPragmaPack && 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,29 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc) { PragmaMsStackAction Action = Sema::PSK_Reset; - unsigned Alignment = 0; + AlignPackInfo::Mode ModeVal = AlignPackInfo::Native; + bool IsAIX = getLangOpts().XLPragmaPack; + 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 (IsAIX) + 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 +246,7 @@ return; } Action = Sema::PSK_Push_Set; - Alignment = Sema::kMac68kAlignmentSentinel; + ModeVal = AlignPackInfo::Mac68k; break; case POAK_Reset: @@ -239,7 +254,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 +266,9 @@ break; } - PackStack.Act(PragmaLoc, Action, StringRef(), Alignment); + AlignPackInfo Info(ModeVal, IsAIX); + + PackStack.Act(PragmaLoc, Action, StringRef(), Info); } void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionAction Action, @@ -299,42 +317,64 @@ // 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().XLPragmaPack && *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; } + // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack: // "#pragma pack(pop, identifier, n) is undefined" 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().XLPragmaPack); + + // AIX pragma pack does not support identifier syntax. + if (getLangOpts().XLPragmaPack && !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,6 +405,8 @@ Diag(PrevPackState.CurrentPragmaLocation, diag::note_pragma_pack_here); } // Warn about modified alignment after #includes. + // FIXME: PackStack may contain both #pragma align and #pragma pack + // information, we should warn about both modified align mode and alignment. if (PrevPackState.CurrentValue != PackStack.CurrentValue) { Diag(IncludeLoc, diag::warn_pragma_pack_modified_after_include); Diag(PackStack.CurrentPragmaLocation, diag::note_pragma_pack_here); @@ -376,6 +418,8 @@ return; bool IsInnermost = true; for (const auto &StackSlot : llvm::reverse(PackStack.Stack)) { + // FIXME: PackStack may contain both #pragma align and #pragma pack + // information, we should warn about both unterminated ones. Diag(StackSlot.PragmaPushLocation, diag::warn_pragma_pack_no_pop_eof); // The user might have already reset the alignment, so suggest replacing // the reset with a pop. @@ -481,6 +525,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 @@ -3748,7 +3748,7 @@ Error("invalid pragma pack record"); return Failure; } - PragmaPackCurrentValue = Record[0]; + PragmaPackCurrentValue = ReadAlignPackInfo(Record[0]); PragmaPackCurrentLocation = ReadSourceLocation(F, Record[1]); unsigned NumStackEntries = Record[2]; unsigned Idx = 3; @@ -3756,7 +3756,7 @@ PragmaPackStack.clear(); for (unsigned I = 0; I < NumStackEntries; ++I) { PragmaPackStackEntry Entry; - Entry.Value = Record[Idx++]; + Entry.Value = ReadAlignPackInfo(Record[Idx++]); Entry.Location = ReadSourceLocation(F, Record[Idx++]); Entry.PushLocation = ReadSourceLocation(F, Record[Idx++]); PragmaPackStrings.push_back(ReadString(Record, Idx)); @@ -7891,12 +7891,13 @@ DropFirst = true; } for (const auto &Entry : - llvm::makeArrayRef(PragmaPackStack).drop_front(DropFirst ? 1 : 0)) + llvm::makeArrayRef(PragmaPackStack).drop_front(DropFirst ? 1 : 0)) { SemaObj->PackStack.Stack.emplace_back(Entry.SlotLabel, Entry.Value, Entry.Location, Entry.PushLocation); + } if (PragmaPackCurrentLocation.isInvalid()) { assert(*PragmaPackCurrentValue == SemaObj->PackStack.DefaultValue && - "Expected a default alignment value"); + "Expected a default align and pack value"); // Keep the current values. } else { SemaObj->PackStack.CurrentValue = *PragmaPackCurrentValue; 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); + AddAlignPackInfo(SemaRef.PackStack.CurrentValue, Record); AddSourceLocation(SemaRef.PackStack.CurrentPragmaLocation, Record); Record.push_back(SemaRef.PackStack.Stack.size()); for (const auto &StackEntry : SemaRef.PackStack.Stack) { - Record.push_back(StackEntry.Value); + AddAlignPackInfo(StackEntry.Value, Record); AddSourceLocation(StackEntry.PragmaLocation, Record); AddSourceLocation(StackEntry.PragmaPushLocation, Record); AddString(StackEntry.StackSlotLabel, Record); @@ -5107,6 +5107,12 @@ } } +void ASTWriter::AddAlignPackInfo(const Sema::AlignPackInfo &Info, + RecordDataImpl &Record) { + uint32_t Raw = Info.getRawEncoding(Info); + Record.push_back(Raw); +} + void ASTWriter::AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record) { uint32_t Raw = Loc.getRawEncoding(); Record.push_back((Raw << 1) | (Raw >> 31)); 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/PCH/aix-pragma-pack.c =================================================================== --- /dev/null +++ clang/test/PCH/aix-pragma-pack.c @@ -0,0 +1,119 @@ +// Test this without pch. +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DSET +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DRESET +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DPUSH +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -include %s -verify -fsyntax-only \ +// RUN: -Wno-pragma-pack -DPUSH_POP +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -include %s -fsyntax-only -fdump-record-layouts \ +// RUN: -Wno-pragma-pack -DALIGN_NATURAL | \ +// RUN: FileCheck %s + +// Test with pch. +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DSET -emit-pch -o %t +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DSET -verify -include-pch %t +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DRESET -emit-pch -o %t +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DRESET -verify -include-pch %t +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DPUSH -emit-pch -o %t +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DPUSH -verify -include-pch %t +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DPUSH_POP -emit-pch -o %t +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DPUSH_POP -verify -include-pch %t +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DALIGN_NATURAL -emit-pch -o %t +// RUN: %clang_cc1 -triple powerpc-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DALIGN_NATURAL \ +// RUN: -fdump-record-layouts -include-pch %t | \ +// RUN: FileCheck %s + +// Test this without pch. +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DSET +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DRESET +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DPUSH +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -include %s -verify -fsyntax-only \ +// RUN: -Wno-pragma-pack -DPUSH_POP +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -include %s -fsyntax-only -fdump-record-layouts \ +// RUN: -Wno-pragma-pack -DALIGN_NATURAL + +// Test with pch. +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DSET -emit-pch -o %t +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DSET -verify -include-pch %t +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DRESET -emit-pch -o %t +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DRESET -verify -include-pch %t +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DPUSH -emit-pch -o %t +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DPUSH -verify -include-pch %t +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DPUSH_POP -emit-pch -o %t +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DPUSH_POP -verify -include-pch %t +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DALIGN_NATURAL -emit-pch -o %t +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -faix-pragma-pack %s -Wno-pragma-pack -DALIGN_NATURAL \ +// RUN: -fdump-record-layouts -include-pch %t | \ +// RUN: FileCheck %s + +#ifndef HEADER +#define HEADER + +#ifdef SET +#pragma pack(1) +#endif + +#ifdef RESET +#pragma pack(2) +#pragma pack() +#endif + +#ifdef PUSH +#pragma pack(1) +#pragma pack(push, 2) +#endif + +#ifdef PUSH_POP +#pragma pack(push, 4) +#pragma pack(push, 2) +#pragma pack(pop) +#endif + +#ifdef ALIGN_NATURAL +#pragma align(natural) +#endif + +#else + +#ifdef SET +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 1}} +#pragma pack(pop) +#endif + +#ifdef RESET +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}} +#pragma() +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}} +#endif + +#ifdef PUSH +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 2}} +#pragma pack(pop) +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 1}} +#pragma pack() +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}} +#pragma pack(pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}} +#endif + +#ifdef PUSH_POP +#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}} +#pragma pack(pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}} +#endif + +#ifdef ALIGN_NATURAL +struct D { + int i; + double d; +} d; + +int s = sizeof(d); + +// CHECK: *** Dumping AST Record Layout +// CHECK: 0 | struct D +// CHECK: 0 | int i +// CHECK: 8 | double d +// CHECK: | [sizeof=16, align=4, preferredalign=8] +#endif + +#endif 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