From 782f26e726eca801f52414d8ae7a546bc3668013 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 23 Jun 2025 16:25:48 +0100 Subject: [PATCH] [cxx-interop] Fix printing of namespaces declared in bridging headers If a C++ namespace has redeclarations in a bridging header, printing AST for the namespace would crash the compiler. This is because such a redeclaration would not have an owning Clang module, and the AST printer did not account for that. This change fixes the crash. rdar://151715540 (cherry picked from commit cc9c51deea8698fdc1be90ffbfd7ca525b6ad33d) --- lib/AST/ASTPrinter.cpp | 4 ++++ .../Cxx/namespace/Inputs/bridging-header.h | 15 +++++++++++++++ .../bridging-header-module-interface.swift | 4 ++++ 3 files changed, 23 insertions(+) create mode 100644 test/Interop/Cxx/namespace/Inputs/bridging-header.h create mode 100644 test/Interop/Cxx/namespace/bridging-header-module-interface.swift diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 453f54fa38f19..e6cf506e37d51 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2737,6 +2737,10 @@ static void addNamespaceMembers(Decl *decl, declOwner = declOwner->getTopLevelModule(); auto Redecls = llvm::SmallVector(namespaceDecl->redecls()); std::stable_sort(Redecls.begin(), Redecls.end(), [&](clang::NamespaceDecl *LHS, clang::NamespaceDecl *RHS) { + // A namespace redeclaration will not have an owning Clang module if it is + // declared in a bridging header. + if (!LHS->getOwningModule() || !RHS->getOwningModule()) + return (bool)LHS->getOwningModule() < (bool)RHS->getOwningModule(); return LHS->getOwningModule()->Name < RHS->getOwningModule()->Name; }); for (auto redecl : Redecls) { diff --git a/test/Interop/Cxx/namespace/Inputs/bridging-header.h b/test/Interop/Cxx/namespace/Inputs/bridging-header.h new file mode 100644 index 0000000000000..1cc267d42c360 --- /dev/null +++ b/test/Interop/Cxx/namespace/Inputs/bridging-header.h @@ -0,0 +1,15 @@ +namespace NS1 { +namespace NS2 { + +struct InBridgingHeader1 {}; + +} // namespace NS2 +} // namespace NS1 + +namespace NS1 { +namespace NS2 { + +struct InBridgingHeader2 {}; + +} // namespace NS2 +} // namespace NS1 diff --git a/test/Interop/Cxx/namespace/bridging-header-module-interface.swift b/test/Interop/Cxx/namespace/bridging-header-module-interface.swift new file mode 100644 index 0000000000000..f068c5da6e3f1 --- /dev/null +++ b/test/Interop/Cxx/namespace/bridging-header-module-interface.swift @@ -0,0 +1,4 @@ +// RUN: %target-swift-ide-test -print-header -header-to-print %S/Inputs/bridging-header.h -import-objc-header %S/Inputs/bridging-header.h -source-filename=%s -cxx-interoperability-mode=upcoming-swift | %FileCheck %s + +// CHECK: struct InBridgingHeader1 +// CHECK: struct InBridgingHeader2