Skip to content

Commit d0484b0

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 096d061 commit d0484b0

21 files changed

+117
-34
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,12 @@ Attribute Changes in Clang
201201
and each must be a positive integer when provided. The parameter ``x`` is required, while ``y`` and
202202
``z`` are optional with default value of 1.
203203

204+
- On targets with Itanium C++ ABI, Clang now supports ``[[gnu:gcc_struct]]``
205+
with the behavior similar to one existing in GCC. In particular, whenever
206+
``-mms-bitfields`` command line option is provided (or if Microsoft-compatible
207+
structure layout is default on the target), ``[[gnu::gcc_struct]]`` requests
208+
the compiler to follow Itanium rules for the layout of an annotated structure.
209+
204210
Improvements to Clang's diagnostics
205211
-----------------------------------
206212
- Clang now applies syntax highlighting to the code snippets it

clang/include/clang/Basic/Attr.td

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3824,7 +3824,14 @@ def CFGuard : InheritableAttr, TargetSpecificAttr<TargetWindows> {
38243824
def MSStruct : InheritableAttr {
38253825
let Spellings = [GCC<"ms_struct">];
38263826
let Subjects = SubjectList<[Record]>;
3827-
let Documentation = [Undocumented];
3827+
let Documentation = [MSStructDocs];
3828+
let SimpleHandler = 1;
3829+
}
3830+
3831+
def GCCStruct : InheritableAttr {
3832+
let Spellings = [GCC<"gcc_struct">];
3833+
let Subjects = SubjectList<[Record]>;
3834+
let Documentation = [MSStructDocs]; // Covers this attribute too.
38283835
let SimpleHandler = 1;
38293836
}
38303837

clang/include/clang/Basic/AttrDocs.td

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8000,3 +8000,19 @@ requirement:
80008000
}
80018001
}];
80028002
}
8003+
8004+
def MSStructDocs : Documentation {
8005+
let Category = DocCatDecl;
8006+
let Content = [{
8007+
The ``ms_struct`` and ``gcc_struct`` attributes request the compiler to enter a
8008+
special record layout compatibility mode which mimics the layout of Microsoft or
8009+
Itanium C++ ABI respectively. Obviously, if the current C++ ABI matches the
8010+
requested ABI, the attribute does nothing. However, if it does not, annotated
8011+
structure or class is laid out in a special compatibility mode, which slightly
8012+
changes offsets for fields and bit-fields. The intention is to match the layout
8013+
of the requested ABI for structures which only use C features.
8014+
8015+
Note that the default behavior can be controlled by ``-mms-bitfields`` and
8016+
``-mno-ms-bitfields`` switches and via ``#pragma ms_struct``.
8017+
}];
8018+
}

clang/include/clang/Basic/DiagnosticASTKinds.td

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

1003+
def err_itanium_layout_unimplemented : Error<
1004+
"Itanium-compatible layout for the Microsoft C++ ABI is not yet supported">;
1005+
10031006
// -Wpadded-bitfield
10041007
def warn_padded_struct_bitfield : Warning<
10051008
"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
@@ -398,6 +398,16 @@ class LangOptionsBase {
398398

399399
enum ComplexRangeKind { CX_Full, CX_Limited, CX_Fortran, CX_None };
400400

401+
enum class LayoutCompatibilityKind {
402+
/// Use default layout rules of the target.
403+
Default = 0,
404+
/// Use Itanium rules for bit-field layout and fundamental types alignment.
405+
Itanium = 1,
406+
/// Use Microsoft C++ ABI rules for bit-field layout and fundamental types
407+
/// alignment.
408+
Microsoft = 2,
409+
};
410+
401411
// Define simple language options (with no accessors).
402412
#define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits;
403413
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)

clang/include/clang/Basic/TargetInfo.h

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

1774+
virtual bool defaultsToMsStruct() const {
1775+
return getCXXABI().isMicrosoft() || getTriple().isWindowsGNUEnvironment();
1776+
}
1777+
17741778
protected:
17751779
/// Copy type and layout related info.
17761780
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
@@ -4538,9 +4538,7 @@ def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">,
45384538
def : Joined<["-"], "mmacosx-version-min=">,
45394539
Group<m_Group>, Alias<mmacos_version_min_EQ>;
45404540
def mms_bitfields : Flag<["-"], "mms-bitfields">, Group<m_Group>,
4541-
Visibility<[ClangOption, CC1Option]>,
4542-
HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">,
4543-
MarshallingInfoFlag<LangOpts<"MSBitfields">>;
4541+
HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">;
45444542
def moutline : Flag<["-"], "moutline">, Group<f_clang_Group>,
45454543
Visibility<[ClangOption, CC1Option]>,
45464544
HelpText<"Enable function outlining (AArch64 only)">;
@@ -4549,6 +4547,12 @@ def mno_outline : Flag<["-"], "mno-outline">, Group<f_clang_Group>,
45494547
HelpText<"Disable function outlining (AArch64 only)">;
45504548
def mno_ms_bitfields : Flag<["-"], "mno-ms-bitfields">, Group<m_Group>,
45514549
HelpText<"Do not set the default structure layout to be compatible with the Microsoft compiler standard">;
4550+
def fms_layout_compatibility_EQ : Joined<["-"], "fms-layout-compatibility=">,
4551+
Visibility<[CC1Option]>,
4552+
HelpText<"Structure layout compatibility with Microsoft C++ ABI">,
4553+
Values<"default,itanium,microsoft">,
4554+
NormalizedValues<["Default", "Itanium", "Microsoft"]>, NormalizedValuesScope<"LangOptions::LayoutCompatibilityKind">,
4555+
MarshallingInfoEnum<LangOpts<"LayoutCompatibility">, "Default">;
45524556
def mskip_rax_setup : Flag<["-"], "mskip-rax-setup">, Group<m_Group>,
45534557
Visibility<[ClangOption, CC1Option]>,
45544558
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
@@ -5063,7 +5063,14 @@ void RecordDecl::completeDefinition() {
50635063
/// This which can be turned on with an attribute, pragma, or the
50645064
/// -mms-bitfields command-line option.
50655065
bool RecordDecl::isMsStruct(const ASTContext &C) const {
5066-
return hasAttr<MSStructAttr>() || C.getLangOpts().MSBitfields == 1;
5066+
if (hasAttr<MSStructAttr>())
5067+
return true;
5068+
if (hasAttr<GCCStructAttr>())
5069+
return false;
5070+
auto LayoutCompatibility = C.getLangOpts().getLayoutCompatibility();
5071+
if (LayoutCompatibility == LangOptions::LayoutCompatibilityKind::Default)
5072+
return C.getTargetInfo().defaultsToMsStruct();
5073+
return LayoutCompatibility == LangOptions::LayoutCompatibilityKind::Microsoft;
50675074
}
50685075

50695076
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
@@ -2802,6 +2802,13 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
28022802
UseExternalLayout = Source->layoutRecordType(
28032803
RD, External.Size, External.Align, External.FieldOffsets,
28042804
External.BaseOffsets, External.VirtualBaseOffsets);
2805+
2806+
if (!RD->isMsStruct(Context)) {
2807+
auto Location = RD->getLocation();
2808+
if (Location.isValid())
2809+
Context.getDiagnostics().Report(Location,
2810+
diag::err_itanium_layout_unimplemented);
2811+
}
28052812
}
28062813

28072814
void

0 commit comments

Comments
 (0)