Skip to content

Commit 94b4666

Browse files
author
Gabor Horvath
committed
[cxx-interop] Support nested structs
It is really involved to change how methods and classes are emitted into the header so this patch introduces the impression of nested structs through using statements and still emits the structs themselves as top level structs. It emits them in their own namespace to avoid name collisions. This patch also had to change some names to be fully qualified to avoid some name lookup errors in case of nested structs. Moreover, nesting level of 3 and above requires C++17 because it relies on nested namespaces. Only nested structs are supported, not nested classes. Since this patch is already started to grow quite big, I decided to put it out for reviews and plan to address some of the shortcomings in a follow-up PR. rdar://118793469
1 parent 3f916f5 commit 94b4666

File tree

45 files changed

+862
-667
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+862
-667
lines changed

lib/AST/SwiftNameTranslation.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,8 @@ swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
244244
return {Unsupported, UnrepresentableGeneric};
245245
genericSignature = typeDecl->getGenericSignature();
246246
}
247-
// Nested types are not yet supported.
248-
if (!typeDecl->hasClangNode() &&
247+
// Nested classes are not yet supported.
248+
if (isa<ClassDecl>(VD) && !typeDecl->hasClangNode() &&
249249
isa_and_nonnull<NominalTypeDecl>(
250250
typeDecl->getDeclContext()->getAsDecl()))
251251
return {Unsupported, UnrepresentableNested};

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
#include "swift/AST/TypeCheckRequests.h"
2121
#include "swift/Basic/Assertions.h"
2222
#include "clang/AST/ASTContext.h"
23+
#include "clang/AST/Decl.h"
2324
#include "clang/AST/DeclTemplate.h"
2425
#include "clang/AST/NestedNameSpecifier.h"
26+
#include "llvm/Support/Casting.h"
2527

2628
using namespace swift;
2729
using namespace cxx_synthesis;
@@ -79,7 +81,6 @@ void ClangSyntaxPrinter::printModuleNamespaceQualifiersIfNeeded(
7981

8082
bool ClangSyntaxPrinter::printNominalTypeOutsideMemberDeclTemplateSpecifiers(
8183
const NominalTypeDecl *typeDecl) {
82-
// FIXME: Full qualifiers for nested types?
8384
if (!typeDecl->isGeneric())
8485
return true;
8586
printGenericSignature(
@@ -126,6 +127,26 @@ void ClangSyntaxPrinter::printClangTypeReference(const clang::Decl *typeDecl) {
126127
}
127128
}
128129

130+
bool ClangSyntaxPrinter::printNestedTypeNamespaceQualifiers(
131+
const ValueDecl *D) const {
132+
bool first = true;
133+
while (auto parent = dyn_cast_or_null<NominalTypeDecl>(
134+
D->getDeclContext()->getAsDecl())) {
135+
// C++ namespaces are imported as enums.
136+
if (parent->hasClangNode() &&
137+
isa<clang::NamespaceDecl>(parent->getClangNode().getAsDecl()))
138+
break;
139+
if (!first)
140+
os << "::";
141+
first = false;
142+
os << "__";
143+
printBaseName(parent);
144+
os << "Nested";
145+
D = parent;
146+
}
147+
return first;
148+
}
149+
129150
void ClangSyntaxPrinter::printNominalTypeReference(
130151
const NominalTypeDecl *typeDecl, const ModuleDecl *moduleContext) {
131152
if (typeDecl->hasClangNode()) {
@@ -134,7 +155,8 @@ void ClangSyntaxPrinter::printNominalTypeReference(
134155
}
135156
printModuleNamespaceQualifiersIfNeeded(typeDecl->getModuleContext(),
136157
moduleContext);
137-
// FIXME: Full qualifiers for nested types?
158+
if (!printNestedTypeNamespaceQualifiers(typeDecl))
159+
os << "::";
138160
ClangSyntaxPrinter(os).printBaseName(typeDecl);
139161
if (typeDecl->isGeneric())
140162
printGenericSignatureParams(
@@ -180,6 +202,18 @@ void ClangSyntaxPrinter::printNamespace(
180202
printNamespace([&](raw_ostream &os) { os << name; }, bodyPrinter, trivia);
181203
}
182204

205+
void ClangSyntaxPrinter::printParentNamespaceForNestedTypes(
206+
const ValueDecl *D, llvm::function_ref<void(raw_ostream &OS)> bodyPrinter,
207+
NamespaceTrivia trivia) const {
208+
if (!isa_and_nonnull<NominalTypeDecl>(D->getDeclContext()->getAsDecl())) {
209+
bodyPrinter(os);
210+
return;
211+
}
212+
printNamespace(
213+
[=](raw_ostream &os) { printNestedTypeNamespaceQualifiers(D); },
214+
bodyPrinter, trivia);
215+
}
216+
183217
void ClangSyntaxPrinter::printExternC(
184218
llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const {
185219
os << "#ifdef __cplusplus\n";
@@ -383,7 +417,8 @@ void ClangSyntaxPrinter::printPrimaryCxxTypeName(
383417
const NominalTypeDecl *type, const ModuleDecl *moduleContext) {
384418
printModuleNamespaceQualifiersIfNeeded(type->getModuleContext(),
385419
moduleContext);
386-
// FIXME: Print class qualifiers for nested class references.
420+
if (!printNestedTypeNamespaceQualifiers(type))
421+
os << "::";
387422
printBaseName(type);
388423
}
389424

lib/PrintAsClang/ClangSyntaxPrinter.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ class ClangSyntaxPrinter {
9494
bool printNominalTypeOutsideMemberDeclInnerStaticAssert(
9595
const NominalTypeDecl *typeDecl);
9696

97+
// Returns true when no qualifiers were printed.
98+
bool printNestedTypeNamespaceQualifiers(const ValueDecl *D) const;
99+
97100
/// Print out the C++ class access qualifier for the given Swift type
98101
/// declaration.
99102
///
@@ -135,6 +138,13 @@ class ClangSyntaxPrinter {
135138
llvm::function_ref<void(raw_ostream &OS)> bodyPrinter,
136139
NamespaceTrivia trivia = NamespaceTrivia::None) const;
137140

141+
/// Prints the C++ namespaces of the outer types for a nested type.
142+
/// E.g., for struct Foo { struct Bar {...} } it will print
143+
/// namespace __FooNested { ..body.. } // namespace __FooNested
144+
void printParentNamespaceForNestedTypes(
145+
const ValueDecl *D, llvm::function_ref<void(raw_ostream &OS)> bodyPrinter,
146+
NamespaceTrivia trivia = NamespaceTrivia::None) const;
147+
138148
/// Print an extern C block with given body.
139149
void
140150
printExternC(llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const;

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "DeclAndTypePrinter.h"
1414
#include "ClangSyntaxPrinter.h"
15+
#include "OutputLanguageMode.h"
1516
#include "PrimitiveTypeMapping.h"
1617
#include "PrintClangClassType.h"
1718
#include "PrintClangFunction.h"
@@ -46,6 +47,7 @@
4647
#include "clang/AST/DeclObjC.h"
4748
#include "clang/Basic/CharInfo.h"
4849
#include "clang/Basic/SourceManager.h"
50+
#include "llvm/Support/Casting.h"
4951
#include "llvm/Support/raw_ostream.h"
5052

5153
using namespace swift;
@@ -234,14 +236,33 @@ class DeclAndTypePrinter::Implementation
234236
os << ">";
235237
}
236238

239+
void printUsingForNestedType(const NominalTypeDecl *TD,
240+
const ModuleDecl *moduleContext) {
241+
if (TD->isImplicit() || TD->isSynthesized())
242+
return;
243+
os << " using ";
244+
ClangSyntaxPrinter(os).printBaseName(TD);
245+
os << "=";
246+
ClangSyntaxPrinter(os).printNominalTypeReference(TD, moduleContext);
247+
os << ";\n";
248+
}
249+
237250
/// Prints the members of a class, extension, or protocol.
238251
template <bool AllowDelayed = false, typename R>
239252
void printMembers(R &&members) {
240253
CxxEmissionScopeRAII cxxScopeRAII(owningPrinter);
241-
// FIXME: Actually track emitted members in nested
242-
// lexical scopes.
243-
// FIXME: Emit unavailable C++ decls for not emitted
244-
// nested members.
254+
// Using statements for nested types.
255+
if (outputLang == OutputLanguageMode::Cxx) {
256+
for (const Decl *member : members) {
257+
if (member->getModuleContext()->isStdlibModule())
258+
break;
259+
// TODO: support nested classes.
260+
if (isa<ClassDecl>(member))
261+
continue;
262+
if (const auto *TD = dyn_cast<NominalTypeDecl>(member))
263+
printUsingForNestedType(TD, TD->getModuleContext());
264+
}
265+
}
245266
bool protocolMembersOptional = false;
246267
for (const Decl *member : members) {
247268
auto VD = dyn_cast<ValueDecl>(member);
@@ -2796,14 +2817,16 @@ static bool isAsyncAlternativeOfOtherDecl(const ValueDecl *VD) {
27962817
return false;
27972818
}
27982819

2799-
static bool isStringNestedType(const ValueDecl *VD, StringRef Typename) {
2820+
namespace swift {
2821+
bool isStringNestedType(const ValueDecl *VD, StringRef Typename) {
28002822
auto ctx = VD->getDeclContext();
28012823
return VD->hasName() && VD->getName().isSimpleName() &&
28022824
VD->getBaseIdentifier().str() == Typename &&
28032825
isa<ExtensionDecl>(ctx->getAsDecl()) &&
28042826
cast<ExtensionDecl>(ctx->getAsDecl())->getExtendedNominal() ==
28052827
VD->getASTContext().getStringDecl();
28062828
}
2829+
} // namespace swift
28072830

28082831
static bool hasExposeAttr(const ValueDecl *VD) {
28092832
if (isa<NominalTypeDecl>(VD) && VD->getModuleContext()->isStdlibModule()) {

lib/PrintAsClang/DeclAndTypePrinter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ class DeclAndTypePrinter {
148148
getObjectTypeAndOptionality(const ValueDecl *D, Type ty);
149149
};
150150

151+
bool isStringNestedType(const ValueDecl *VD, StringRef Typename);
152+
151153
} // end namespace swift
152154

153155
#endif

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "swift/Basic/Assertions.h"
3232
#include "swift/Basic/SourceManager.h"
3333
#include "swift/ClangImporter/ClangImporter.h"
34+
#include "swift/SIL/SILInstruction.h"
3435
#include "swift/Strings.h"
3536

3637
#include "clang/AST/Decl.h"
@@ -218,7 +219,10 @@ class ModuleWriter {
218219
return state.first == EmissionState::Defined;
219220
}
220221

221-
bool require(const TypeDecl *D) {
222+
bool require(const TypeDecl *D) { return requireTypes(D, declsToWrite); }
223+
224+
template <typename T>
225+
bool requireTypes(const TypeDecl *D, T &types) {
222226
if (addImport(D)) {
223227
seenTypes[D] = { EmissionState::Defined, true };
224228
return true;
@@ -229,7 +233,7 @@ class ModuleWriter {
229233
case EmissionState::NotYetDefined:
230234
case EmissionState::DefinitionRequested:
231235
state.first = EmissionState::DefinitionRequested;
232-
declsToWrite.push_back(D);
236+
types.push_back(D);
233237
return false;
234238
case EmissionState::Defined:
235239
return true;
@@ -364,23 +368,31 @@ class ModuleWriter {
364368
}
365369

366370
bool hadAnyDelayedMembers = false;
367-
SmallVector<ValueDecl *, 4> nestedTypes;
371+
SmallVector<const ValueDecl *, 4> nestedTypes;
368372
for (auto member : members) {
369373
PrettyStackTraceDecl loopEntry("printing for member", member);
370374
auto VD = dyn_cast<ValueDecl>(member);
371375
if (!VD || !printer.shouldInclude(VD))
372376
continue;
373377

374378
// Catch nested types and emit their definitions /after/ this class.
375-
if (isa<TypeDecl>(VD)) {
376-
// Don't emit nested types that are just implicitly @objc.
377-
// You should have to opt into this, since they are even less
378-
// namespaced than usual.
379-
if (std::any_of(VD->getAttrs().begin(), VD->getAttrs().end(),
380-
[](const DeclAttribute *attr) {
381-
return isa<ObjCAttr>(attr) && !attr->isImplicit();
382-
})) {
383-
nestedTypes.push_back(VD);
379+
if (const auto *TD = dyn_cast<TypeDecl>(VD)) {
380+
if (outputLangMode == OutputLanguageMode::Cxx) {
381+
if (!isa<TypeAliasDecl>(TD) && !isStringNestedType(VD, "UTF8View") &&
382+
!isStringNestedType(VD, "Index")) {
383+
forwardDeclareType(TD);
384+
requireTypes(TD, nestedTypes);
385+
}
386+
} else {
387+
// Don't emit nested types that are just implicitly @objc.
388+
// You should have to opt into this, since they are even less
389+
// namespaced than usual.
390+
if (std::any_of(VD->getAttrs().begin(), VD->getAttrs().end(),
391+
[](const DeclAttribute *attr) {
392+
return isa<ObjCAttr>(attr) && !attr->isImplicit();
393+
})) {
394+
nestedTypes.push_back(VD);
395+
}
384396
}
385397
continue;
386398
}
@@ -1060,11 +1072,14 @@ EmittedClangHeaderDependencyInfo swift::printModuleContentsAsCxx(
10601072
os << "}\n";
10611073
}
10621074

1075+
os << "#pragma clang diagnostic push\n";
1076+
os << "#pragma clang diagnostic ignored \"-Wreserved-identifier\"\n";
10631077
// Construct a C++ namespace for the module.
10641078
ClangSyntaxPrinter(os).printNamespace(
10651079
[&](raw_ostream &os) { ClangSyntaxPrinter(os).printBaseName(&M); },
10661080
[&](raw_ostream &os) { os << moduleOS.str(); },
10671081
ClangSyntaxPrinter::NamespaceTrivia::AttributeSwiftPrivate, &M);
1082+
os << "#pragma clang diagnostic pop\n";
10681083

10691084
if (M.isStdlibModule()) {
10701085
os << "#pragma clang diagnostic pop\n";

0 commit comments

Comments
 (0)