Skip to content

Commit b26dd88

Browse files
committed
[clang] Stub out gcc_struct attribute
This commit implements gcc_struct attribute with the behavior similar to one in GCC. Current behavior is as follows: When C++ ABI is not "Microsoft" (i. e. when ItaniumRecordLayoutBuilder is used), [[gcc_struct]] will locally cancel the effect of -mms-bitfields on a record. If -mms-bitfields is not supplied and is not a default behavior on a target, [[gcc_struct]] will be a no-op. This should provide enough compatibility with GCC. If C++ ABI is "Microsoft", [[gcc_struct]] will currently always produce a diagnostic, since support for it is not yet implemented in MicrosoftRecordLayoutBuilder. Note, however, that all the infrastructure is ready for the future implementation. In particular, check for default value of -mms-bitfields is moved from a driver to TargetInfo, since it now non-trivially depends on other supplied flags. Also this, unfortunately, makes it impossible to use usual argument parsing for `-m{no-,}ms-bitfields`. The patch doesn't introduce any backwards-incompatible changes, except for situations when cc1 is called directly with `-mms-bitfields` option.
1 parent 850f713 commit b26dd88

22 files changed

+118
-38
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,12 @@ Attribute Changes in Clang
397397
returns a type annotated with ``[[clang::coro_lifetimebound]]`` and ``[[clang::coro_return_type]]``.
398398
This analysis can be disabled for a function by annotating the function with ``[[clang::coro_disable_lifetimebound]]``.
399399

400+
- On targets with Itanium C++ ABI, Clang now supports ``[[gnu:gcc_struct]]``
401+
with the behavior similar to one existing in GCC. In particular, whenever
402+
``-mms-bitfields`` command line option is provided (or if Microsoft-compatible
403+
structure layout is default on the target), ``[[gnu::gcc_struct]]`` requests
404+
the compiler to follow Itanium rules for the layout of an annotated structure.
405+
400406
Improvements to Clang's diagnostics
401407
-----------------------------------
402408
- Clang constexpr evaluator now prints template arguments when displaying

clang/include/clang/Basic/Attr.td

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3711,7 +3711,14 @@ def CFGuard : InheritableAttr, TargetSpecificAttr<TargetWindows> {
37113711
def MSStruct : InheritableAttr {
37123712
let Spellings = [GCC<"ms_struct">];
37133713
let Subjects = SubjectList<[Record]>;
3714-
let Documentation = [Undocumented];
3714+
let Documentation = [MSStructDocs];
3715+
let SimpleHandler = 1;
3716+
}
3717+
3718+
def GCCStruct : InheritableAttr {
3719+
let Spellings = [GCC<"gcc_struct">];
3720+
let Subjects = SubjectList<[Record]>;
3721+
let Documentation = [MSStructDocs]; // Covers this attribute too.
37153722
let SimpleHandler = 1;
37163723
}
37173724

clang/include/clang/Basic/AttrDocs.td

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7827,3 +7827,19 @@ requirement:
78277827
}
78287828
}];
78297829
}
7830+
7831+
def MSStructDocs : Documentation {
7832+
let Category = DocCatDecl;
7833+
let Content = [{
7834+
The ``ms_struct`` and ``gcc_struct`` attributes request the compiler to enter a
7835+
special record layout compatibility mode which mimics the layout of Microsoft or
7836+
Itanium C++ ABI respectively. Obviously, if the current C++ ABI matches the
7837+
requested ABI, the attribute does nothing. However, if it does not, annotated
7838+
structure or class is laid out in a special compatibility mode, which slightly
7839+
changes offsets for fields and bit-fields. The intention is to match the layout
7840+
of the requested ABI for structures which only use C features.
7841+
7842+
Note that the default behavior can be controlled by ``-mms-bitfields`` and
7843+
``-mno-ms-bitfields`` switches and via ``#pragma ms_struct``.
7844+
}];
7845+
}

clang/include/clang/Basic/DiagnosticASTKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,9 @@ def warn_npot_ms_struct : Warning<
998998
"data types with sizes that aren't a power of two">,
999999
DefaultError, InGroup<IncompatibleMSStruct>;
10001000

1001+
def err_itanium_layout_unimplemented : Error<
1002+
"Itanium-compatible layout for the Microsoft C++ ABI is not yet supported">;
1003+
10011004
// -Wpadded-bitfield
10021005
def warn_padded_struct_bitfield : Warning<
10031006
"padding %select{struct|interface|class}0 %1 with %2 "

clang/include/clang/Basic/LangOptions.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ LANGOPT(AssumeNothrowExceptionDtor , 1, 0, "Assume exception object's destructor
149149
LANGOPT(TraditionalCPP , 1, 0, "traditional CPP emulation")
150150
LANGOPT(RTTI , 1, 1, "run-time type information")
151151
LANGOPT(RTTIData , 1, 1, "emit run-time type information data")
152-
LANGOPT(MSBitfields , 1, 0, "Microsoft-compatible structure layout")
152+
ENUM_LANGOPT(LayoutCompatibility, LayoutCompatibilityKind, 2,
153+
LayoutCompatibilityKind::Default, "Microsoft-compatible structure layout")
153154
LANGOPT(MSVolatile , 1, 0, "Microsoft-compatible volatile loads and stores")
154155
LANGOPT(Freestanding, 1, 0, "freestanding implementation")
155156
LANGOPT(NoBuiltin , 1, 0, "disable builtin functions")

clang/include/clang/Basic/LangOptions.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,16 @@ class LangOptions : public LangOptionsBase {
394394

395395
enum ComplexRangeKind { CX_Full, CX_Limited, CX_Fortran };
396396

397+
enum class LayoutCompatibilityKind {
398+
/// Use default layout rules of the target.
399+
Default = 0,
400+
/// Use Itanium rules for bit-field layout and fundamental types alignment.
401+
Itanium = 1,
402+
/// Use Microsoft C++ ABI rules for bit-field layout and fundamental types
403+
/// alignment.
404+
Microsoft = 2,
405+
};
406+
397407
public:
398408
/// The used language standard.
399409
LangStandard::Kind LangStd;

clang/include/clang/Basic/TargetInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,6 +1741,10 @@ class TargetInfo : public TransferrableTargetInfo,
17411741
/// Whether to support HIP image/texture API's.
17421742
virtual bool hasHIPImageSupport() const { return true; }
17431743

1744+
virtual bool defaultsToMsStruct() const {
1745+
return getCXXABI().isMicrosoft() || getTriple().isWindowsGNUEnvironment();
1746+
}
1747+
17441748
protected:
17451749
/// Copy type and layout related info.
17461750
void copyAuxTarget(const TargetInfo *Aux);

clang/include/clang/Driver/Options.td

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4464,9 +4464,7 @@ def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">,
44644464
def : Joined<["-"], "mmacosx-version-min=">,
44654465
Group<m_Group>, Alias<mmacos_version_min_EQ>;
44664466
def mms_bitfields : Flag<["-"], "mms-bitfields">, Group<m_Group>,
4467-
Visibility<[ClangOption, CC1Option]>,
4468-
HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">,
4469-
MarshallingInfoFlag<LangOpts<"MSBitfields">>;
4467+
HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">;
44704468
def moutline : Flag<["-"], "moutline">, Group<f_clang_Group>,
44714469
Visibility<[ClangOption, CC1Option]>,
44724470
HelpText<"Enable function outlining (AArch64 only)">;
@@ -4475,6 +4473,12 @@ def mno_outline : Flag<["-"], "mno-outline">, Group<f_clang_Group>,
44754473
HelpText<"Disable function outlining (AArch64 only)">;
44764474
def mno_ms_bitfields : Flag<["-"], "mno-ms-bitfields">, Group<m_Group>,
44774475
HelpText<"Do not set the default structure layout to be compatible with the Microsoft compiler standard">;
4476+
def fms_layout_compatibility_EQ : Joined<["-"], "fms-layout-compatibility=">,
4477+
Visibility<[CC1Option]>,
4478+
HelpText<"Structure layout compatibility with Microsoft C++ ABI">,
4479+
Values<"default,itanium,microsoft">,
4480+
NormalizedValues<["Default", "Itanium", "Microsoft"]>, NormalizedValuesScope<"LangOptions::LayoutCompatibilityKind">,
4481+
MarshallingInfoEnum<LangOpts<"LayoutCompatibility">, "Default">;
44784482
def mskip_rax_setup : Flag<["-"], "mskip-rax-setup">, Group<m_Group>,
44794483
Visibility<[ClangOption, CC1Option]>,
44804484
HelpText<"Skip setting up RAX register when passing variable arguments (x86 only)">,

clang/lib/AST/Decl.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5033,7 +5033,14 @@ void RecordDecl::completeDefinition() {
50335033
/// This which can be turned on with an attribute, pragma, or the
50345034
/// -mms-bitfields command-line option.
50355035
bool RecordDecl::isMsStruct(const ASTContext &C) const {
5036-
return hasAttr<MSStructAttr>() || C.getLangOpts().MSBitfields == 1;
5036+
if (hasAttr<MSStructAttr>())
5037+
return true;
5038+
if (hasAttr<GCCStructAttr>())
5039+
return false;
5040+
auto LayoutCompatibility = C.getLangOpts().getLayoutCompatibility();
5041+
if (LayoutCompatibility == LangOptions::LayoutCompatibilityKind::Default)
5042+
return C.getTargetInfo().defaultsToMsStruct();
5043+
return LayoutCompatibility == LangOptions::LayoutCompatibilityKind::Microsoft;
50375044
}
50385045

50395046
void RecordDecl::reorderDecls(const SmallVectorImpl<Decl *> &Decls) {

clang/lib/AST/RecordLayoutBuilder.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2795,6 +2795,13 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
27952795
UseExternalLayout = Source->layoutRecordType(
27962796
RD, External.Size, External.Align, External.FieldOffsets,
27972797
External.BaseOffsets, External.VirtualBaseOffsets);
2798+
2799+
if (!RD->isMsStruct(Context)) {
2800+
auto Location = RD->getLocation();
2801+
if (Location.isValid())
2802+
Context.getDiagnostics().Report(Location,
2803+
diag::err_itanium_layout_unimplemented);
2804+
}
27982805
}
27992806

28002807
void

0 commit comments

Comments
 (0)