Skip to content

Commit 858383c

Browse files
authored
Merge pull request #83173 from DougGregor/shared-reference-of-incomplete
[Clang importer] Import incomplete SWIFT_SHARED_REFERENCE types
2 parents 40ed86e + 76c0e93 commit 858383c

File tree

11 files changed

+220
-56
lines changed

11 files changed

+220
-56
lines changed

include/swift/ClangImporter/ClangImporter.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,10 @@ getCxxReferencePointeeTypeOrNone(const clang::Type *type);
706706
/// Returns true if the given type is a C++ `const` reference type.
707707
bool isCxxConstReferenceType(const clang::Type *type);
708708

709+
/// Determine whether the given Clang record declaration has one of the
710+
/// attributes that makes it import as a reference types.
711+
bool hasImportAsRefAttr(const clang::RecordDecl *decl);
712+
709713
/// Determine whether this typedef is a CF type.
710714
bool isCFTypeDecl(const clang::TypedefNameDecl *Decl);
711715

@@ -804,16 +808,18 @@ std::optional<T> matchSwiftAttrConsideringInheritance(
804808

805809
if (const auto *recordDecl = llvm::dyn_cast<clang::CXXRecordDecl>(decl)) {
806810
std::optional<T> result;
807-
recordDecl->forallBases([&](const clang::CXXRecordDecl *base) -> bool {
808-
if (auto baseMatch = matchSwiftAttr<T>(base, patterns)) {
809-
result = baseMatch;
810-
return false;
811-
}
811+
if (recordDecl->isCompleteDefinition()) {
812+
recordDecl->forallBases([&](const clang::CXXRecordDecl *base) -> bool {
813+
if (auto baseMatch = matchSwiftAttr<T>(base, patterns)) {
814+
result = baseMatch;
815+
return false;
816+
}
812817

813-
return true;
814-
});
818+
return true;
819+
});
815820

816-
return result;
821+
return result;
822+
}
817823
}
818824

819825
return std::nullopt;

lib/ClangImporter/ClangImporter.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5312,7 +5312,8 @@ ClangTypeEscapability::evaluate(Evaluator &evaluator,
53125312
if (desc.annotationOnly)
53135313
return CxxEscapability::Unknown;
53145314
auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
5315-
if (!cxxRecordDecl || cxxRecordDecl->isAggregate()) {
5315+
if (recordDecl->getDefinition() &&
5316+
(!cxxRecordDecl || cxxRecordDecl->isAggregate())) {
53165317
if (cxxRecordDecl) {
53175318
for (auto base : cxxRecordDecl->bases()) {
53185319
auto baseEscapability = evaluateEscapability(
@@ -6346,8 +6347,9 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
63466347
}
63476348

63486349
// If this is a C++ record, look through any base classes.
6349-
if (auto cxxRecord =
6350-
dyn_cast<clang::CXXRecordDecl>(recordDecl->getClangDecl())) {
6350+
const clang::CXXRecordDecl *cxxRecord;
6351+
if ((cxxRecord = dyn_cast<clang::CXXRecordDecl>(recordDecl->getClangDecl())) &&
6352+
cxxRecord->isCompleteDefinition()) {
63516353
// Capture the arity of already found members in the
63526354
// current record, to avoid adding ambiguous members
63536355
// from base classes.
@@ -7813,7 +7815,7 @@ ClangImporter::createEmbeddedBridgingHeaderCacheKey(
78137815
"ChainedHeaderIncludeTree -> EmbeddedHeaderIncludeTree");
78147816
}
78157817

7816-
static bool hasImportAsRefAttr(const clang::RecordDecl *decl) {
7818+
bool importer::hasImportAsRefAttr(const clang::RecordDecl *decl) {
78177819
return decl->hasAttrs() && llvm::any_of(decl->getAttrs(), [](auto *attr) {
78187820
if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr))
78197821
return swiftAttr->getAttribute() == "import_reference" ||

lib/ClangImporter/ImportDecl.cpp

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,10 @@ using MirroredMethodEntry =
846846
std::tuple<const clang::ObjCMethodDecl*, ProtocolDecl*, bool /*isAsync*/>;
847847

848848
static bool areRecordFieldsComplete(const clang::CXXRecordDecl *decl) {
849+
// If the type is incomplete, then the fields are not complete.
850+
if (!decl->isCompleteDefinition())
851+
return false;
852+
849853
for (const auto *f : decl->fields()) {
850854
auto *fieldRecord = f->getType()->getAsCXXRecordDecl();
851855
if (fieldRecord) {
@@ -2101,18 +2105,21 @@ namespace {
21012105
if (decl->isInterface())
21022106
return nullptr;
21032107

2104-
if (!decl->getDefinition()) {
2108+
bool incompleteTypeAsReference = false;
2109+
if (auto def = decl->getDefinition()) {
2110+
// Continue with the definition of the type.
2111+
decl = def;
2112+
} else if (recordHasReferenceSemantics(decl)) {
2113+
// Incomplete types are okay if the resulting type has reference
2114+
// semantics.
2115+
incompleteTypeAsReference = true;
2116+
} else {
21052117
Impl.addImportDiagnostic(
21062118
decl,
21072119
Diagnostic(diag::incomplete_record, Impl.SwiftContext.AllocateCopy(
21082120
decl->getNameAsString())),
21092121
decl->getLocation());
2110-
}
21112122

2112-
// FIXME: Figure out how to deal with incomplete types, since that
2113-
// notion doesn't exist in Swift.
2114-
decl = decl->getDefinition();
2115-
if (!decl) {
21162123
forwardDeclaration = true;
21172124
return nullptr;
21182125
}
@@ -2128,7 +2135,7 @@ namespace {
21282135
}
21292136

21302137
// Don't import nominal types that are over-aligned.
2131-
if (Impl.isOverAligned(decl)) {
2138+
if (decl->isCompleteDefinition() && Impl.isOverAligned(decl)) {
21322139
Impl.addImportDiagnostic(
21332140
decl, Diagnostic(
21342141
diag::record_over_aligned,
@@ -2139,6 +2146,9 @@ namespace {
21392146

21402147
auto isNonTrivialDueToAddressDiversifiedPtrAuth =
21412148
[](const clang::RecordDecl *decl) {
2149+
if (!decl->isCompleteDefinition())
2150+
return true;
2151+
21422152
for (auto *field : decl->fields()) {
21432153
if (!field->getType().isNonTrivialToPrimitiveCopy()) {
21442154
continue;
@@ -2194,7 +2204,8 @@ namespace {
21942204
*correctSwiftName);
21952205

21962206
auto dc =
2197-
Impl.importDeclContextOf(decl, importedName.getEffectiveContext());
2207+
Impl.importDeclContextOf(decl, importedName.getEffectiveContext(),
2208+
incompleteTypeAsReference);
21982209
if (!dc) {
21992210
Impl.addImportDiagnostic(
22002211
decl, Diagnostic(
@@ -2241,9 +2252,11 @@ namespace {
22412252
// solution would be to turn them into members and add conversion
22422253
// functions.
22432254
if (auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(decl)) {
2244-
for (auto base : cxxRecordDecl->bases()) {
2245-
if (auto *baseRecordDecl = base.getType()->getAsCXXRecordDecl()) {
2246-
Impl.importDecl(baseRecordDecl, getVersion());
2255+
if (cxxRecordDecl->isCompleteDefinition()) {
2256+
for (auto base : cxxRecordDecl->bases()) {
2257+
if (auto *baseRecordDecl = base.getType()->getAsCXXRecordDecl()) {
2258+
Impl.importDecl(baseRecordDecl, getVersion());
2259+
}
22472260
}
22482261
}
22492262
}
@@ -2451,15 +2464,18 @@ namespace {
24512464

24522465
const clang::CXXRecordDecl *cxxRecordDecl =
24532466
dyn_cast<clang::CXXRecordDecl>(decl);
2454-
bool hasBaseClasses = cxxRecordDecl && !cxxRecordDecl->bases().empty();
2467+
bool hasBaseClasses = cxxRecordDecl &&
2468+
cxxRecordDecl->isCompleteDefinition() &&
2469+
!cxxRecordDecl->bases().empty();
24552470
if (hasBaseClasses) {
24562471
hasUnreferenceableStorage = true;
24572472
hasMemberwiseInitializer = false;
24582473
}
24592474

24602475
bool needsEmptyInitializer = true;
24612476
if (cxxRecordDecl) {
2462-
needsEmptyInitializer = !cxxRecordDecl->isAbstract() &&
2477+
needsEmptyInitializer = cxxRecordDecl->isCompleteDefinition() &&
2478+
!cxxRecordDecl->isAbstract() &&
24632479
(!cxxRecordDecl->hasDefaultConstructor() ||
24642480
cxxRecordDecl->ctors().empty());
24652481
}
@@ -2503,7 +2519,8 @@ namespace {
25032519
// only when the same is possible in C++. While we could check for that
25042520
// exactly, checking whether the C++ class is an aggregate
25052521
// (C++ [dcl.init.aggr]) has the same effect.
2506-
bool isAggregate = !cxxRecordDecl || cxxRecordDecl->isAggregate();
2522+
bool isAggregate = decl->isCompleteDefinition() &&
2523+
(!cxxRecordDecl || cxxRecordDecl->isAggregate());
25072524
if ((hasReferenceableFields && hasMemberwiseInitializer && isAggregate) ||
25082525
forceMemberwiseInitializer) {
25092526
// The default zero initializer suppresses the implicit value
@@ -2907,7 +2924,13 @@ namespace {
29072924
if (!Impl.SwiftContext.LangOpts.EnableCXXInterop)
29082925
return VisitRecordDecl(decl);
29092926

2910-
if (!decl->getDefinition()) {
2927+
if (auto def = decl->getDefinition()) {
2928+
// Continue with the definition of the type.
2929+
decl = def;
2930+
} else if (recordHasReferenceSemantics(decl)) {
2931+
// Incomplete types are okay if the resulting type has reference
2932+
// semantics.
2933+
} else {
29112934
Impl.addImportDiagnostic(
29122935
decl,
29132936
Diagnostic(diag::incomplete_record, Impl.SwiftContext.AllocateCopy(
@@ -2923,10 +2946,7 @@ namespace {
29232946
Impl.diagnose(HeaderLoc(attr.second),
29242947
diag::private_fileid_attr_here);
29252948
}
2926-
}
29272949

2928-
decl = decl->getDefinition();
2929-
if (!decl) {
29302950
forwardDeclaration = true;
29312951
return nullptr;
29322952
}
@@ -3143,12 +3163,14 @@ namespace {
31433163
void
31443164
addExplicitProtocolConformances(NominalTypeDecl *decl,
31453165
const clang::CXXRecordDecl *clangDecl) {
3146-
// Propagate conforms_to attribute from public base classes.
3147-
for (auto base : clangDecl->bases()) {
3148-
if (base.getAccessSpecifier() != clang::AccessSpecifier::AS_public)
3149-
continue;
3150-
if (auto *baseClangDecl = base.getType()->getAsCXXRecordDecl())
3151-
addExplicitProtocolConformances(decl, baseClangDecl);
3166+
if (clangDecl->isCompleteDefinition()) {
3167+
// Propagate conforms_to attribute from public base classes.
3168+
for (auto base : clangDecl->bases()) {
3169+
if (base.getAccessSpecifier() != clang::AccessSpecifier::AS_public)
3170+
continue;
3171+
if (auto *baseClangDecl = base.getType()->getAsCXXRecordDecl())
3172+
addExplicitProtocolConformances(decl, baseClangDecl);
3173+
}
31523174
}
31533175

31543176
if (!clangDecl->hasAttrs())
@@ -10236,7 +10258,8 @@ ClangImporter::Implementation::importDeclForDeclContext(
1023610258
DeclContext *
1023710259
ClangImporter::Implementation::importDeclContextOf(
1023810260
const clang::Decl *decl,
10239-
EffectiveClangContext context)
10261+
EffectiveClangContext context,
10262+
bool allowForwardDeclaration)
1024010263
{
1024110264
DeclContext *importedDC = nullptr;
1024210265
switch (context.getKind()) {
@@ -10265,7 +10288,7 @@ ClangImporter::Implementation::importDeclContextOf(
1026510288
}
1026610289

1026710290
if (dc->isTranslationUnit()) {
10268-
if (auto *module = getClangModuleForDecl(decl))
10291+
if (auto *module = getClangModuleForDecl(decl, allowForwardDeclaration))
1026910292
return module;
1027010293
else
1027110294
return nullptr;
@@ -10529,7 +10552,9 @@ void ClangImporter::Implementation::loadAllMembersOfRecordDecl(
1052910552
}
1053010553

1053110554
// If this is a C++ record, look through the base classes too.
10532-
if (auto cxxRecord = dyn_cast<clang::CXXRecordDecl>(clangRecord)) {
10555+
const clang::CXXRecordDecl *cxxRecord;
10556+
if ((cxxRecord = dyn_cast<clang::CXXRecordDecl>(clangRecord)) &&
10557+
cxxRecord->isCompleteDefinition()) {
1053310558
for (auto base : cxxRecord->bases()) {
1053410559
if (skipIfNonPublic && base.getAccessSpecifier() != clang::AS_public)
1053510560
continue;

lib/ClangImporter/ImporterImpl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1227,7 +1227,8 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
12271227
/// \returns The imported declaration context, or null if it could not
12281228
/// be converted.
12291229
DeclContext *importDeclContextOf(const clang::Decl *D,
1230-
EffectiveClangContext context);
1230+
EffectiveClangContext context,
1231+
bool allowForwardDeclaration = false);
12311232

12321233
/// Determine whether the given declaration is considered
12331234
/// 'unavailable' in Swift.

lib/ClangImporter/SwiftDeclSynthesizer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2551,7 +2551,7 @@ llvm::SmallVector<clang::CXXMethodDecl *, 4>
25512551
SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef(
25522552
const clang::CXXRecordDecl *cxxRecordDecl) {
25532553

2554-
if (cxxRecordDecl->isAbstract())
2554+
if (!cxxRecordDecl->isCompleteDefinition() || cxxRecordDecl->isAbstract())
25552555
return {};
25562556

25572557
clang::ASTContext &clangCtx = cxxRecordDecl->getASTContext();

lib/ClangImporter/SwiftLookupTable.cpp

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,27 +1881,19 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table,
18811881
if (shouldSuppressDeclImport(named))
18821882
return;
18831883

1884-
// Leave incomplete struct/enum/union types out of the table; Swift only
1885-
// handles pointers to them.
1886-
// FIXME: At some point we probably want to be importing incomplete types,
1887-
// so that pointers to different incomplete types themselves have distinct
1888-
// types. At that time it will be necessary to make the decision of whether
1889-
// or not to import an incomplete type declaration based on whether it's
1890-
// actually the struct backing a CF type:
1891-
//
1892-
// typedef struct CGColor *CGColorRef;
1893-
//
1894-
// The best way to do this is probably to change CFDatabase.def to include
1895-
// struct names when relevant, not just pointer names. That way we can check
1896-
// both CFDatabase.def and the objc_bridge attribute and cover all our bases.
1884+
// Leave incomplete struct/enum/union types out of the table, unless they
1885+
// are types that will be imported as reference types (e.g., CF types or
1886+
// those that use SWIFT_SHARED_REFERENCE).
18971887
if (auto *tagDecl = dyn_cast<clang::TagDecl>(named)) {
18981888
// We add entries for ClassTemplateSpecializations that don't have
18991889
// definition. It's possible that the decl will be instantiated by
19001890
// SwiftDeclConverter later on. We cannot force instantiating
19011891
// ClassTemplateSPecializations here because we're currently writing the
19021892
// AST, so we cannot modify it.
19031893
if (!isa<clang::ClassTemplateSpecializationDecl>(named) &&
1904-
!tagDecl->getDefinition()) {
1894+
!tagDecl->getDefinition() &&
1895+
!(isa<clang::RecordDecl>(tagDecl) &&
1896+
hasImportAsRefAttr(cast<clang::RecordDecl>(tagDecl)))) {
19051897
return;
19061898
}
19071899
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
Name: ReferenceCounted
3+
Tags:
4+
- Name: OpaqueRefImpl
5+
SwiftImportAs: reference
6+
SwiftRetainOp: OPRetain
7+
SwiftReleaseOp: OPRelease
8+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include <stdlib.h>
2+
#include <stdio.h>
3+
4+
#include "reference-counted.h"
5+
6+
typedef struct IncompleteImpl {
7+
unsigned refCount;
8+
double weight;
9+
} *Incomplete;
10+
11+
12+
Incomplete Incomplete_create(double weight) {
13+
Incomplete result = (Incomplete)malloc(sizeof(struct IncompleteImpl));
14+
result->refCount = 1;
15+
result->weight = weight;
16+
return result;
17+
}
18+
19+
void INRetain(Incomplete i) {
20+
i->refCount++;
21+
}
22+
23+
void INRelease(Incomplete i) {
24+
i->refCount--;
25+
if (i->refCount == 0) {
26+
printf("Destroyed instance containing weight %f\n", i->weight);
27+
free(i);
28+
}
29+
}
30+
31+
double Incomplete_getWeight(Incomplete i) {
32+
return i->weight;
33+
}
34+
35+
struct OpaqueRefImpl {
36+
unsigned refCount;
37+
};
38+
39+
OpaqueRef Opaque_create(void) {
40+
OpaqueRef result = (OpaqueRef)malloc(sizeof(struct OpaqueRefImpl));
41+
result->refCount = 1;
42+
return result;
43+
}
44+
45+
void OPRetain(OpaqueRef i) {
46+
i->refCount++;
47+
}
48+
49+
void OPRelease(OpaqueRef i) {
50+
i->refCount--;
51+
if (i->refCount == 0) {
52+
printf("Destroyed OpaqueRef instance\n");
53+
free(i);
54+
}
55+
}

test/Interop/Cxx/foreign-reference/Inputs/module.modulemap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ module WitnessTable {
3535

3636
module ReferenceCounted {
3737
header "reference-counted.h"
38-
requires cplusplus
3938
}
4039

4140
module ReferenceCountedObjCProperty {

0 commit comments

Comments
 (0)