Skip to content

Commit 0276feb

Browse files
committed
handle libc++ v17-19
libc++ v17-19 was split into multiple top-level modules, while versions earlier and later had one TLM with submodules.
1 parent 120c7de commit 0276feb

File tree

5 files changed

+41
-20
lines changed

5 files changed

+41
-20
lines changed

include/swift/ClangImporter/ClangImporter.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -702,12 +702,6 @@ bool isCxxStdModule(const clang::Module *module);
702702
/// (std_vector, std_iosfwd, etc).
703703
bool isCxxStdModule(StringRef moduleName, bool IsSystem);
704704

705-
/// Build the path corresponding to the Swift wrapper for a clang module.
706-
/// Returns ImportPath::Builder to leave control over if and where to clone the
707-
/// path to the caller.
708-
ImportPath::Builder getSwiftModulePath(ASTContext &SwiftContext,
709-
const clang::Module *M);
710-
711705
/// Returns the pointee type if the given type is a C++ `const`
712706
/// reference type, `None` otherwise.
713707
std::optional<clang::QualType>

lib/ClangImporter/ClangImporter.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3805,7 +3805,23 @@ ImportDecl *swift::createImportDecl(ASTContext &Ctx,
38053805
auto *ImportedMod = ClangN.getClangModule();
38063806
assert(ImportedMod);
38073807

3808-
ImportPath::Builder importPath = getSwiftModulePath(Ctx, ImportedMod);
3808+
ImportPath::Builder importPath;
3809+
auto *TmpMod = ImportedMod;
3810+
while (TmpMod) {
3811+
// If this is a C++ stdlib module, print its name as `CxxStdlib` instead of
3812+
// `std`. `CxxStdlib` is the only accepted spelling of the C++ stdlib module
3813+
// name in Swift. In libc++ versions 17-19 there are multiple TLMs, named
3814+
// std_vector, std_array etc. We don't support importing those modules, but
3815+
// when printing the module interface it'd be weird to print "import
3816+
// CxxStdlib" over and over, so those are still printed as "import
3817+
// std_vector". This only affects the module interface for CxxStdlib.
3818+
Identifier moduleName = !TmpMod->isSubModule() && TmpMod->Name == "std"
3819+
? Ctx.Id_CxxStdlib
3820+
: Ctx.getIdentifier(TmpMod->Name);
3821+
importPath.push_back(moduleName);
3822+
TmpMod = TmpMod->Parent;
3823+
}
3824+
std::reverse(importPath.begin(), importPath.end());
38093825

38103826
bool IsExported = false;
38113827
for (auto *ExportedMod : Exported) {
@@ -4653,8 +4669,8 @@ void ClangModuleUnit::getImportedModulesForLookup(
46534669
if (owner.SwiftContext.LangOpts.EnableCXXInterop && topLevel &&
46544670
isCxxStdModule(topLevel) && wrapper->clangModule &&
46554671
isCxxStdModule(wrapper->clangModule)) {
4656-
// The CxxStdlib overlay re-exports the clang module std, which in recent
4657-
// libc++ versions re-exports top-level modules for different std headers
4672+
// The CxxStdlib overlay re-exports the clang module std, which in libc++
4673+
// versions 17-19 re-exports top-level modules for different std headers
46584674
// (std_string, std_vector, etc). The overlay module for each of the std
46594675
// modules is the CxxStdlib module itself. Make sure we return the actual
46604676
// clang modules (std_xyz) as transitive dependencies instead of just
@@ -8759,7 +8775,7 @@ bool importer::isCxxStdModule(const clang::Module *module) {
87598775
bool importer::isCxxStdModule(StringRef moduleName, bool IsSystem) {
87608776
if (moduleName == "std")
87618777
return true;
8762-
// In recent libc++ versions the module is split into multiple top-level
8778+
// In libc++ versions 17-19 the module is split into multiple top-level
87638779
// modules (std_vector, std_utility, etc).
87648780
if (IsSystem && moduleName.starts_with("std_")) {
87658781
if (moduleName == "std_errno_h")
@@ -8769,7 +8785,7 @@ bool importer::isCxxStdModule(StringRef moduleName, bool IsSystem) {
87698785
return false;
87708786
}
87718787

8772-
ImportPath::Builder importer::getSwiftModulePath(ASTContext &SwiftContext, const clang::Module *M) {
8788+
ImportPath::Builder ClangImporter::Implementation::getSwiftModulePath(const clang::Module *M) {
87738789
ImportPath::Builder builder;
87748790
while (M) {
87758791
if (!M->isSubModule() && isCxxStdModule(M))
@@ -8782,10 +8798,6 @@ ImportPath::Builder importer::getSwiftModulePath(ASTContext &SwiftContext, const
87828798
return builder;
87838799
}
87848800

8785-
ImportPath::Builder ClangImporter::Implementation::getSwiftModulePath(const clang::Module *M) {
8786-
return ::getSwiftModulePath(SwiftContext, M);
8787-
}
8788-
87898801
std::optional<clang::QualType>
87908802
importer::getCxxReferencePointeeTypeOrNone(const clang::Type *type) {
87918803
if (type->isReferenceType())

test/Interop/Cxx/stdlib/Inputs/check-libcxx-version.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ int main() {
66
return 1;
77
#endif
88

9-
#if _LIBCPP_VERSION >= 170004
9+
// the libc++ module was split into multiple top-level modules in Clang 17,
10+
// and then re-merged into one module with submodules in Clang 20
11+
#if _LIBCPP_VERSION >= 170004 && _LIBCPP_VERSION < 200000
1012
return 0;
1113
#else
1214
return 1;

test/Interop/Cxx/stdlib/libcxx-module-interface.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Only run this test with older libc++, before the top-level std module got split into multiple top-level modules.
1+
// Don't run this test with libc++ versions 17-19, when the top-level std module was split into multiple top-level modules.
22
// RUN: %empty-directory(%t)
33
// RUN: %target-clangxx %S/Inputs/check-libcxx-version.cpp -o %t/check-libcxx-version
44
// RUN: %target-codesign %t/check-libcxx-version
Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
1-
// RUN: %sourcekitd-test -req=interface-gen -module CxxStdlib -- -Xfrontend -disable-implicit-concurrency-module-import -Xfrontend -disable-implicit-string-processing-module-import -cxx-interoperability-mode=default -target %target-triple -sdk %sdk | %FileCheck %s
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-clangxx %S/../../Interop/Cxx/stdlib/Inputs/check-libcxx-version.cpp -o %t/check-libcxx-version
3+
// RUN: %target-codesign %t/check-libcxx-version
4+
5+
// Since this test runs check-libcxx-version, it requires execution.
6+
// REQUIRES: executable_test
7+
8+
// RUN: %target-run %t/check-libcxx-version || %sourcekitd-test -req=interface-gen -module CxxStdlib -- -Xfrontend -disable-implicit-concurrency-module-import -Xfrontend -disable-implicit-string-processing-module-import -cxx-interoperability-mode=default -target %target-triple -sdk %sdk | %FileCheck %s --check-prefix CHECK-MONO
9+
// RUN: not %target-run %t/check-libcxx-version || %sourcekitd-test -req=interface-gen -module CxxStdlib -- -Xfrontend -disable-implicit-concurrency-module-import -Xfrontend -disable-implicit-string-processing-module-import -cxx-interoperability-mode=default -target %target-triple -sdk %sdk | %FileCheck %s --check-prefix CHECK-SPLIT
210

311
// REQUIRES: OS=macosx
412

5-
// CHECK: import {{CxxStdlib.vector|std_vector}}
6-
// CHECK: extension std.basic_string<CChar, std.__1.char_traits<CChar>, std.__1.allocator<CChar>> {
13+
// CHECK-MONO-NOT: import CxxStdlib{{$}}
14+
// CHECK-MONO: import CxxStdlib.vector
15+
// CHECK-MONO: extension std.basic_string<CChar, std.__1.char_traits<CChar>, std.__1.allocator<CChar>> {
16+
17+
// CHECK-SPLIT-NOT: import CxxStdlib{{$}}
18+
// CHECK-SPLIT: import std_vector
19+
// CHECK-SPLIT: extension std.basic_string<CChar, std.__1.char_traits<CChar>, std.__1.allocator<CChar>> {

0 commit comments

Comments
 (0)