Skip to content

Commit e69abeb

Browse files
authored
Classify C++ structs as loadable or address-only (swiftlang#31707)
* Classify C++ structs as loadable or address-only C++ structs are only loadable if they are trivially copyable. Resolves SR-12472.
1 parent 2e3994e commit e69abeb

File tree

7 files changed

+379
-2
lines changed

7 files changed

+379
-2
lines changed

include/swift/AST/Decl.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -558,10 +558,12 @@ class alignas(1 << DeclAlignInBits) Decl {
558558
IsIncompatibleWithWeakReferences : 1
559559
);
560560

561-
SWIFT_INLINE_BITFIELD(StructDecl, NominalTypeDecl, 1,
561+
SWIFT_INLINE_BITFIELD(StructDecl, NominalTypeDecl, 1+1,
562562
/// True if this struct has storage for fields that aren't accessible in
563563
/// Swift.
564-
HasUnreferenceableStorage : 1
564+
HasUnreferenceableStorage : 1,
565+
/// True if this struct is imported from C++ and not trivially copyable.
566+
IsCxxNotTriviallyCopyable : 1
565567
);
566568

567569
SWIFT_INLINE_BITFIELD(EnumDecl, NominalTypeDecl, 2+1,
@@ -3822,6 +3824,14 @@ class StructDecl final : public NominalTypeDecl {
38223824
void setHasUnreferenceableStorage(bool v) {
38233825
Bits.StructDecl.HasUnreferenceableStorage = v;
38243826
}
3827+
3828+
bool isCxxNotTriviallyCopyable() const {
3829+
return Bits.StructDecl.IsCxxNotTriviallyCopyable;
3830+
}
3831+
3832+
void setIsCxxNotTriviallyCopyable(bool v) {
3833+
Bits.StructDecl.IsCxxNotTriviallyCopyable = v;
3834+
}
38253835
};
38263836

38273837
/// This is the base type for AncestryOptions. Each flag describes possible

lib/AST/Decl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4090,6 +4090,7 @@ StructDecl::StructDecl(SourceLoc StructLoc, Identifier Name, SourceLoc NameLoc,
40904090
StructLoc(StructLoc)
40914091
{
40924092
Bits.StructDecl.HasUnreferenceableStorage = false;
4093+
Bits.StructDecl.IsCxxNotTriviallyCopyable = false;
40934094
}
40944095

40954096
bool NominalTypeDecl::hasMemberwiseInitializer() const {

lib/ClangImporter/ImportDecl.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "clang/AST/DeclCXX.h"
4949
#include "clang/Basic/CharInfo.h"
5050
#include "swift/Basic/Statistic.h"
51+
#include "clang/Basic/Specifiers.h"
5152
#include "clang/Basic/TargetInfo.h"
5253
#include "clang/Lex/Preprocessor.h"
5354
#include "clang/Sema/Lookup.h"
@@ -3468,6 +3469,25 @@ namespace {
34683469

34693470
result->setHasUnreferenceableStorage(hasUnreferenceableStorage);
34703471

3472+
if (auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(decl)) {
3473+
result->setIsCxxNotTriviallyCopyable(
3474+
!cxxRecordDecl->isTriviallyCopyable());
3475+
3476+
for (auto ctor : cxxRecordDecl->ctors()) {
3477+
if (ctor->isCopyConstructor() &&
3478+
(ctor->isDeleted() || ctor->getAccess() != clang::AS_public)) {
3479+
result->setIsCxxNotTriviallyCopyable(true);
3480+
break;
3481+
}
3482+
}
3483+
3484+
if (auto dtor = cxxRecordDecl->getDestructor()) {
3485+
if (dtor->isDeleted() || dtor->getAccess() != clang::AS_public) {
3486+
result->setIsCxxNotTriviallyCopyable(true);
3487+
}
3488+
}
3489+
}
3490+
34713491
return result;
34723492
}
34733493

lib/SIL/IR/TypeLowering.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,10 @@ namespace {
14461446
if (handleResilience(structType, D, properties))
14471447
return handleAddressOnly(structType, properties);
14481448

1449+
if (D->isCxxNotTriviallyCopyable()) {
1450+
properties.setAddressOnly();
1451+
}
1452+
14491453
auto subMap = structType->getContextSubstitutionMap(&TC.M, D);
14501454

14511455
// Classify the type according to its stored properties.
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#ifndef TEST_INTEROP_CXX_CLASS_INPUTS_LOADABLE_TYPES_H
2+
#define TEST_INTEROP_CXX_CLASS_INPUTS_LOADABLE_TYPES_H
3+
4+
struct EmptyStruct {};
5+
6+
// Tests for individual special members
7+
8+
struct StructWithDefaultConstructor {
9+
StructWithDefaultConstructor() {}
10+
};
11+
12+
struct StructWithAdditionalConstructor {
13+
StructWithAdditionalConstructor() {}
14+
StructWithAdditionalConstructor(int parameter) {}
15+
};
16+
17+
struct StructWithCopyConstructor {
18+
StructWithCopyConstructor(const StructWithCopyConstructor &) {}
19+
};
20+
21+
struct StructWithInheritedCopyConstructor : StructWithCopyConstructor {};
22+
23+
struct StructWithSubobjectCopyConstructor {
24+
StructWithCopyConstructor subobject;
25+
};
26+
27+
struct StructWithDefaultedCopyConstructor {
28+
StructWithDefaultedCopyConstructor(
29+
const StructWithDefaultedCopyConstructor &) = default;
30+
};
31+
32+
struct StructWithInheritedDefaultedCopyConstructor
33+
: StructWithDefaultedCopyConstructor {};
34+
35+
struct StructWithSubobjectDefaultedCopyConstructor {
36+
StructWithDefaultedCopyConstructor subobject;
37+
};
38+
39+
struct StructWithPrivateDefaultedCopyConstructor {
40+
private:
41+
StructWithPrivateDefaultedCopyConstructor(
42+
const StructWithPrivateDefaultedCopyConstructor &) = default;
43+
};
44+
45+
struct StructWithInheritedPrivateDefaultedCopyConstructor
46+
: StructWithPrivateDefaultedCopyConstructor {};
47+
48+
struct StructWithSubobjectPrivateDefaultedCopyConstructor {
49+
StructWithPrivateDefaultedCopyConstructor subobject;
50+
};
51+
52+
struct StructWithMoveConstructor {
53+
StructWithMoveConstructor(StructWithMoveConstructor &&) {}
54+
};
55+
56+
struct StructWithInheritedMoveConstructor : StructWithMoveConstructor {};
57+
58+
struct StructWithSubobjectMoveConstructor {
59+
StructWithMoveConstructor subobject;
60+
};
61+
62+
struct StructWithCopyAssignment {
63+
StructWithCopyAssignment &operator=(const StructWithCopyAssignment &) {}
64+
};
65+
66+
struct StructWithInheritedCopyAssignment : StructWithCopyAssignment {};
67+
68+
struct StructWithSubobjectCopyAssignment {
69+
StructWithCopyAssignment subobject;
70+
};
71+
72+
struct StructWithMoveAssignment {
73+
StructWithMoveAssignment &operator=(StructWithMoveAssignment &&) {}
74+
};
75+
76+
struct StructWithInheritedMoveAssignment : StructWithMoveAssignment {};
77+
78+
struct StructWithSubobjectMoveAssignment {
79+
StructWithMoveAssignment subobject;
80+
};
81+
82+
struct StructWithDestructor {
83+
~StructWithDestructor(){}
84+
};
85+
86+
struct StructWithInheritedDestructor : StructWithDestructor {};
87+
88+
struct StructWithSubobjectDestructor {
89+
StructWithDestructor subobject;
90+
};
91+
92+
struct StructWithDefaultedDestructor {
93+
~StructWithDefaultedDestructor() = default;
94+
};
95+
96+
struct StructWithInheritedDefaultedDestructor : StructWithDefaultedDestructor {
97+
};
98+
99+
struct StructWithSubobjectDefaultedDestructor {
100+
StructWithDefaultedDestructor subobject;
101+
};
102+
103+
struct StructWithPrivateDefaultedDestructor {
104+
private:
105+
~StructWithPrivateDefaultedDestructor() = default;
106+
};
107+
108+
struct StructWithInheritedPrivateDefaultedDestructor
109+
: StructWithPrivateDefaultedDestructor {};
110+
111+
struct StructWithSubobjectPrivateDefaultedDestructor {
112+
StructWithPrivateDefaultedDestructor subobject;
113+
};
114+
115+
// Tests for common sets of special member functions.
116+
117+
struct StructTriviallyCopyableMovable {
118+
StructTriviallyCopyableMovable(const StructTriviallyCopyableMovable &) =
119+
default;
120+
StructTriviallyCopyableMovable(StructTriviallyCopyableMovable &&) = default;
121+
StructTriviallyCopyableMovable &
122+
operator=(const StructTriviallyCopyableMovable &) = default;
123+
StructTriviallyCopyableMovable &
124+
operator=(StructTriviallyCopyableMovable &&) = default;
125+
~StructTriviallyCopyableMovable() = default;
126+
};
127+
128+
struct StructNonCopyableTriviallyMovable {
129+
StructNonCopyableTriviallyMovable(const StructNonCopyableTriviallyMovable &) =
130+
delete;
131+
StructNonCopyableTriviallyMovable(StructNonCopyableTriviallyMovable &&) =
132+
default;
133+
StructNonCopyableTriviallyMovable &
134+
operator=(const StructNonCopyableTriviallyMovable &) = delete;
135+
StructNonCopyableTriviallyMovable &
136+
operator=(StructNonCopyableTriviallyMovable &&) = default;
137+
~StructNonCopyableTriviallyMovable() = default;
138+
};
139+
140+
struct StructNonCopyableNonMovable {
141+
StructNonCopyableNonMovable(const StructNonCopyableNonMovable &) = delete;
142+
StructNonCopyableNonMovable(StructNonCopyableNonMovable &&) = default;
143+
StructNonCopyableNonMovable &
144+
operator=(const StructNonCopyableNonMovable &) = delete;
145+
StructNonCopyableNonMovable &
146+
operator=(StructNonCopyableNonMovable &&) = default;
147+
~StructNonCopyableNonMovable() = default;
148+
};
149+
150+
struct StructDeletedDestructor {
151+
StructDeletedDestructor(const StructDeletedDestructor &) = default;
152+
StructDeletedDestructor(StructDeletedDestructor &&) = default;
153+
StructDeletedDestructor &operator=(const StructDeletedDestructor &) = default;
154+
StructDeletedDestructor &operator=(StructDeletedDestructor &&) = default;
155+
~StructDeletedDestructor() = delete;
156+
};
157+
158+
#endif

test/Interop/Cxx/class/Inputs/module.modulemap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ module AccessSpecifiers {
22
header "access-specifiers.h"
33
}
44

5+
module LoadableTypes {
6+
header "loadable-types.h"
7+
}
8+
59
module MemberwiseInitializer {
610
header "memberwise-initializer.h"
711
}

0 commit comments

Comments
 (0)