Skip to content

Commit 0770e78

Browse files
committed
[ClangImporter] Add clang module imports to Swift wrapper module
When macros like _SwiftifyImport are added to a wrapper module for a clang module, they may need to refer to symbols declared in another clang module that the wrapped module imports (e.g. because they are used in the original signature). This adds all the imported clang modules as implicit imports to the wrapper module. rdar://151611573
1 parent ea63d04 commit 0770e78

File tree

14 files changed

+195
-11
lines changed

14 files changed

+195
-11
lines changed

include/swift/Subsystems.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,7 @@ namespace swift {
125125

126126
/// Resolve imports for a source file generated to adapt a given
127127
/// Clang module.
128-
void performImportResolutionForClangMacroBuffer(
129-
SourceFile &SF, ModuleDecl *clangModule
130-
);
128+
void performImportResolutionForClangMacroBuffer(SourceFile &SF);
131129

132130
/// Once type-checking is complete, this instruments code with calls to an
133131
/// intrinsic that record the expected values of local variables so they can

lib/ClangImporter/ClangImporter.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2795,6 +2795,14 @@ ClangModuleUnit *ClangImporter::Implementation::getWrapperForModule(
27952795
if (auto mainModule = SwiftContext.MainModule) {
27962796
implicitImportInfo = mainModule->getImplicitImportInfo();
27972797
}
2798+
for (auto *I : underlying->Imports) {
2799+
// Make sure that synthesized Swift code in the clang module wrapper
2800+
// (e.g. _SwiftifyImport macro expansions) can access the same symbols as
2801+
// if it were actually in the clang module
2802+
ImportPath::Builder importPath(SwiftContext, I->getFullModuleName(), '.');
2803+
UnloadedImportedModule importedModule(importPath.copyTo(SwiftContext), ImportKind::Module);
2804+
implicitImportInfo.AdditionalUnloadedImports.push_back(importedModule);
2805+
}
27982806
ClangModuleUnit *file = nullptr;
27992807
auto wrapper = ModuleDecl::create(name, SwiftContext, implicitImportInfo,
28002808
[&](ModuleDecl *wrapper, auto addFile) {

lib/Sema/ImportResolution.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,15 +319,14 @@ void swift::performImportResolution(SourceFile &SF) {
319319
verify(SF);
320320
}
321321

322-
void swift::performImportResolutionForClangMacroBuffer(
323-
SourceFile &SF, ModuleDecl *clangModule
324-
) {
322+
void swift::performImportResolutionForClangMacroBuffer(SourceFile &SF) {
325323
// If we've already performed import resolution, bail.
326324
if (SF.ASTStage == SourceFile::ImportsResolved)
327325
return;
328326

327+
// `getWrapperForModule` has already declared all the implicit clang module
328+
// imports we need
329329
ImportResolver resolver(SF);
330-
resolver.addImplicitImport(clangModule);
331330

332331
// FIXME: This is a hack that we shouldn't need, but be sure that we can
333332
// see the Swift standard library.

lib/Sema/TypeCheckMacros.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,10 +1059,8 @@ createMacroSourceFile(std::unique_ptr<llvm::MemoryBuffer> buffer,
10591059
/*parsingOpts=*/{}, /*isPrimary=*/false);
10601060
if (auto parentSourceFile = dc->getParentSourceFile())
10611061
macroSourceFile->setImports(parentSourceFile->getImports());
1062-
else if (auto clangModuleUnit =
1063-
dyn_cast<ClangModuleUnit>(dc->getModuleScopeContext())) {
1064-
auto clangModule = clangModuleUnit->getParentModule();
1065-
performImportResolutionForClangMacroBuffer(*macroSourceFile, clangModule);
1062+
else if (isa<ClangModuleUnit>(dc->getModuleScopeContext())) {
1063+
performImportResolutionForClangMacroBuffer(*macroSourceFile);
10661064
}
10671065
return macroSourceFile;
10681066
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#pragma once
2+
3+
typedef int a_t;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#pragma once
2+
3+
typedef int b_t;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#pragma once
2+
typedef int c_t;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#pragma once
2+
typedef int d_t;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#pragma once
2+
typedef int e_t;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module ModuleA {
2+
header "module-a.h"
3+
export *
4+
}
5+
module ModuleB {
6+
header "module-b.h"
7+
}
8+
module ModuleOuter {
9+
module ModuleC {
10+
header "module-c.h"
11+
export *
12+
}
13+
explicit module ModuleD {
14+
header "module-d.h"
15+
export *
16+
}
17+
}
18+
module ModuleDeep {
19+
module ModuleDeepNested {
20+
module ModuleDeepNestedNested {
21+
header "module-e.h"
22+
}
23+
}
24+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#pragma once
2+
3+
#include "TransitiveModules/module-a.h"
4+
#include "TransitiveModules/module-b.h"
5+
#include "TransitiveModules/module-c.h"
6+
#include "TransitiveModules/module-d.h"
7+
#include "TransitiveModules/module-e.h"
8+
9+
#define __counted_by(x) __attribute__((__counted_by__(x)))
10+
#define __noescape __attribute__((noescape))
11+
12+
void basic_include(const a_t *__counted_by(len) p __noescape, a_t len);
13+
14+
void non_exported_include(const b_t *__counted_by(len) p __noescape, b_t len);
15+
16+
void submodule_include(const c_t *__counted_by(len) p __noescape, c_t len);
17+
18+
void explicit_submodule_include(const d_t *__counted_by(len) p __noescape, d_t len);
19+
20+
void deep_submodule_noexport(const e_t *__counted_by(len) p __noescape, e_t len);

test/Interop/C/swiftify-import/Inputs/module.modulemap

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,10 @@ module CommentsClang {
2626
header "comments.h"
2727
export *
2828
}
29+
module ClangIncludesModule {
30+
header "clang-includes.h"
31+
export *
32+
}
33+
module ClangIncludesNoExportModule {
34+
header "clang-includes.h"
35+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// REQUIRES: swift_feature_SafeInteropWrappers
2+
3+
// RUN: %target-swift-ide-test -print-module -module-to-print=ClangIncludesNoExportModule -plugin-path %swift-plugin-dir -I %S/Inputs -source-filename=x -enable-experimental-feature SafeInteropWrappers | %FileCheck %s
4+
5+
// swift-ide-test doesn't currently typecheck the macro expansions, so run the compiler as well
6+
// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/ClangIncludesNoExport.swiftmodule -I %S/Inputs -enable-experimental-feature SafeInteropWrappers %s
7+
8+
import ClangIncludesNoExportModule
9+
10+
// CHECK: import ModuleA
11+
// CHECK-NEXT: import ModuleB
12+
// CHECK-NOT: import
13+
// CHECK-EMPTY:
14+
15+
// CHECK-NEXT: func basic_include(_ p: UnsafePointer<a_t>!, _ len: a_t)
16+
// CHECK-NEXT: func non_exported_include(_ p: UnsafePointer<b_t>!, _ len: b_t)
17+
// CHECK-NEXT: func submodule_include(_ p: UnsafePointer<c_t>!, _ len: c_t)
18+
// CHECK-NEXT: func explicit_submodule_include(_ p: UnsafePointer<d_t>!, _ len: d_t)
19+
// CHECK-NEXT: func deep_submodule_noexport(_ p: UnsafePointer<e_t>!, _ len: e_t)
20+
21+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
22+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
23+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func basic_include(_ p: Span<a_t>)
24+
25+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
26+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
27+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func deep_submodule_noexport(_ p: Span<e_t>)
28+
29+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
30+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
31+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func explicit_submodule_include(_ p: Span<d_t>)
32+
33+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
34+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
35+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func non_exported_include(_ p: Span<b_t>)
36+
37+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
38+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
39+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func submodule_include(_ p: Span<c_t>)
40+
41+
public func callBasicInclude(_ p: Span<CInt>) {
42+
basic_include(p)
43+
}
44+
45+
public func callNonExported(_ p: Span<CInt>) {
46+
non_exported_include(p)
47+
}
48+
49+
public func callSubmoduleInclude(_ p: Span<CInt>) {
50+
submodule_include(p)
51+
}
52+
53+
public func callExplicitSubmoduleInclude(_ p: Span<CInt>) {
54+
explicit_submodule_include(p)
55+
}
56+
57+
public func callDeepSubmoduleNoexport(_ p: Span<CInt>) {
58+
deep_submodule_noexport(p)
59+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// REQUIRES: swift_feature_SafeInteropWrappers
2+
3+
// RUN: %target-swift-ide-test -print-module -module-to-print=ClangIncludesModule -plugin-path %swift-plugin-dir -I %S/Inputs -source-filename=x -enable-experimental-feature SafeInteropWrappers | %FileCheck %s
4+
5+
// swift-ide-test doesn't currently typecheck the macro expansions, so run the compiler as well
6+
// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/ClangIncludes.swiftmodule -I %S/Inputs -enable-experimental-feature SafeInteropWrappers %s
7+
8+
import ClangIncludesModule
9+
10+
// CHECK: @_exported import ModuleA
11+
// CHECK-NEXT: @_exported import ModuleB
12+
// CHECK-NOT: import
13+
// CHECK-EMPTY:
14+
15+
// CHECK-NEXT: func basic_include(_ p: UnsafePointer<a_t>!, _ len: a_t)
16+
// CHECK-NEXT: func non_exported_include(_ p: UnsafePointer<b_t>!, _ len: b_t)
17+
// CHECK-NEXT: func submodule_include(_ p: UnsafePointer<c_t>!, _ len: c_t)
18+
// CHECK-NEXT: func explicit_submodule_include(_ p: UnsafePointer<d_t>!, _ len: d_t)
19+
// CHECK-NEXT: func deep_submodule_noexport(_ p: UnsafePointer<e_t>!, _ len: e_t)
20+
21+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
22+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
23+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func basic_include(_ p: Span<a_t>)
24+
25+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
26+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
27+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func deep_submodule_noexport(_ p: Span<e_t>)
28+
29+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
30+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
31+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func explicit_submodule_include(_ p: Span<d_t>)
32+
33+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
34+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
35+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func non_exported_include(_ p: Span<b_t>)
36+
37+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
38+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
39+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func submodule_include(_ p: Span<c_t>)
40+
41+
public func callBasicInclude(_ p: Span<CInt>) {
42+
basic_include(p)
43+
}
44+
45+
public func callNonExported(_ p: Span<CInt>) {
46+
non_exported_include(p)
47+
}
48+
49+
public func callSubmoduleInclude(_ p: Span<CInt>) {
50+
submodule_include(p)
51+
}
52+
53+
public func callExplicitSubmoduleInclude(_ p: Span<CInt>) {
54+
explicit_submodule_include(p)
55+
}
56+
57+
public func callDeepSubmoduleNoexport(_ p: Span<CInt>) {
58+
deep_submodule_noexport(p)
59+
}

0 commit comments

Comments
 (0)