Skip to content

Commit 8542903

Browse files
committed
Only inherit C++ modules when C++ interop enabled
Imports of modules marked `requires: cplusplus` should only be inherited when C++ interop is enabled. Similarly, imports of modules marked `requires: !cplusplus` should only be inherited when C++ interop is disabled.
1 parent 634084b commit 8542903

File tree

2 files changed

+158
-4
lines changed

2 files changed

+158
-4
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2848,13 +2848,19 @@ ClangModuleUnit *ClangImporter::Implementation::getWrapperForModule(
28482848
for (auto UI : implicitImportInfo.AdditionalUnloadedImports)
28492849
Imported.insert(UI.module.getImportPath());
28502850
assert(implicitImportInfo.AdditionalImports.empty());
2851+
const bool cxx = SwiftContext.LangOpts.EnableCXXInterop;
28512852

2852-
auto addImplicitImport = [&implicitImportInfo, &Imported,
2853+
auto addImplicitImport = [&implicitImportInfo, &Imported, cxx,
28532854
this](const clang::Module *M,
28542855
bool guaranteedUnique) {
2855-
const bool cannotBeImported = llvm::any_of(M->Requirements, [](auto &Req) {
2856-
return !Req.RequiredState && Req.FeatureName == "swift";
2857-
});
2856+
const bool cannotBeImported =
2857+
llvm::any_of(M->Requirements, [cxx](auto &Req) {
2858+
if (Req.FeatureName == "swift")
2859+
return !Req.RequiredState;
2860+
if (Req.FeatureName == "cplusplus")
2861+
return Req.RequiredState != cxx;
2862+
return false;
2863+
});
28582864
if (cannotBeImported) {
28592865
return;
28602866
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// REQUIRES: swift_feature_SafeInteropWrappers
2+
3+
// Tests that we don't try to import modules that don't work well with C++ interop (when enabled)
4+
5+
// RUN: %empty-directory(%t)
6+
// RUN: split-file --leading-lines %s %t
7+
8+
// Case 1: a.swift calls A1.B1.foo with C++ interop
9+
// RUN: not %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -cxx-interoperability-mode=default -I %t%{fs-sep}Inputs -enable-experimental-feature SafeInteropWrappers %t/a.swift -dump-source-file-imports 2>&1 | %FileCheck --check-prefixes CHECK-A,CHECK-A-CXX %s
10+
// RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -cxx-interoperability-mode=default -I %t%{fs-sep}Inputs -enable-experimental-feature SafeInteropWrappers %t/a.swift -verify -verify-additional-prefix cxx- -verify-additional-file %t%{fs-sep}Inputs%{fs-sep}B1.h -verify-ignore-macro-note
11+
12+
// Case 2: a.swift calls A1.B1.foo without C++ interop
13+
// RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t%{fs-sep}Inputs -enable-experimental-feature SafeInteropWrappers %t/a.swift -dump-source-file-imports 2>&1 | %FileCheck --check-prefixes CHECK-A,CHECK-A-C %s
14+
// RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t%{fs-sep}Inputs -enable-experimental-feature SafeInteropWrappers %t/a.swift -verify
15+
16+
// Case 3: b.swift calls A2.B2.foo with C++ interop
17+
// RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -cxx-interoperability-mode=default -I %t%{fs-sep}Inputs -enable-experimental-feature SafeInteropWrappers %t/b.swift -dump-source-file-imports 2>&1 | %FileCheck --check-prefixes CHECK-B,CHECK-B-CXX %s
18+
// RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -cxx-interoperability-mode=default -I %t%{fs-sep}Inputs -enable-experimental-feature SafeInteropWrappers %t/b.swift -verify
19+
20+
// Case 4: b.swift calls A2.B2.foo without C++ interop
21+
// RUN: not %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t%{fs-sep}Inputs -enable-experimental-feature SafeInteropWrappers %t/b.swift -dump-source-file-imports 2>&1 | %FileCheck --check-prefix CHECK-B %s
22+
// RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t%{fs-sep}Inputs -enable-experimental-feature SafeInteropWrappers %t/b.swift -verify -verify-additional-prefix c- -verify-additional-file %t%{fs-sep}Inputs%{fs-sep}B2.h -verify-ignore-macro-note
23+
24+
// CHECK-A: imports for {{.*}}a.swift:
25+
// CHECK-A-NEXT: Swift
26+
// CHECK-A-CXX-NEXT: CxxShim
27+
// CHECK-A-CXX-NEXT: Cxx
28+
// CHECK-A-NEXT: _StringProcessing
29+
// CHECK-A-NEXT: _SwiftConcurrencyShims
30+
// CHECK-A-NEXT: _Concurrency
31+
// CHECK-A-NEXT: B1
32+
// CHECK-A-NEXT: A1
33+
// CHECK-A-NEXT: imports for A1.foo:
34+
35+
// CHECK-A-NEXT: imports for @__swiftmacro{{.*}}foo{{.*}}_SwiftifyImport{{.*}}.swift:
36+
// CHECK-A-NEXT: Swift
37+
// CHECK-A-C-NEXT: C1
38+
// CHECK-A-NEXT: B1
39+
// CHECK-A-CXX-NEXT: CxxShim
40+
// CHECK-A-CXX-NEXT: Cxx
41+
// CHECK-A-NEXT: _StringProcessing
42+
// CHECK-A-NEXT: _SwiftConcurrencyShims
43+
// CHECK-A-NEXT: _Concurrency
44+
45+
// CHECK-B: imports for {{.*}}b.swift:
46+
// CHECK-B-NEXT: Swift
47+
// CHECK-B-CXX-NEXT: CxxShim
48+
// CHECK-B-CXX-NEXT: Cxx
49+
// CHECK-B-NEXT: _StringProcessing
50+
// CHECK-B-NEXT: _SwiftConcurrencyShims
51+
// CHECK-B-NEXT: _Concurrency
52+
// CHECK-B-NEXT: B2
53+
// CHECK-B-NEXT: A2
54+
// CHECK-B-NEXT: imports for A2.bar:
55+
56+
// CHECK-B-NEXT: imports for @__swiftmacro{{.*}}bar{{.*}}_SwiftifyImport{{.*}}.swift:
57+
// CHECK-B-NEXT: Swift
58+
// CHECK-B-CXX-NEXT: C2
59+
// CHECK-B-NEXT: B2
60+
// CHECK-B-CXX-NEXT: CxxShim
61+
// CHECK-B-CXX-NEXT: Cxx
62+
// CHECK-B-NEXT: _StringProcessing
63+
// CHECK-B-NEXT: _SwiftConcurrencyShims
64+
// CHECK-B-NEXT: _Concurrency
65+
66+
67+
//--- Inputs/module.modulemap
68+
module A1 {
69+
explicit module B1 {
70+
header "B1.h"
71+
explicit module C1 {
72+
header "C1.h"
73+
requires !cplusplus
74+
}
75+
}
76+
}
77+
module A2 {
78+
explicit module B2 {
79+
header "B2.h"
80+
explicit module C2 {
81+
header "C2.h"
82+
requires cplusplus
83+
}
84+
}
85+
}
86+
87+
//--- Inputs/B1.h
88+
#pragma once
89+
90+
#include "C1.h"
91+
#define __sized_by(s) __attribute__((__sized_by__(s)))
92+
93+
// foo causes an error with cxx-interop
94+
c1_t foo(void * _Nonnull __sized_by(size), int size);
95+
/*
96+
expected-cxx-note@-2{{'foo' declared here}}
97+
expected-cxx-expansion@-3:54{{
98+
expected-cxx-error@2:110{{cannot find type 'c1_t' in scope}}
99+
}}
100+
*/
101+
102+
//--- Inputs/B2.h
103+
#pragma once
104+
105+
#include "C2.h"
106+
#define __sized_by(s) __attribute__((__sized_by__(s)))
107+
108+
// bar causes an error without cxx-interop
109+
c2_t bar(void * _Nonnull __sized_by(size), int size);
110+
/*
111+
expected-c-note@-2{{'bar' declared here}}
112+
expected-c-expansion@-3:54{{
113+
expected-c-error@2:110{{cannot find type 'c2_t' in scope}}
114+
}}
115+
*/
116+
117+
//--- Inputs/C1.h
118+
#pragma once
119+
120+
typedef int c1_t;
121+
122+
//--- Inputs/C2.h
123+
#pragma once
124+
125+
typedef int c2_t;
126+
127+
//--- a.swift
128+
import A1.B1
129+
130+
public func callUnsafe(_ p: UnsafeMutableRawPointer) {
131+
let _ = foo(p, 13)
132+
}
133+
public func callSafe(_ p: UnsafeMutableRawBufferPointer) {
134+
let _ = foo(p) // expected-cxx-error{{cannot convert value of type 'UnsafeMutableRawBufferPointer' to expected argument type 'UnsafeMutableRawPointer'}}
135+
// expected-cxx-error@-1{{missing argument}}
136+
}
137+
138+
//--- b.swift
139+
import A2.B2
140+
141+
public func callUnsafe(_ p: UnsafeMutableRawPointer) {
142+
let _ = bar(p, 13)
143+
}
144+
public func callSafe(_ p: UnsafeMutableRawBufferPointer) {
145+
let _ = bar(p) // expected-c-error{{cannot convert value of type 'UnsafeMutableRawBufferPointer' to expected argument type 'UnsafeMutableRawPointer'}}
146+
// expected-c-error@-1{{missing argument}}
147+
148+
}

0 commit comments

Comments
 (0)