Skip to content

Commit 863d2e4

Browse files
authored
Merge pull request #75477 from swiftlang/gaborh/nested-structs
[cxx-interop] Support nested structs
2 parents 75f00fe + 94b4666 commit 863d2e4

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)