Skip to content

Commit e1ec45e

Browse files
committed
1 parent fa39569 commit e1ec45e

7 files changed

+107
-7
lines changed

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/Decl.h"
2222
#include "swift/AST/DeclContext.h"
2323
#include "swift/AST/Initializer.h"
24+
#include "swift/AST/ModuleNameLookup.h"
2425
#include "swift/AST/ProtocolConformance.h"
2526
#include "swift/AST/SourceFile.h"
2627
#include "swift/AST/TypeDeclFinder.h"
@@ -160,6 +161,34 @@ static bool diagnoseDeclExportability(SourceLoc loc, const ValueDecl *D,
160161
if (originKind == DisallowedOriginKind::None)
161162
return false;
162163

164+
// Even if the current module is @_implementationOnly, Swift should
165+
// not report an error in the cases where the symbol is also exported from
166+
// a non @_implementationOnly module. Thus, we look at all the imported
167+
// modules and see if we can find the symbol in a non @_implementationOnly
168+
// module.
169+
SmallVector<ImportedModule, 4> importedModules;
170+
userSF.getImportedModules(
171+
importedModules,
172+
ModuleDecl::ImportFilter(
173+
{ModuleDecl::ImportFilterKind::Exported,
174+
ModuleDecl::ImportFilterKind::Default,
175+
ModuleDecl::ImportFilterKind::SPIAccessControl,
176+
ModuleDecl::ImportFilterKind::ShadowedByCrossImportOverlay}));
177+
auto nlOptions = NL_UnqualifiedDefault | NL_IncludeUsableFromInline;
178+
179+
for (auto &importedModule : importedModules) {
180+
SmallVector<ValueDecl *, 4> decls;
181+
namelookup::lookupInModule(importedModule.importedModule, D->getName(),
182+
decls, NLKind::UnqualifiedLookup,
183+
namelookup::ResolutionKind::Overloadable,
184+
importedModule.importedModule, nlOptions);
185+
186+
for (auto *decl : decls) {
187+
if (decl->getFormalAccess() >= AccessLevel::Public) {
188+
return false;
189+
}
190+
}
191+
}
163192
// TODO: different diagnostics
164193
ASTContext &ctx = definingModule->getASTContext();
165194
ctx.Diags.diagnose(loc, diag::inlinable_decl_ref_from_hidden_module,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@_exported import UserA
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@_exported import UserB
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: mkdir %t/use_module_a %t/use_module_b
3+
// RUN: %target-swift-frontend -enable-library-evolution -swift-version 5 -emit-module -o %t/use_module_a/UseModuleA.swiftmodule %S/Inputs/use-module-a.swift -I %S/Inputs -enable-cxx-interop
4+
// RUN: %target-swift-frontend -enable-library-evolution -swift-version 5 -emit-module -o %t/use_module_b/UseModuleB.swiftmodule %S/Inputs/use-module-b.swift -I %S/Inputs -enable-cxx-interop
5+
6+
// RUN: %target-swift-frontend -typecheck -swift-version 5 -I %t/use_module_a -I %t/use_module_b -I %S/Inputs -enable-cxx-interop %s
7+
8+
9+
// If a symbol comes from two modules, one of which is marked as
10+
// @_implementationOnly, Swift may choose the @_implementationOnly source
11+
// and then error out due to the symbol being hidden.
12+
13+
// Swift should consider all sources for the symbol and recognize that the
14+
// symbol is not hidden behind @_implementationOnly in all modules.
15+
16+
// This test, as well as the `lookup-visible-symbols-recursively.swift` check
17+
// that the `getFortyTwo` symbol can be found when at least one of the
18+
// modules is not `@_implementationOnly`.
19+
20+
@_implementationOnly import UseModuleA
21+
import UseModuleB
22+
23+
@inlinable
24+
public func callFortyTwo() -> CInt {
25+
return getFortyTwo()
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: mkdir %t/use_module_a %t/use_module_b
3+
// RUN: %target-swift-frontend -enable-library-evolution -swift-version 5 -emit-module -o %t/use_module_a/UseModuleA.swiftmodule %S/Inputs/use-module-a.swift -I %S/Inputs -enable-cxx-interop
4+
// RUN: %target-swift-frontend -enable-library-evolution -swift-version 5 -emit-module -o %t/use_module_b/UseModuleB.swiftmodule %S/Inputs/use-module-b.swift -I %S/Inputs -enable-cxx-interop
5+
6+
// RUN: %target-swift-frontend -typecheck -swift-version 5 -I %t/use_module_a -I %t/use_module_b -I %S/Inputs -enable-cxx-interop %s
7+
8+
9+
// If a symbol comes from two modules, one of which is marked as
10+
// @_implementationOnly, Swift may choose the @_implementationOnly source
11+
// and then error out due to the symbol being hidden.
12+
13+
// Swift should consider all sources for the symbol and recognize that the
14+
// symbol is not hidden behind @_implementationOnly in all modules.
15+
16+
// This test, as well as the `lookup-visible-symbols-recursively-inversed.swift
17+
// check that the `getFortyTwo` symbol can be found when at least one of the
18+
// modules is not `@_implementationOnly`.
19+
20+
import UseModuleA
21+
@_implementationOnly import UseModuleB
22+
23+
@inlinable
24+
public func callFortyTwo() -> CInt {
25+
return getFortyTwo()
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t/FortyTwo.swiftmodule -I %S/Inputs %s
3+
4+
// If a symbol comes from two modules, one of which is marked as
5+
// @_implementationOnly, Swift may choose the @_implementationOnly source
6+
// and then error out due to the symbol being hidden.
7+
8+
// Swift should consider all sources for the symbol and recognize that the
9+
// symbol is not hidden behind @_implementationOnly in all modules.
10+
11+
// In this test case, UserA and UserB both textually include `helper.h`,
12+
// therefore both export `getFortyTwo()`.
13+
// This test verifies that even if Swift chooses UserB.getFortyTwo(), it
14+
// doesn't error out, because the symbol is also exported from UserA.
15+
16+
import UserA
17+
@_implementationOnly import UserB
18+
19+
@_inlineable
20+
public func callFortyTwo() -> CInt {
21+
return getFortyTwo()
22+
}

test/Interop/C/implementation-only-imports/prefer-a-visible-symbol-over-implementation-only-ones.swift

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %target-swift-frontend -emit-module -o %t/FortyTwo.swiftmodule -I %S/Inputs %s
33

4-
// REQUIRES: SR-13785
5-
6-
// TODO: Fix @_implementationOnly to consider all symbol sources
7-
84
// If a symbol comes from two modules, one of which is marked as
95
// @_implementationOnly, Swift may choose the @_implementationOnly source
106
// and then error out due to the symbol being hidden.
117

128
// Swift should consider all sources for the symbol and recognize that the
139
// symbol is not hidden behind @_implementationOnly in all modules.
1410

15-
// E.g:
1611
// In this test case, UserA and UserB both textually include `helper.h`,
1712
// therefore both export `getFortyTwo()`.
18-
// This test verifies that even though Swift chooses UserA.getFortyTwo(), we
19-
// shouldn't get an error, because the symbol is also exported from UserB.
13+
// This test verifies that even if Swift chooses UserA.getFortyTwo(), it
14+
// doesn't error out, because the symbol is also exported from UserB.
2015

2116
@_implementationOnly import UserA
2217
import UserB

0 commit comments

Comments
 (0)