Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 2a225e3

Browse files
committed
ms_struct does not imply the MS base-layout ABI; separate these
conditions in the IRGen struct layout code. rdar://20636558 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@235949 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 2dd1cb0 commit 2a225e3

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

Diff for: lib/CodeGen/CGRecordLayoutBuilder.cpp

+23-6
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,25 @@ struct CGRecordLowering {
9999
MemberInfo StorageInfo(CharUnits Offset, llvm::Type *Data) {
100100
return MemberInfo(Offset, MemberInfo::Field, Data);
101101
}
102-
bool useMSABI() {
102+
103+
/// The Microsoft bitfield layout rule allocates discrete storage
104+
/// units of the field's formal type and only combines adjacent
105+
/// fields of the same formal type. We want to emit a layout with
106+
/// these discrete storage units instead of combining them into a
107+
/// continuous run.
108+
bool isDiscreteBitFieldABI() {
103109
return Context.getTargetInfo().getCXXABI().isMicrosoft() ||
104110
D->isMsStruct(Context);
105111
}
112+
113+
/// The Itanium base layout rule allows virtual bases to overlap
114+
/// other bases, which complicates layout in specific ways.
115+
///
116+
/// Note specifically that the ms_struct attribute doesn't change this.
117+
bool isOverlappingVBaseABI() {
118+
return !Context.getTargetInfo().getCXXABI().isMicrosoft();
119+
}
120+
106121
/// \brief Wraps llvm::Type::getIntNTy with some implicit arguments.
107122
llvm::Type *getIntNType(uint64_t NumBits) {
108123
return llvm::Type::getIntNTy(Types.getLLVMContext(),
@@ -119,8 +134,9 @@ struct CGRecordLowering {
119134
/// for itanium bitfields that are smaller than their declared type.
120135
llvm::Type *getStorageType(const FieldDecl *FD) {
121136
llvm::Type *Type = Types.ConvertTypeForMem(FD->getType());
122-
return useMSABI() || !FD->isBitField() ? Type :
123-
getIntNType(std::min(FD->getBitWidthValue(Context),
137+
if (!FD->isBitField()) return Type;
138+
if (isDiscreteBitFieldABI()) return Type;
139+
return getIntNType(std::min(FD->getBitWidthValue(Context),
124140
(unsigned)Context.toBits(getSize(Type))));
125141
}
126142
/// \brief Gets the llvm Basesubobject type from a CXXRecordDecl.
@@ -365,7 +381,7 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
365381
// used to determine if the ASTRecordLayout is treating these two bitfields as
366382
// contiguous. StartBitOffset is offset of the beginning of the Run.
367383
uint64_t StartBitOffset, Tail = 0;
368-
if (useMSABI()) {
384+
if (isDiscreteBitFieldABI()) {
369385
for (; Field != FieldEnd; ++Field) {
370386
uint64_t BitOffset = getFieldBitOffset(*Field);
371387
// Zero-width bitfields end runs.
@@ -465,7 +481,7 @@ void CGRecordLowering::accumulateVBases() {
465481
// smaller than the nvsize. Here we check to see if such a base is placed
466482
// before the nvsize and set the scissor offset to that, instead of the
467483
// nvsize.
468-
if (!useMSABI())
484+
if (isOverlappingVBaseABI())
469485
for (const auto &Base : RD->vbases()) {
470486
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
471487
if (BaseDecl->isEmpty())
@@ -486,7 +502,8 @@ void CGRecordLowering::accumulateVBases() {
486502
CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl);
487503
// If the vbase is a primary virtual base of some base, then it doesn't
488504
// get its own storage location but instead lives inside of that base.
489-
if (!useMSABI() && Context.isNearlyEmpty(BaseDecl) &&
505+
if (isOverlappingVBaseABI() &&
506+
Context.isNearlyEmpty(BaseDecl) &&
490507
!hasOwnStorage(RD, BaseDecl)) {
491508
Members.push_back(MemberInfo(Offset, MemberInfo::VBase, nullptr,
492509
BaseDecl));

Diff for: test/CodeGenCXX/ms_struct.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s
2+
3+
// rdar://20636558
4+
5+
#pragma GCC diagnostic ignored "-Wincompatible-ms-struct"
6+
#define ATTR __attribute__((__ms_struct__))
7+
8+
struct ATTR VBase {
9+
virtual void foo() = 0;
10+
};
11+
12+
struct ATTR Base : virtual VBase {
13+
virtual void bar() = 0;
14+
};
15+
16+
struct ATTR Derived : Base {
17+
Derived();
18+
void foo();
19+
void bar();
20+
int value;
21+
};
22+
23+
// CHECK: [[DERIVED:%.*]] = type <{ [[BASE:%.*]], i32, [4 x i8] }>
24+
// CHECK: [[BASE]] = type { [[VBASE:%.*]] }
25+
// CHECK: [[VBASE]] = type { i32 (...)** }
26+
27+
// CHECK: define void @_ZN7DerivedC2Ev
28+
// CHECK: [[SELF:%.*]] = load [[DERIVED]]*
29+
// CHECK: [[T0:%.*]] = bitcast [[DERIVED]]* [[SELF]] to [[BASE]]*
30+
// CHECK: call void @_ZN4BaseC2Ev([[BASE]]* [[T0]], i8**
31+
// CHECK: [[T0:%.*]] = getelementptr inbounds {{.*}} [[SELF]], i32 0, i32 1
32+
// CHECK: store i32 20, i32* [[T0]],
33+
Derived::Derived() : value(20) {}

0 commit comments

Comments
 (0)