Skip to content

Commit 406cc1d

Browse files
committed
[ImportResolution] Override module imports for macros in namespaces
Contents in namespaces are imported to the bridging header module `__ObjC`. When macros attached to a decl imported from a namespace are expanded, they also end up in `__ObjC`. This prevents them from inheriting imports from the module they originated in. This patch implements a workaround by adding an alternative constructor to `ImportResolver` that takes an explicit origin module as input, overriding which module counts as the "parent" module.
1 parent da96079 commit 406cc1d

File tree

4 files changed

+79
-14
lines changed

4 files changed

+79
-14
lines changed

include/swift/Subsystems.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ namespace swift {
125125

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

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

lib/Sema/ImportResolution.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,14 @@ class ImportResolver final : public DeclVisitor<ImportResolver> {
197197
addImplicitImports();
198198
}
199199

200+
// FIXME: Remove this ctor once namespace contents are imported to their
201+
// corresponding module instead of the __ObjC module
202+
ImportResolver(SourceFile &SF, ModuleDecl *explicitUnderlyingClangModule)
203+
: SF(SF), ctx(SF.getASTContext()),
204+
underlyingClangModule(explicitUnderlyingClangModule) {
205+
addImplicitImports();
206+
}
207+
200208
void addImplicitImports();
201209

202210
void addImplicitImport(ModuleDecl *module) {
@@ -326,12 +334,13 @@ void swift::performImportResolution(SourceFile &SF) {
326334
verify(SF);
327335
}
328336

329-
void swift::performImportResolutionForClangMacroBuffer(SourceFile &SF) {
337+
void swift::performImportResolutionForClangMacroBuffer(
338+
SourceFile &SF, ModuleDecl *explicitOriginModule) {
330339
assert(SF.ASTStage == SourceFile::Unprocessed);
331340

332341
// `getWrapperForModule` has already declared all the implicit clang module
333342
// imports we need
334-
ImportResolver resolver(SF);
343+
ImportResolver resolver(SF, explicitOriginModule);
335344
SF.setImports(resolver.getFinishedImports());
336345
SF.setImportedUnderlyingModule(resolver.getUnderlyingClangModule());
337346

@@ -597,7 +606,19 @@ ModuleImplicitImportsRequest::evaluate(Evaluator &evaluator,
597606
}
598607

599608
void ImportResolver::addImplicitImports() {
600-
auto implicitImports = SF.getParentModule()->getImplicitImports();
609+
// This is a workaround for the fact that namespaces are imported into the
610+
// bridging header module. To allow correct lookup, we expose a ctor with an
611+
// explicit underlying clang module input, which is the clang module that this
612+
// macro expansion actually originates in.
613+
const ModuleDecl *moduleToInherit = nullptr;
614+
if (underlyingClangModule) {
615+
moduleToInherit = underlyingClangModule;
616+
boundImports.push_back(
617+
AttributedImport(ImportedModule(underlyingClangModule)));
618+
} else {
619+
moduleToInherit = SF.getParentModule();
620+
}
621+
auto implicitImports = moduleToInherit->getImplicitImports();
601622

602623
// TODO: Support cross-module imports.
603624
for (auto &import : implicitImports.imports) {

lib/Sema/TypeCheckMacros.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,12 @@ createMacroSourceFile(std::unique_ptr<llvm::MemoryBuffer> buffer,
10611061
if (auto parentSourceFile = dc->getParentSourceFile())
10621062
macroSourceFile->setImports(parentSourceFile->getImports());
10631063
else if (isa<ClangModuleUnit>(dc->getModuleScopeContext())) {
1064-
performImportResolutionForClangMacroBuffer(*macroSourceFile);
1064+
ModuleDecl *originModule = nullptr;
1065+
// FIXME: remove this workaround once namespace contents are imported into
1066+
// their corresponding modules
1067+
if (macroSourceFile->getParentModule()->isClangHeaderImportModule())
1068+
originModule = cast<Decl *>(target)->getModuleContextForNameLookup();
1069+
performImportResolutionForClangMacroBuffer(*macroSourceFile, originModule);
10651070
}
10661071
return macroSourceFile;
10671072
}
Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,66 @@
11
// REQUIRES: swift_feature_SafeInteropWrappers
22

3-
// RUN: rm -rf %t
3+
// RUN: %empty-directory(%t)
44
// RUN: split-file %s %t
5-
// RUN: %target-swift-ide-test -plugin-path %swift-plugin-dir -I %t/Inputs -cxx-interoperability-mode=upcoming-swift -enable-experimental-feature SafeInteropWrappers -print-module -module-to-print=Namespace -source-filename=x | %FileCheck %s
6-
// RUN: %target-swift-frontend -plugin-path %swift-plugin-dir -I %t/Inputs -cxx-interoperability-mode=default -enable-experimental-feature SafeInteropWrappers %t/namespace.swift -dump-macro-expansions -typecheck -verify
5+
// RUN: %target-swift-frontend -plugin-path %swift-plugin-dir -I %t/Inputs -cxx-interoperability-mode=default -enable-experimental-feature SafeInteropWrappers %t/namespace.swift -emit-module -verify
6+
// RUN: %target-swift-ide-test -plugin-path %swift-plugin-dir -I %t/Inputs -cxx-interoperability-mode=upcoming-swift -enable-experimental-feature SafeInteropWrappers -print-module -module-to-print=Namespace -source-filename=x > %t/interface.txt
7+
// RUN: diff %t/interface.txt %t/interface.txt.expected
78

8-
// CHECK: enum foo {
9-
// CHECK: static func bar(_ p: UnsafeMutableBufferPointer<Float>)
9+
//--- interface.txt.expected
10+
@_exported import Namespace.Baz
1011

12+
enum foo {
13+
static func foo_func(_ p: UnsafeMutablePointer<Float>!, _ len: Int32)
14+
/// This is an auto-generated wrapper for safer interop
15+
@_alwaysEmitIntoClient @_disfavoredOverload public static func foo_func(_ p: UnsafeMutableBufferPointer<Float>)
16+
static func foo_func2(_ p: UnsafePointer<baz_t>!, _ len: baz_t)
17+
/// This is an auto-generated wrapper for safer interop
18+
@available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
19+
@_alwaysEmitIntoClient @_disfavoredOverload public static func foo_func2(_ p: Span<baz_t>)
20+
enum bar {
21+
static func bar_func(_ p: UnsafePointer<baz_t>!, _ len: baz_t)
22+
/// This is an auto-generated wrapper for safer interop
23+
@available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
24+
@_alwaysEmitIntoClient @_disfavoredOverload public static func bar_func(_ p: Span<baz_t>)
25+
}
26+
}
1127
//--- Inputs/module.modulemap
1228
module Namespace {
1329
header "namespace.h"
1430
requires cplusplus
31+
module Baz {
32+
header "baz.h"
33+
}
1534
}
1635

1736
//--- Inputs/namespace.h
37+
#include "baz.h"
38+
39+
#define __counted_by(x) __attribute__((__counted_by__(x)))
40+
#define __noescape __attribute__((noescape))
1841

1942
namespace foo {
20-
__attribute__((swift_attr("@_SwiftifyImport(.countedBy(pointer: .param(1), count: \"len\"))"))) void bar(float *p, int len);
43+
__attribute__((swift_attr("@_SwiftifyImport(.countedBy(pointer: .param(1), count: \"len\"))"))) void foo_func(float *p, int len);
44+
void foo_func2(const baz_t * __counted_by(len) p __noescape, baz_t len);
45+
namespace bar {
46+
void bar_func(const baz_t * __counted_by(len) p __noescape, baz_t len);
47+
}
2148
}
2249

50+
//--- Inputs/baz.h
51+
typedef int baz_t;
52+
2353
//--- namespace.swift
2454
import Namespace
25-
55+
2656
func test(s: UnsafeMutableBufferPointer<Float>) {
27-
foo.bar(s)
28-
}
57+
foo.foo_func(s)
58+
}
59+
60+
func test2(s: Span<CInt>) {
61+
foo.foo_func2(s)
62+
}
63+
64+
func test3(s: Span<CInt>) {
65+
foo.bar.bar_func(s)
66+
}

0 commit comments

Comments
 (0)