forked from OSchip/llvm-project
[Frontend] Add pragma align natural and sort out pragma pack stack effect
- Implemente the natural align for XL on AIX - Sort out pragma pack stack effect - Add -fxl-pragma-stack option to enable XL on AIX pragma stack effect Differential Revision: https://reviews.llvm.org/D87702
This commit is contained in:
parent
07b6aeb568
commit
f0abe2aeac
|
@ -681,6 +681,13 @@ def AlignMac68k : InheritableAttr {
|
|||
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]>;
|
||||
|
|
|
@ -854,6 +854,8 @@ def err_pragma_options_align_mac68k_target_unsupported : Error<
|
|||
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<
|
||||
warn_pragma_pack_invalid_alignment.Text>;
|
||||
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>,
|
||||
|
@ -887,6 +889,8 @@ def warn_cxx_ms_struct :
|
|||
Warning<"ms_struct may not produce Microsoft-compatible layouts for classes "
|
||||
"with base classes or virtual functions">,
|
||||
DefaultError, InGroup<IncompatibleMSStruct>;
|
||||
def err_pragma_pack_identifer_not_supported : Error<
|
||||
"specifying an identifier within `#pragma pack` is not supported on this target">;
|
||||
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', "
|
||||
|
|
|
@ -354,6 +354,8 @@ ENUM_LANGOPT(VtorDispMode, MSVtorDispMode, 2, MSVtorDispMode::ForVBaseOverride,
|
|||
|
||||
LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling")
|
||||
|
||||
LANGOPT(XLPragmaPack, 1, 0, "IBM XL #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 "
|
||||
|
|
|
@ -1026,6 +1026,8 @@ defm apple_pragma_pack : BoolFOption<"apple-pragma-pack",
|
|||
"LangOpts->ApplePragmaPack", DefaultsToFalse,
|
||||
ChangedBy<PosFlag, [], "Enable Apple gcc-compatible #pragma pack handling">,
|
||||
ResetBy<NegFlag>>;
|
||||
def fxl_pragma_pack : Flag<["-"], "fxl-pragma-pack">, Group<f_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Enable IBM XL #pragma pack handling">;
|
||||
def shared_libsan : Flag<["-"], "shared-libsan">,
|
||||
HelpText<"Dynamically link the sanitizer runtime">;
|
||||
def static_libsan : Flag<["-"], "static-libsan">,
|
||||
|
@ -1966,6 +1968,7 @@ def fmudflapth : Flag<["-"], "fmudflapth">, Group<f_Group>;
|
|||
def fmudflap : Flag<["-"], "fmudflap">, Group<f_Group>;
|
||||
def fnested_functions : Flag<["-"], "fnested-functions">, Group<f_Group>;
|
||||
def fnext_runtime : Flag<["-"], "fnext-runtime">, Group<f_Group>;
|
||||
def fno_xl_pragma_pack : Flag<["-"], "fno-xl-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>,
|
||||
|
|
|
@ -473,6 +473,108 @@ public:
|
|||
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, unsigned Num, bool IsXL)
|
||||
: PackAttr(true), AlignMode(M), PackNumber(Num), XLStack(IsXL) {
|
||||
assert(Num == PackNumber && "The pack number has been truncated.");
|
||||
}
|
||||
|
||||
// #pragma align info constructor
|
||||
AlignPackInfo(AlignPackInfo::Mode M, bool IsXL)
|
||||
: PackAttr(false), AlignMode(M),
|
||||
PackNumber(M == Packed ? 1 : UninitPackVal), XLStack(IsXL) {}
|
||||
|
||||
explicit AlignPackInfo(bool IsXL) : AlignPackInfo(Native, IsXL) {}
|
||||
|
||||
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.
|
||||
static uint32_t getRawEncoding(const AlignPackInfo &Info) {
|
||||
std::uint32_t Encoding{};
|
||||
if (Info.IsXLStack())
|
||||
Encoding |= IsXLMask;
|
||||
|
||||
Encoding |= static_cast<uint32_t>(Info.getAlignMode()) << 1;
|
||||
|
||||
if (Info.IsPackAttr())
|
||||
Encoding |= PackAttrMask;
|
||||
|
||||
Encoding |= static_cast<uint32_t>(Info.getPackNumber()) << 4;
|
||||
|
||||
return Encoding;
|
||||
}
|
||||
|
||||
static AlignPackInfo getFromRawEncoding(unsigned Encoding) {
|
||||
bool IsXL = static_cast<bool>(Encoding & IsXLMask);
|
||||
AlignPackInfo::Mode M =
|
||||
static_cast<AlignPackInfo::Mode>((Encoding & AlignModeMask) >> 1);
|
||||
int PackNumber = (Encoding & PackNumMask) >> 4;
|
||||
|
||||
if (Encoding & PackAttrMask)
|
||||
return AlignPackInfo(M, PackNumber, IsXL);
|
||||
|
||||
return AlignPackInfo(M, IsXL);
|
||||
}
|
||||
|
||||
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 IsXLStack() const { return XLStack; }
|
||||
|
||||
bool operator==(const AlignPackInfo &Info) const {
|
||||
return std::tie(AlignMode, PackNumber, PackAttr, XLStack) ==
|
||||
std::tie(Info.AlignMode, Info.PackNumber, Info.PackAttr,
|
||||
Info.XLStack);
|
||||
}
|
||||
|
||||
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 XL #pragma align/pack stack.
|
||||
bool XLStack;
|
||||
|
||||
/// \brief Uninitialized pack value.
|
||||
static constexpr unsigned char UninitPackVal = -1;
|
||||
|
||||
// Masks to encode and decode an AlignPackInfo.
|
||||
static constexpr uint32_t IsXLMask{0x0000'0001};
|
||||
static constexpr uint32_t AlignModeMask{0x0000'0006};
|
||||
static constexpr uint32_t PackAttrMask{0x00000'0008};
|
||||
static constexpr uint32_t PackNumMask{0x0000'01F0};
|
||||
};
|
||||
|
||||
template<typename ValueType>
|
||||
struct PragmaStack {
|
||||
struct Slot {
|
||||
|
@ -565,13 +667,10 @@ public:
|
|||
/// 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> AlignPackStack;
|
||||
PragmaStack<AlignPackInfo> AlignPackStack;
|
||||
// The current #pragma align/pack values and locations at each #include.
|
||||
struct AlignPackIncludeState {
|
||||
unsigned CurrentValue;
|
||||
AlignPackInfo CurrentValue;
|
||||
SourceLocation CurrentPragmaLocation;
|
||||
bool HasNonDefaultValue, ShouldWarnOnInclude;
|
||||
};
|
||||
|
@ -12750,6 +12849,13 @@ struct LateParsedTemplate {
|
|||
/// 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 {
|
||||
|
|
|
@ -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 @@ private:
|
|||
llvm::SmallVector<std::string, 2> FpPragmaStrings;
|
||||
|
||||
/// The pragma align/pack state.
|
||||
Optional<unsigned> PragmaAlignPackCurrentValue;
|
||||
Optional<Sema::AlignPackInfo> PragmaAlignPackCurrentValue;
|
||||
SourceLocation PragmaAlignPackCurrentLocation;
|
||||
struct PragmaAlignPackStackEntry {
|
||||
unsigned Value;
|
||||
Sema::AlignPackInfo Value;
|
||||
SourceLocation Location;
|
||||
SourceLocation PushLocation;
|
||||
StringRef SlotLabel;
|
||||
|
@ -2117,6 +2118,11 @@ public:
|
|||
/// 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 {
|
||||
|
|
|
@ -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"
|
||||
|
@ -589,6 +590,10 @@ public:
|
|||
/// 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);
|
||||
|
||||
|
|
|
@ -615,6 +615,8 @@ protected:
|
|||
|
||||
unsigned IsMac68kAlign : 1;
|
||||
|
||||
unsigned IsNaturalAlign : 1;
|
||||
|
||||
unsigned IsMsStruct : 1;
|
||||
|
||||
/// UnfilledBitsInLastUnit - If the last field laid out was a bitfield,
|
||||
|
@ -693,7 +695,9 @@ protected:
|
|||
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()),
|
||||
IsMsStruct(false), UnfilledBitsInLastUnit(0),
|
||||
LastBitfieldStorageUnitSize(0), MaxFieldAlignment(CharUnits::Zero()),
|
||||
DataSize(0), NonVirtualSize(CharUnits::Zero()),
|
||||
NonVirtualAlignment(CharUnits::One()),
|
||||
|
@ -1243,7 +1247,7 @@ ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
|
|||
// 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,8 +1317,6 @@ void ItaniumRecordLayoutBuilder::InitializeLayout(const Decl *D) {
|
|||
}
|
||||
|
||||
Packed = D->hasAttr<PackedAttr>();
|
||||
HandledFirstNonOverlappingEmptyField =
|
||||
!Context.getTargetInfo().defaultsToAIXPowerAlignment();
|
||||
|
||||
// Honor the default struct packing maximum alignment flag.
|
||||
if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct) {
|
||||
|
@ -1326,11 +1328,17 @@ void ItaniumRecordLayoutBuilder::InitializeLayout(const Decl *D) {
|
|||
// 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());
|
||||
|
||||
|
@ -1338,6 +1346,9 @@ void ItaniumRecordLayoutBuilder::InitializeLayout(const Decl *D) {
|
|||
UpdateAlignment(Context.toCharUnitsFromBits(MaxAlign));
|
||||
}
|
||||
|
||||
HandledFirstNonOverlappingEmptyField =
|
||||
!Context.getTargetInfo().defaultsToAIXPowerAlignment() || IsNaturalAlign;
|
||||
|
||||
// If there is an external AST source, ask it for the various offsets.
|
||||
if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
|
||||
if (ExternalASTSource *Source = Context.getExternalSource()) {
|
||||
|
@ -1921,7 +1932,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
|
|||
// 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) {
|
||||
|
|
|
@ -6106,6 +6106,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
|||
options::OPT_fno_apple_pragma_pack, false))
|
||||
CmdArgs.push_back("-fapple-pragma-pack");
|
||||
|
||||
if (Args.hasFlag(options::OPT_fxl_pragma_pack,
|
||||
options::OPT_fno_xl_pragma_pack, RawTriple.isOSAIX()))
|
||||
CmdArgs.push_back("-fxl-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);
|
||||
|
|
|
@ -2502,6 +2502,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
|
|||
|| Args.hasArg(OPT_fdump_record_layouts);
|
||||
if (Opts.FastRelaxedMath)
|
||||
Opts.setDefaultFPContractMode(LangOptions::FPM_Fast);
|
||||
Opts.XLPragmaPack = Args.hasArg(OPT_fxl_pragma_pack);
|
||||
llvm::sort(Opts.ModuleFeatures);
|
||||
Opts.NativeHalfType |= Args.hasArg(OPT_fnative_half_type);
|
||||
Opts.NativeHalfArgsAndReturns |= Args.hasArg(OPT_fnative_half_arguments_and_returns);
|
||||
|
|
|
@ -1803,9 +1803,10 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
|
|||
|
||||
// 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/XL, #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")) {
|
||||
|
@ -1853,10 +1854,12 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
|
|||
}
|
||||
}
|
||||
}
|
||||
} 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 IBM XL, #pragma pack() is equivalent to #pragma
|
||||
// pack(pop).
|
||||
Action = Sema::PSK_Pop;
|
||||
}
|
||||
|
||||
|
@ -1985,6 +1988,7 @@ void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP,
|
|||
|
||||
// #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;
|
||||
|
@ -1999,7 +2003,12 @@ static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok,
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -2032,6 +2041,14 @@ static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok,
|
|||
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)) {
|
||||
|
|
|
@ -158,7 +158,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
|
|||
OriginalLexicalContext(nullptr), MSStructPragmaOn(false),
|
||||
MSPointerToMemberRepresentationMethod(
|
||||
LangOpts.getMSPointerToMemberRepresentationMethod()),
|
||||
VtorDispStack(LangOpts.getVtorDispMode()), AlignPackStack(0),
|
||||
VtorDispStack(LangOpts.getVtorDispMode()),
|
||||
AlignPackStack(AlignPackInfo(getLangOpts().XLPragmaPack)),
|
||||
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
|
||||
CodeSegStack(nullptr), FpPragmaStack(FPOptionsOverride()),
|
||||
CurInitSeg(nullptr), VisContext(nullptr),
|
||||
|
|
|
@ -48,22 +48,31 @@ Sema::PragmaStackSentinelRAII::~PragmaStackSentinelRAII() {
|
|||
}
|
||||
|
||||
void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
|
||||
// If there is no pack value, we don't need any attributes.
|
||||
if (!AlignPackStack.CurrentValue)
|
||||
AlignPackInfo InfoVal = AlignPackStack.CurrentValue;
|
||||
AlignPackInfo::Mode M = InfoVal.getAlignMode();
|
||||
bool IsPackSet = InfoVal.IsPackSet();
|
||||
bool IsXLPragma = getLangOpts().XLPragmaPack;
|
||||
|
||||
// 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 = AlignPackStack.CurrentValue) {
|
||||
if (Alignment == Sema::kMac68kAlignmentSentinel)
|
||||
RD->addAttr(AlignMac68kAttr::CreateImplicit(Context));
|
||||
else
|
||||
RD->addAttr(MaxFieldAlignmentAttr::CreateImplicit(Context,
|
||||
Alignment * 8));
|
||||
if (M == AlignPackInfo::Mac68k && (IsXLPragma || InfoVal.IsAlignAttr())) {
|
||||
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 (IsXLPragma && M == AlignPackInfo::Natural)
|
||||
RD->addAttr(AlignNaturalAttr::CreateImplicit(Context));
|
||||
|
||||
if (AlignPackIncludeStack.empty())
|
||||
return;
|
||||
// The #pragma align/pack affected a record in an included file, so Clang
|
||||
// should warn when that the pragma was written in a file that included the
|
||||
// should warn when that pragma was written in a file that included the
|
||||
// included file.
|
||||
for (auto &AlignPackedInclude : llvm::reverse(AlignPackIncludeStack)) {
|
||||
if (AlignPackedInclude.CurrentPragmaLocation !=
|
||||
|
@ -206,23 +215,27 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
|
|||
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.
|
||||
// With XL, 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;
|
||||
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:
|
||||
|
@ -232,15 +245,15 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
|
|||
return;
|
||||
}
|
||||
Action = Sema::PSK_Push_Set;
|
||||
Alignment = Sema::kMac68kAlignmentSentinel;
|
||||
ModeVal = AlignPackInfo::Mac68k;
|
||||
break;
|
||||
|
||||
case POAK_Reset:
|
||||
// Reset just pops the top of the stack, or resets the current alignment to
|
||||
// default.
|
||||
Action = Sema::PSK_Pop;
|
||||
if (AlignPackStack.Stack.empty()) {
|
||||
if (AlignPackStack.CurrentValue) {
|
||||
if (AlignPackStack.CurrentValue.getAlignMode() != AlignPackInfo::Native ||
|
||||
AlignPackStack.CurrentValue.IsPackAttr()) {
|
||||
Action = Sema::PSK_Reset;
|
||||
} else {
|
||||
Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
|
||||
|
@ -251,7 +264,9 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
|
|||
break;
|
||||
}
|
||||
|
||||
AlignPackStack.Act(PragmaLoc, Action, StringRef(), Alignment);
|
||||
AlignPackInfo Info(ModeVal, getLangOpts().XLPragmaPack);
|
||||
|
||||
AlignPackStack.Act(PragmaLoc, Action, StringRef(), Info);
|
||||
}
|
||||
|
||||
void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionAction Action,
|
||||
|
@ -296,46 +311,68 @@ void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionA
|
|||
|
||||
void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
|
||||
StringRef SlotLabel, Expr *alignment) {
|
||||
bool IsXLPragma = getLangOpts().XLPragmaPack;
|
||||
// XL pragma pack does not support identifier syntax.
|
||||
if (IsXLPragma && !SlotLabel.empty()) {
|
||||
Diag(PragmaLoc, diag::err_pragma_pack_identifer_not_supported);
|
||||
return;
|
||||
}
|
||||
|
||||
const AlignPackInfo CurVal = AlignPackStack.CurrentValue;
|
||||
Expr *Alignment = static_cast<Expr *>(alignment);
|
||||
|
||||
// If specified then alignment must be a "small" power of two.
|
||||
unsigned AlignmentVal = 0;
|
||||
AlignPackInfo::Mode ModeVal = CurVal.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 (IsXLPragma && *Val == 0) {
|
||||
// pack(0) does not work out with XL.
|
||||
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 = AlignPackStack.CurrentValue;
|
||||
if (AlignmentVal == 0)
|
||||
AlignmentVal = 8;
|
||||
if (AlignmentVal == Sema::kMac68kAlignmentSentinel)
|
||||
AlignmentVal = CurVal.IsPackSet() ? CurVal.getPackNumber() : 8;
|
||||
if (ModeVal == AlignPackInfo::Mac68k &&
|
||||
(IsXLPragma || CurVal.IsAlignAttr()))
|
||||
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 (AlignPackStack.Stack.empty())
|
||||
if (AlignPackStack.Stack.empty()) {
|
||||
assert(CurVal.getAlignMode() == AlignPackInfo::Native &&
|
||||
"Empty pack stack can only be at Native alignment mode.");
|
||||
Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "pack" << "stack empty";
|
||||
}
|
||||
}
|
||||
|
||||
AlignPackStack.Act(PragmaLoc, Action, SlotLabel, AlignmentVal);
|
||||
AlignPackInfo Info(ModeVal, AlignmentVal, IsXLPragma);
|
||||
|
||||
AlignPackStack.Act(PragmaLoc, Action, SlotLabel, Info);
|
||||
}
|
||||
|
||||
void Sema::DiagnoseNonDefaultPragmaAlignPack(PragmaAlignPackDiagnoseKind Kind,
|
||||
|
@ -493,6 +530,68 @@ void Sema::ActOnPragmaMSVtorDisp(PragmaMsStackAction Action,
|
|||
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;
|
||||
});
|
||||
// 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.IsXLStack() && Value.IsAlignAttr() &&
|
||||
CurrentValue.IsPackAttr()) {
|
||||
// XL '#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()) {
|
||||
// xl '#pragma align' sets the baseline, and `#pragma pack` cannot pop
|
||||
// over the baseline.
|
||||
if (Value.IsXLStack() && 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,
|
||||
NamedDecl *Decl) {
|
||||
SourceLocation PragmaLocation;
|
||||
|
|
|
@ -3747,7 +3747,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
|
|||
Error("invalid pragma pack record");
|
||||
return Failure;
|
||||
}
|
||||
PragmaAlignPackCurrentValue = Record[0];
|
||||
PragmaAlignPackCurrentValue = ReadAlignPackInfo(Record[0]);
|
||||
PragmaAlignPackCurrentLocation = ReadSourceLocation(F, Record[1]);
|
||||
unsigned NumStackEntries = Record[2];
|
||||
unsigned Idx = 3;
|
||||
|
@ -3755,7 +3755,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
|
|||
PragmaAlignPackStack.clear();
|
||||
for (unsigned I = 0; I < NumStackEntries; ++I) {
|
||||
PragmaAlignPackStackEntry Entry;
|
||||
Entry.Value = Record[Idx++];
|
||||
Entry.Value = ReadAlignPackInfo(Record[Idx++]);
|
||||
Entry.Location = ReadSourceLocation(F, Record[Idx++]);
|
||||
Entry.PushLocation = ReadSourceLocation(F, Record[Idx++]);
|
||||
PragmaAlignPackStrings.push_back(ReadString(Record, Idx));
|
||||
|
@ -7892,14 +7892,15 @@ void ASTReader::UpdateSema() {
|
|||
PragmaAlignPackStack.front().PushLocation);
|
||||
DropFirst = true;
|
||||
}
|
||||
for (const auto &Entry :
|
||||
llvm::makeArrayRef(PragmaAlignPackStack).drop_front(DropFirst ? 1 : 0))
|
||||
for (const auto &Entry : llvm::makeArrayRef(PragmaAlignPackStack)
|
||||
.drop_front(DropFirst ? 1 : 0)) {
|
||||
SemaObj->AlignPackStack.Stack.emplace_back(
|
||||
Entry.SlotLabel, Entry.Value, Entry.Location, Entry.PushLocation);
|
||||
}
|
||||
if (PragmaAlignPackCurrentLocation.isInvalid()) {
|
||||
assert(*PragmaAlignPackCurrentValue ==
|
||||
SemaObj->AlignPackStack.DefaultValue &&
|
||||
"Expected a default alignment value");
|
||||
"Expected a default align and pack value");
|
||||
// Keep the current values.
|
||||
} else {
|
||||
SemaObj->AlignPackStack.CurrentValue = *PragmaAlignPackCurrentValue;
|
||||
|
|
|
@ -4159,11 +4159,11 @@ void ASTWriter::WritePackPragmaOptions(Sema &SemaRef) {
|
|||
return;
|
||||
|
||||
RecordData Record;
|
||||
Record.push_back(SemaRef.AlignPackStack.CurrentValue);
|
||||
AddAlignPackInfo(SemaRef.AlignPackStack.CurrentValue, Record);
|
||||
AddSourceLocation(SemaRef.AlignPackStack.CurrentPragmaLocation, Record);
|
||||
Record.push_back(SemaRef.AlignPackStack.Stack.size());
|
||||
for (const auto &StackEntry : SemaRef.AlignPackStack.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::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
|
|||
}
|
||||
}
|
||||
|
||||
void ASTWriter::AddAlignPackInfo(const Sema::AlignPackInfo &Info,
|
||||
RecordDataImpl &Record) {
|
||||
uint32_t Raw = Sema::AlignPackInfo::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));
|
||||
|
|
|
@ -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: "-fxl-pragma-pack"
|
|
@ -1,9 +1,9 @@
|
|||
// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \
|
||||
// RUN: -fsyntax-only %s | \
|
||||
// RUN: -fsyntax-only -fxl-pragma-pack %s | \
|
||||
// RUN: FileCheck %s
|
||||
|
||||
// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \
|
||||
// RUN: -fsyntax-only %s | \
|
||||
// RUN: -fsyntax-only -fxl-pragma-pack %s | \
|
||||
// RUN: FileCheck %s
|
||||
|
||||
namespace test1 {
|
||||
|
@ -335,6 +335,7 @@ struct C {
|
|||
short j;
|
||||
double k;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(2)
|
||||
struct D {
|
||||
|
@ -342,22 +343,26 @@ struct D {
|
|||
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);
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \
|
||||
// RUN: -fxl-pragma-pack -fsyntax-only %s | \
|
||||
// RUN: FileCheck %s
|
||||
|
||||
// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \
|
||||
// RUN: -fxl-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
|
|
@ -0,0 +1,119 @@
|
|||
// Test this without pch.
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-pragma-pack %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DSET
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-pragma-pack %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DRESET
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-pragma-pack %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DPUSH
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-pragma-pack %s -include %s -verify -fsyntax-only \
|
||||
// RUN: -Wno-pragma-pack -DPUSH_POP
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-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 -fxl-pragma-pack %s -Wno-pragma-pack -DSET -emit-pch -o %t
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DSET -verify -include-pch %t
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DRESET -emit-pch -o %t
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DRESET -verify -include-pch %t
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DPUSH -emit-pch -o %t
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DPUSH -verify -include-pch %t
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DPUSH_POP -emit-pch -o %t
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DPUSH_POP -verify -include-pch %t
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DALIGN_NATURAL -emit-pch -o %t
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown-aix -fxl-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 -fxl-pragma-pack %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DSET
|
||||
// RUN: %clang_cc1 -triple powerpc64-unknown-aix -fxl-pragma-pack %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DRESET
|
||||
// RUN: %clang_cc1 -triple powerpc64-unknown-aix -fxl-pragma-pack %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DPUSH
|
||||
// RUN: %clang_cc1 -triple powerpc64-unknown-aix -fxl-pragma-pack %s -include %s -verify -fsyntax-only \
|
||||
// RUN: -Wno-pragma-pack -DPUSH_POP
|
||||
// RUN: %clang_cc1 -triple powerpc64-unknown-aix -fxl-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 -fxl-pragma-pack %s -Wno-pragma-pack -DSET -emit-pch -o %t
|
||||
// RUN: %clang_cc1 -triple powerpc64-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DSET -verify -include-pch %t
|
||||
// RUN: %clang_cc1 -triple powerpc64-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DRESET -emit-pch -o %t
|
||||
// RUN: %clang_cc1 -triple powerpc64-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DRESET -verify -include-pch %t
|
||||
// RUN: %clang_cc1 -triple powerpc64-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DPUSH -emit-pch -o %t
|
||||
// RUN: %clang_cc1 -triple powerpc64-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DPUSH -verify -include-pch %t
|
||||
// RUN: %clang_cc1 -triple powerpc64-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DPUSH_POP -emit-pch -o %t
|
||||
// RUN: %clang_cc1 -triple powerpc64-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DPUSH_POP -verify -include-pch %t
|
||||
// RUN: %clang_cc1 -triple powerpc64-unknown-aix -fxl-pragma-pack %s -Wno-pragma-pack -DALIGN_NATURAL -emit-pch -o %t
|
||||
// RUN: %clang_cc1 -triple powerpc64-unknown-aix -fxl-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
|
|
@ -0,0 +1,229 @@
|
|||
// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \
|
||||
// RUN: -fxl-pragma-pack -verify -fsyntax-only -x c++ %s | \
|
||||
// RUN: FileCheck %s
|
||||
|
||||
// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \
|
||||
// RUN: -fxl-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-error {{specifying an identifier within `#pragma pack` is not supported on this target}}
|
||||
struct A {
|
||||
int i;
|
||||
double d;
|
||||
};
|
||||
#pragma pack(pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}}
|
||||
|
||||
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=4, preferredalign=4,
|
||||
// CHECK-NEXT: | nvsize=12, nvalign=4, preferrednvalign=4]
|
||||
|
||||
} // 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
|
Loading…
Reference in New Issue