Skip to content

Commit 13b1faf

Browse files
committed
[ClangImporter] Add submodules as implicit imports of wrapper module
Decls in Swift wrapper module may not originate in the top-level clang module with the same name, since decls in clang submodules are dumped into the top-level module. This is because Swift has no concept of submodules. To make sure that any imported decl has access to the same symbols as the original clang decl had, all transitive submodules, and their imports, are added as implicit imports of the wrapper module. This is necessary in the case where a submodule is marked `explicit`. The content in explicit submodules isn't normally made visible when importing the parent module. Decls from explicit submodules still end up in the top-level wrapper module however, so in Swift they do still need to be visible from the top-level module. This is relevant for macro expansions, so that they can refer to the same types as the original decl.
1 parent 9dd52ee commit 13b1faf

File tree

2 files changed

+80
-10
lines changed

2 files changed

+80
-10
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2834,16 +2834,29 @@ ClangModuleUnit *ClangImporter::Implementation::getWrapperForModule(
28342834
if (auto mainModule = SwiftContext.MainModule) {
28352835
implicitImportInfo = mainModule->getImplicitImportInfo();
28362836
}
2837-
for (auto *I : underlying->Imports) {
2838-
// Make sure that synthesized Swift code in the clang module wrapper
2839-
// (e.g. _SwiftifyImport macro expansions) can access the same symbols as
2840-
// if it were actually in the clang module
2841-
std::string swiftModuleName = isCxxStdModule(I) ?
2842-
static_cast<std::string>(SwiftContext.Id_CxxStdlib) :
2843-
I->getFullModuleName();
2844-
ImportPath::Builder importPath(SwiftContext, swiftModuleName, '.');
2845-
UnloadedImportedModule importedModule(importPath.copyTo(SwiftContext), ImportKind::Module);
2846-
implicitImportInfo.AdditionalUnloadedImports.push_back(importedModule);
2837+
2838+
// Decls in this Swift module may originate in the top-level clang module with the
2839+
// same name, since decls in clang submodules are dumped into the top-level module.
2840+
// Add all transitive submodules as implicit imports in case any of them are marked
2841+
// `explicit`. The content in explicit modules isn't normally made visible when
2842+
// importing the parent module, but in this case the parent module is all we have.
2843+
llvm::SmallVector<const clang::Module *, 32> SubmoduleWorklist;
2844+
SubmoduleWorklist.push_back(underlying);
2845+
while (!SubmoduleWorklist.empty()) {
2846+
const clang::Module *CurrModule = SubmoduleWorklist.pop_back_val();
2847+
for (auto *I : CurrModule->Imports) {
2848+
// Make sure that synthesized Swift code in the clang module wrapper
2849+
// (e.g. _SwiftifyImport macro expansions) can access the same symbols as
2850+
// if it were actually in the clang module, by copying the imports.
2851+
std::string swiftModuleName = isCxxStdModule(I) ?
2852+
static_cast<std::string>(SwiftContext.Id_CxxStdlib) :
2853+
I->getFullModuleName();
2854+
ImportPath::Builder importPath(SwiftContext, swiftModuleName, '.');
2855+
UnloadedImportedModule importedModule(importPath.copyTo(SwiftContext), ImportKind::Module);
2856+
implicitImportInfo.AdditionalUnloadedImports.push_back(importedModule);
2857+
}
2858+
for (auto *Submodule : CurrModule->submodules())
2859+
SubmoduleWorklist.push_back(Submodule);
28472860
}
28482861
ClangModuleUnit *file = nullptr;
28492862
auto wrapper = ModuleDecl::create(name, SwiftContext, implicitImportInfo,
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// REQUIRES: swift_feature_SafeInteropWrappers
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: split-file %s %t
5+
6+
// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/ClangIncludesExplicit.swiftmodule -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/test.swift
7+
8+
//--- test.swift
9+
import A1.B1.C1.D1
10+
11+
public func callUnsafe(_ p: UnsafeMutableRawPointer) {
12+
let _ = foo(p, 13)
13+
}
14+
15+
public func callSafe(_ p: UnsafeMutableRawBufferPointer) {
16+
let _ = foo(p)
17+
}
18+
19+
//--- Inputs/module.modulemap
20+
module A1 {
21+
explicit module B1 {
22+
explicit module C1 {
23+
explicit module D1 {
24+
header "D1.h"
25+
}
26+
}
27+
}
28+
}
29+
30+
module A2 {
31+
explicit module B2 {
32+
header "B2.h"
33+
export C2
34+
35+
explicit module C2 {
36+
header "C2.h"
37+
}
38+
}
39+
}
40+
41+
//--- Inputs/D1.h
42+
#pragma once
43+
44+
#include "B2.h"
45+
#define __sized_by(s) __attribute__((__sized_by__(s)))
46+
47+
c2_t foo(void * _Nonnull __sized_by(size), int size);
48+
49+
//--- Inputs/B2.h
50+
#pragma once
51+
52+
#include "C2.h"
53+
54+
//--- Inputs/C2.h
55+
#pragma once
56+
57+
typedef int c2_t;

0 commit comments

Comments
 (0)