Skip to content

[cxx-interop] Fix a rare compilation error in reverse interop header #80598

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/ClangImporter/ClangImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
7 changes: 7 additions & 0 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<clang::NamespaceDecl>(ed->getClangDecl());

return false;
}
8 changes: 1 addition & 7 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <algorithm>
Expand Down Expand Up @@ -3730,13 +3731,6 @@ namespace {
return nullptr;
}

static bool isClangNamespace(const DeclContext *dc) {
if (const auto *ed = dc->getSelfEnumDecl())
return isa<clang::NamespaceDecl>(ed->getClangDecl());

return false;
}

Decl *importFunctionDecl(
const clang::FunctionDecl *decl, ImportedName importedName,
std::optional<ImportedName> correctSwiftName,
Expand Down
3 changes: 2 additions & 1 deletion lib/PrintAsClang/ClangSyntaxPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ void ClangSyntaxPrinter::printNamespace(
void ClangSyntaxPrinter::printParentNamespaceForNestedTypes(
const ValueDecl *D, llvm::function_ref<void(raw_ostream &OS)> bodyPrinter,
NamespaceTrivia trivia) const {
if (!isa_and_nonnull<NominalTypeDecl>(D->getDeclContext()->getAsDecl())) {
if (!isa_and_nonnull<NominalTypeDecl>(D->getDeclContext()->getAsDecl()) ||
importer::isClangNamespace(D->getDeclContext())) {
bodyPrinter(os);
return;
}
Expand Down
28 changes: 16 additions & 12 deletions lib/PrintAsClang/PrintClangValueType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,18 +630,21 @@ void ClangValueTypePrinter::printTypeGenericTraits(
bool isOpaqueLayout) {
auto *NTD = dyn_cast<NominalTypeDecl>(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<ClassDecl>(typeDecl);
bool addPointer =
typeDecl->isObjC() || (classDecl && classDecl->isForeignReferenceType());
Expand Down Expand Up @@ -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() << "::";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,7 @@ public struct Strct {
// CHECK: ns::ImmortalTemplate<int> *_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
Expand All @@ -212,14 +209,17 @@ 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<>
// CHECK-NEXT: inline const constexpr bool isUsableInGenericContext<ns::NonTrivialTemplateInt> = true;
// CHECK-NEXT: template<>
// CHECK-NEXT: struct TypeMetadataTrait<ns::NonTrivialTemplateInt> {
// 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{
Expand All @@ -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
Expand All @@ -251,14 +248,17 @@ 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<>
// CHECK-NEXT: inline const constexpr bool isUsableInGenericContext<ns::NonTrivialTemplateTrivial> = true;
// CHECK-NEXT: template<>
// CHECK-NEXT: struct TypeMetadataTrait<ns::NonTrivialTemplateTrivial> {
// 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{
Expand Down
Original file line number Diff line number Diff line change
@@ -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] {
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public func retObjCClassArray() -> [ObjCKlass] {
// CHECK-NEXT: template<>
// CHECK-NEXT: struct TypeMetadataTrait<ObjCKlass*> {
// 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: };

Expand Down
8 changes: 8 additions & 0 deletions test/Interop/SwiftToCxx/structs/nested-structs-in-cxx.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,11 @@ public class TestObject {
case invalid
}
}

extension RecordConfig.File {
public func getFileExtension() -> String { ".wav" }
}

public func getFiles() -> [RecordConfig.File] {
[]
}