diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index de1091ba12cd5..25418d266409f 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -773,6 +773,9 @@ getPrivateFileIDAttrs(const clang::CXXRecordDecl *decl); /// /// Returns false if \a decl was not imported by ClangImporter. bool declIsCxxOnly(const Decl *decl); + +/// Is this DeclContext an `enum` that represents a C++ namespace? +bool isClangNamespace(const DeclContext *dc); } // namespace importer struct ClangInvocationFileMapping { diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index ade853a2fa111..a37ba1c343454 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -8793,3 +8793,10 @@ bool importer::declIsCxxOnly(const Decl *decl) { } return false; } + +bool importer::isClangNamespace(const DeclContext *dc) { + if (const auto *ed = dc->getSelfEnumDecl()) + return isa_and_nonnull(ed->getClangDecl()); + + return false; +} diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 919670e0eb1dc..a11406db9e3d8 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -75,6 +75,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/TinyPtrVector.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Path.h" #include @@ -3730,13 +3731,6 @@ namespace { return nullptr; } - static bool isClangNamespace(const DeclContext *dc) { - if (const auto *ed = dc->getSelfEnumDecl()) - return isa(ed->getClangDecl()); - - return false; - } - Decl *importFunctionDecl( const clang::FunctionDecl *decl, ImportedName importedName, std::optional correctSwiftName, diff --git a/lib/PrintAsClang/ClangSyntaxPrinter.cpp b/lib/PrintAsClang/ClangSyntaxPrinter.cpp index 936db616d4b2d..2310a4078cdc9 100644 --- a/lib/PrintAsClang/ClangSyntaxPrinter.cpp +++ b/lib/PrintAsClang/ClangSyntaxPrinter.cpp @@ -207,7 +207,8 @@ void ClangSyntaxPrinter::printNamespace( void ClangSyntaxPrinter::printParentNamespaceForNestedTypes( const ValueDecl *D, llvm::function_ref bodyPrinter, NamespaceTrivia trivia) const { - if (!isa_and_nonnull(D->getDeclContext()->getAsDecl())) { + if (!isa_and_nonnull(D->getDeclContext()->getAsDecl()) || + importer::isClangNamespace(D->getDeclContext())) { bodyPrinter(os); return; } diff --git a/lib/PrintAsClang/PrintClangValueType.cpp b/lib/PrintAsClang/PrintClangValueType.cpp index 6ac4997581490..7e05ead0613fc 100644 --- a/lib/PrintAsClang/PrintClangValueType.cpp +++ b/lib/PrintAsClang/PrintClangValueType.cpp @@ -630,18 +630,21 @@ void ClangValueTypePrinter::printTypeGenericTraits( bool isOpaqueLayout) { auto *NTD = dyn_cast(typeDecl); ClangSyntaxPrinter printer(typeDecl->getASTContext(), os); - // FIXME: avoid popping out of the module's namespace here. - os << "} // end namespace \n\n"; - os << "namespace swift SWIFT_PRIVATE_ATTR {\n"; - if (typeDecl->hasClangNode()) { /// Print a reference to the type metadata function for a C++ type. - ClangSyntaxPrinter(typeDecl->getASTContext(), os).printNamespace( - cxx_synthesis::getCxxImplNamespaceName(), [&](raw_ostream &os) { - ClangSyntaxPrinter(typeDecl->getASTContext(), os).printCTypeMetadataTypeFunction( - typeDecl, typeMetadataFuncName, typeMetadataFuncRequirements); - }); + printer.printParentNamespaceForNestedTypes(typeDecl, [&](raw_ostream &os) { + printer.printNamespace( + cxx_synthesis::getCxxImplNamespaceName(), [&](raw_ostream &os) { + ClangSyntaxPrinter(typeDecl->getASTContext(), os) + .printCTypeMetadataTypeFunction(typeDecl, typeMetadataFuncName, + typeMetadataFuncRequirements); + }); + }); } + + // FIXME: avoid popping out of the module's namespace here. + os << "} // end namespace \n\n"; + os << "namespace swift SWIFT_PRIVATE_ATTR {\n"; auto classDecl = dyn_cast(typeDecl); bool addPointer = typeDecl->isObjC() || (classDecl && classDecl->isForeignReferenceType()); @@ -676,10 +679,11 @@ void ClangValueTypePrinter::printTypeGenericTraits( ClangSyntaxPrinter(typeDecl->getASTContext(), os).printInlineForHelperFunction(); os << "void * _Nonnull getTypeMetadata() {\n"; os << " return "; - if (!typeDecl->hasClangNode()) { + if (typeDecl->hasClangNode()) + printer.printBaseName(moduleContext); + else printer.printBaseName(typeDecl->getModuleContext()); - os << "::"; - } + os << "::"; if (!printer.printNestedTypeNamespaceQualifiers(typeDecl)) os << "::"; os << cxx_synthesis::getCxxImplNamespaceName() << "::"; diff --git a/test/Interop/CxxToSwiftToCxx/bridge-cxx-struct-back-to-cxx.swift b/test/Interop/CxxToSwiftToCxx/bridge-cxx-struct-back-to-cxx.swift index d460c4dc4711e..cae37b20351fb 100644 --- a/test/Interop/CxxToSwiftToCxx/bridge-cxx-struct-back-to-cxx.swift +++ b/test/Interop/CxxToSwiftToCxx/bridge-cxx-struct-back-to-cxx.swift @@ -200,10 +200,7 @@ public struct Strct { // CHECK: ns::ImmortalTemplate *_Nonnull retImmortalTemplate() noexcept SWIFT_SYMBOL({{.*}}) SWIFT_WARN_UNUSED_RESULT { // CHECK-NEXT: return UseCxxTy::_impl::$s8UseCxxTy19retImmortalTemplateSo2nsO0028ImmortalTemplateCInt_jBAGgnbVyF(); // CHECK-NEXT: } - -// CHECK: } // end namespace // CHECK-EMPTY: -// CHECK-NEXT: namespace swift SWIFT_PRIVATE_ATTR { // CHECK-NEXT: namespace _impl { // CHECK-EMPTY: // CHECK-NEXT: // Type metadata accessor for NonTrivialTemplateInt @@ -212,6 +209,9 @@ public struct Strct { // CHECK-EMPTY: // CHECK-NEXT: } // namespace _impl // CHECK-EMPTY: +// CHECK-NEXT: } // end namespace +// CHECK-EMPTY: +// CHECK-NEXT: namespace swift SWIFT_PRIVATE_ATTR { // CHECK-NEXT: #pragma clang diagnostic push // CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions" // CHECK-NEXT: template<> @@ -219,7 +219,7 @@ public struct Strct { // CHECK-NEXT: template<> // CHECK-NEXT: struct TypeMetadataTrait { // CHECK-NEXT: static SWIFT_INLINE_PRIVATE_HELPER void * _Nonnull getTypeMetadata() { -// CHECK-NEXT: return _impl::$sSo2nsO0030NonTrivialTemplateCInt_hHAFhrbVMa(0)._0; +// CHECK-NEXT: return UseCxxTy::_impl::$sSo2nsO0030NonTrivialTemplateCInt_hHAFhrbVMa(0)._0; // CHECK-NEXT: } // CHECK-NEXT: }; // CHECK-NEXT: namespace _impl{ @@ -240,9 +240,6 @@ public struct Strct { // CHECK-NEXT: return result; // CHECK-NEXT: } // CHECK-EMPTY: -// CHECK-NEXT: } // end namespace -// CHECK-EMPTY: -// CHECK-NEXT: namespace swift SWIFT_PRIVATE_ATTR { // CHECK-NEXT: namespace _impl { // CHECK-EMPTY: // CHECK-NEXT: // Type metadata accessor for NonTrivialTemplateTrivial @@ -251,6 +248,9 @@ public struct Strct { // CHECK-EMPTY: // CHECK-NEXT: } // namespace _impl // CHECK-EMPTY: +// CHECK-NEXT: } // end namespace +// CHECK-EMPTY: +// CHECK-NEXT: namespace swift SWIFT_PRIVATE_ATTR { // CHECK-NEXT: #pragma clang diagnostic push // CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions" // CHECK-NEXT: template<> @@ -258,7 +258,7 @@ public struct Strct { // CHECK-NEXT: template<> // CHECK-NEXT: struct TypeMetadataTrait { // CHECK-NEXT: static SWIFT_INLINE_PRIVATE_HELPER void * _Nonnull getTypeMetadata() { -// CHECK-NEXT: return _impl::$sSo2nsO0042NonTrivialTemplatensTrivialinNS_HlGFlenawcVMa(0)._0; +// CHECK-NEXT: return UseCxxTy::_impl::$sSo2nsO0042NonTrivialTemplatensTrivialinNS_HlGFlenawcVMa(0)._0; // CHECK-NEXT: } // CHECK-NEXT: }; // CHECK-NEXT: namespace _impl{ diff --git a/test/Interop/CxxToSwiftToCxx/nested-cxx-class-back-to-swift.swift b/test/Interop/CxxToSwiftToCxx/nested-cxx-class-back-to-swift.swift new file mode 100644 index 0000000000000..446f211f290d3 --- /dev/null +++ b/test/Interop/CxxToSwiftToCxx/nested-cxx-class-back-to-swift.swift @@ -0,0 +1,27 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-swift-frontend %t/use-cxx-types.swift -module-name UseCxxTy -typecheck -verify -emit-clang-header-path %t/UseCxxTy.h -I %t -enable-experimental-cxx-interop -clang-header-expose-decls=all-public -disable-availability-checking +// RUN: cat %t/header.h >> %t/full-header.h +// RUN: cat %t/UseCxxTy.h >> %t/full-header.h +// RUN: %target-interop-build-clangxx -std=c++20 -c -xc++-header %t/full-header.h -o %t/o.o + +//--- header.h + +struct Cell { class Visitor {}; }; + +//--- module.modulemap +module CxxTest { + header "header.h" + requires cplusplus +} + +//--- use-cxx-types.swift +import CxxTest + +public extension Cell.Visitor { + func visit() {} +} + +public func f() -> [Cell.Visitor] { +} diff --git a/test/Interop/ObjCToSwiftToObjCxx/bridge-objc-types-back-to-objcxx.swift b/test/Interop/ObjCToSwiftToObjCxx/bridge-objc-types-back-to-objcxx.swift index 7a407f781c2e4..ee728971d31f7 100644 --- a/test/Interop/ObjCToSwiftToObjCxx/bridge-objc-types-back-to-objcxx.swift +++ b/test/Interop/ObjCToSwiftToObjCxx/bridge-objc-types-back-to-objcxx.swift @@ -94,7 +94,7 @@ public func retObjCClassArray() -> [ObjCKlass] { // CHECK-NEXT: template<> // CHECK-NEXT: struct TypeMetadataTrait { // CHECK-NEXT: static SWIFT_INLINE_PRIVATE_HELPER void * _Nonnull getTypeMetadata() { -// CHECK-NEXT: return _impl::$sSo9ObjCKlassCMa(0)._0; +// CHECK-NEXT: return UseObjCTy::_impl::$sSo9ObjCKlassCMa(0)._0; // CHECK-NEXT: } // CHECK-NEXT: }; diff --git a/test/Interop/SwiftToCxx/structs/nested-structs-in-cxx.swift b/test/Interop/SwiftToCxx/structs/nested-structs-in-cxx.swift index c8cfe3d74276e..e54105b5fe018 100644 --- a/test/Interop/SwiftToCxx/structs/nested-structs-in-cxx.swift +++ b/test/Interop/SwiftToCxx/structs/nested-structs-in-cxx.swift @@ -68,3 +68,11 @@ public class TestObject { case invalid } } + +extension RecordConfig.File { + public func getFileExtension() -> String { ".wav" } +} + +public func getFiles() -> [RecordConfig.File] { + [] +}