diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index 37f0e007ea9c2..59ccf4f94b74c 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -22,6 +22,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/Import.h" #include "swift/AST/Pattern.h" #include "swift/AST/ParameterList.h" #include "swift/AST/TypeCheckRequests.h" @@ -1439,7 +1440,6 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, } } }; - } // end anonymous namespace /// Returns the kind of origin, implementation-only import or SPI declaration, @@ -1459,6 +1459,40 @@ swift::getDisallowedOriginKind(const Decl *decl, if (where.isSPI()) downgradeToWarning = DowngradeToWarning::Yes; + // Even if the current module is @_implementationOnly, Swift should + // not report an error in the cases where the decl is also exported from + // a non @_implementationOnly module. Thus, we check to see if there is + // a visible access path to the Clang decl, and only error out in case + // there is none. + auto filter = ModuleDecl::ImportFilter( + {ModuleDecl::ImportFilterKind::Exported, + ModuleDecl::ImportFilterKind::Default, + ModuleDecl::ImportFilterKind::SPIAccessControl, + ModuleDecl::ImportFilterKind::ShadowedByCrossImportOverlay}); + SmallVector sfImportedModules; + SF->getImportedModules(sfImportedModules, filter); + if (auto clangDecl = decl->getClangDecl()) { + for (auto redecl : clangDecl->redecls()) { + if (auto tagReDecl = dyn_cast(redecl)) { + // This is a forward declaration. We ignore visibility of those. + if (tagReDecl->getBraceRange().isInvalid()) { + continue; + } + } + auto moduleWrapper = + decl->getASTContext().getClangModuleLoader()->getWrapperForModule( + redecl->getOwningModule()); + auto visibleAccessPath = + find_if(sfImportedModules, [&moduleWrapper](auto importedModule) { + return importedModule.importedModule == moduleWrapper || + !importedModule.importedModule + ->isImportedImplementationOnly(moduleWrapper); + }); + if (visibleAccessPath != sfImportedModules.end()) { + return DisallowedOriginKind::None; + } + } + } // Implementation-only imported, cannot be reexported. return DisallowedOriginKind::ImplementationOnly; } else if (decl->isSPI() && !where.isSPI()) { diff --git a/test/Interop/C/implementation-only-imports/Inputs/module.modulemap b/test/Interop/C/implementation-only-imports/Inputs/module.modulemap index dd845b25d568c..cd5b5d67c7df1 100644 --- a/test/Interop/C/implementation-only-imports/Inputs/module.modulemap +++ b/test/Interop/C/implementation-only-imports/Inputs/module.modulemap @@ -1,9 +1,9 @@ module UserA { - header "user_a.h" + header "user-a.h" export * } module UserB { - header "user_b.h" + header "user-b.h" export * } diff --git a/test/Interop/C/implementation-only-imports/Inputs/use-module-a.swift b/test/Interop/C/implementation-only-imports/Inputs/use-module-a.swift new file mode 100644 index 0000000000000..f806673847548 --- /dev/null +++ b/test/Interop/C/implementation-only-imports/Inputs/use-module-a.swift @@ -0,0 +1 @@ +@_exported import UserA diff --git a/test/Interop/C/implementation-only-imports/Inputs/use-module-b.swift b/test/Interop/C/implementation-only-imports/Inputs/use-module-b.swift new file mode 100644 index 0000000000000..7708e676ab393 --- /dev/null +++ b/test/Interop/C/implementation-only-imports/Inputs/use-module-b.swift @@ -0,0 +1 @@ +@_exported import UserB diff --git a/test/Interop/C/implementation-only-imports/Inputs/user-a.h b/test/Interop/C/implementation-only-imports/Inputs/user-a.h new file mode 100644 index 0000000000000..4f6d821f9b7fb --- /dev/null +++ b/test/Interop/C/implementation-only-imports/Inputs/user-a.h @@ -0,0 +1,6 @@ +#ifndef TEST_INTEROP_C_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_A_H +#define TEST_INTEROP_C_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_A_H + +#include "helper.h" + +#endif // TEST_INTEROP_C_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_A_H diff --git a/test/Interop/C/implementation-only-imports/Inputs/user-b.h b/test/Interop/C/implementation-only-imports/Inputs/user-b.h new file mode 100644 index 0000000000000..7b7dbc7a6fd1e --- /dev/null +++ b/test/Interop/C/implementation-only-imports/Inputs/user-b.h @@ -0,0 +1,6 @@ +#ifndef TEST_INTEROP_C_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_B_H +#define TEST_INTEROP_C_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_B_H + +#include "helper.h" + +#endif // TEST_INTEROP_C_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_B_H diff --git a/test/Interop/C/implementation-only-imports/Inputs/user_a.h b/test/Interop/C/implementation-only-imports/Inputs/user_a.h deleted file mode 100644 index bebbd757c5561..0000000000000 --- a/test/Interop/C/implementation-only-imports/Inputs/user_a.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef TEST_INTEROP_C_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USERA_H -#define TEST_INTEROP_C_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USERA_H - -#include "helper.h" - -#endif // TEST_INTEROP_C_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USERA_H diff --git a/test/Interop/C/implementation-only-imports/Inputs/user_b.h b/test/Interop/C/implementation-only-imports/Inputs/user_b.h deleted file mode 100644 index 2beac678bf1d2..0000000000000 --- a/test/Interop/C/implementation-only-imports/Inputs/user_b.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef TEST_INTEROP_C_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USERB_H -#define TEST_INTEROP_C_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USERB_H - -#include "helper.h" - -#endif // TEST_INTEROP_C_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USERB_H diff --git a/test/Interop/C/implementation-only-imports/check-function-transitive-visibility-inversed.swift b/test/Interop/C/implementation-only-imports/check-function-transitive-visibility-inversed.swift new file mode 100644 index 0000000000000..6746f49d7a49b --- /dev/null +++ b/test/Interop/C/implementation-only-imports/check-function-transitive-visibility-inversed.swift @@ -0,0 +1,21 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir %t/use_module_a %t/use_module_b +// 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 +// 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 + +// RUN: %target-swift-frontend -typecheck -swift-version 5 -I %t/use_module_a -I %t/use_module_b -I %S/Inputs %s + +// Swift should consider all sources for a decl and recognize that the +// decl is not hidden behind @_implementationOnly in all modules. + +// This test, as well as `check-function-transitive-visibility.swift` +// ensures that Swift looks into the transitive visible modules as well +// when looking for the `getFortyTwo()` decl. + +import UseModuleA +@_implementationOnly import UseModuleB + +@inlinable +public func callFortyTwo() -> CInt { + return getFortyTwo() +} diff --git a/test/Interop/C/implementation-only-imports/check-function-transitive-visibility.swift b/test/Interop/C/implementation-only-imports/check-function-transitive-visibility.swift new file mode 100644 index 0000000000000..35515bfbcde54 --- /dev/null +++ b/test/Interop/C/implementation-only-imports/check-function-transitive-visibility.swift @@ -0,0 +1,21 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir %t/use_module_a %t/use_module_b +// 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 +// 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 + +// RUN: %target-swift-frontend -typecheck -swift-version 5 -I %t/use_module_a -I %t/use_module_b -I %S/Inputs %s + +// Swift should consider all sources for a decl and recognize that the +// decl is not hidden behind @_implementationOnly in all modules. + +// This test, as well as `check-function-transitive-visibility-inversed.swift` +// ensures that Swift looks into the transitive visible modules as well +// when looking for the `getFortyTwo()` decl. + +import UseModuleA +@_implementationOnly import UseModuleB + +@inlinable +public func callFortyTwo() -> CInt { + return getFortyTwo() +} diff --git a/test/Interop/C/implementation-only-imports/check-function-visibility-inversed.swift b/test/Interop/C/implementation-only-imports/check-function-visibility-inversed.swift new file mode 100644 index 0000000000000..974349324ea83 --- /dev/null +++ b/test/Interop/C/implementation-only-imports/check-function-visibility-inversed.swift @@ -0,0 +1,17 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/FortyTwo.swiftmodule -I %S/Inputs %s + +// Swift should consider all sources for a decl and recognize that the +// decl is not hidden behind @_implementationOnly in all modules. + +// This test, as well as `check-function-visibility.swift` +// checks that the `getFortyTwo` decl can be found when at least one of the +// modules is not `@_implementationOnly`. + +import UserA +@_implementationOnly import UserB + +@_inlineable +public func callFortyTwo() -> CInt { + return getFortyTwo() +} diff --git a/test/Interop/C/implementation-only-imports/check-function-visibility.swift b/test/Interop/C/implementation-only-imports/check-function-visibility.swift new file mode 100644 index 0000000000000..b427725e1e155 --- /dev/null +++ b/test/Interop/C/implementation-only-imports/check-function-visibility.swift @@ -0,0 +1,17 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/FortyTwo.swiftmodule -I %S/Inputs %s + +// Swift should consider all sources for a decl and recognize that the +// decl is not hidden behind @_implementationOnly in all modules. + +// This test, as well as `check-function-visibility-inversed.swift` +// checks that the `getFortyTwo()` decl can be found when at least one of the +// modules is not `@_implementationOnly`. + +@_implementationOnly import UserA +import UserB + +@_inlineable +public func callFortyTwo() -> CInt { + return getFortyTwo() +} diff --git a/test/Interop/C/implementation-only-imports/prefer-a-visible-symbol-over-implementation-only-ones.swift b/test/Interop/C/implementation-only-imports/prefer-a-visible-symbol-over-implementation-only-ones.swift deleted file mode 100644 index a7a04c655547c..0000000000000 --- a/test/Interop/C/implementation-only-imports/prefer-a-visible-symbol-over-implementation-only-ones.swift +++ /dev/null @@ -1,27 +0,0 @@ -// RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -emit-module -o %t/FortyTwo.swiftmodule -I %S/Inputs %s - -// REQUIRES: SR-13785 - -// TODO: Fix @_implementationOnly to consider all symbol sources - -// If a symbol comes from two modules, one of which is marked as -// @_implementationOnly, Swift may choose the @_implementationOnly source -// and then error out due to the symbol being hidden. - -// Swift should consider all sources for the symbol and recognize that the -// symbol is not hidden behind @_implementationOnly in all modules. - -// E.g: -// In this test case, UserA and UserB both textually include `helper.h`, -// therefore both export `getFortyTwo()`. -// This test verifies that even though Swift chooses UserA.getFortyTwo(), we -// shouldn't get an error, because the symbol is also exported from UserB. - -@_implementationOnly import UserA -import UserB - -@_inlineable -public func callFortyTwo() -> CInt { - return getFortyTwo() -} diff --git a/test/Interop/Cxx/implementation-only-imports/Inputs/decl-a.h b/test/Interop/Cxx/implementation-only-imports/Inputs/decl-a.h new file mode 100644 index 0000000000000..72998faab7e62 --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/Inputs/decl-a.h @@ -0,0 +1,6 @@ +#ifndef TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_DECL_A_H +#define TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_DECL_A_H + +inline int getFortySomething() { return 42; }; + +#endif // TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_DECL_A_H diff --git a/test/Interop/Cxx/implementation-only-imports/Inputs/decl-b.h b/test/Interop/Cxx/implementation-only-imports/Inputs/decl-b.h new file mode 100644 index 0000000000000..35839a51051af --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/Inputs/decl-b.h @@ -0,0 +1,6 @@ +#ifndef TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_DECL_B_H +#define TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_DECL_B_H + +inline int getFortySomething() { return 46; }; + +#endif // TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_DECL_B_H diff --git a/test/Interop/Cxx/implementation-only-imports/Inputs/helper.h b/test/Interop/Cxx/implementation-only-imports/Inputs/helper.h new file mode 100644 index 0000000000000..5c4d405bb5d61 --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/Inputs/helper.h @@ -0,0 +1,20 @@ +#ifndef TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_HELPER_H +#define TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_HELPER_H + +inline int getFortyTwo() { return 42; } + +class MagicWrapper { +public: + int _number; + MagicWrapper(){_number = 2;}; + MagicWrapper(int number) : _number(number){}; + MagicWrapper operator - (MagicWrapper other) { + return MagicWrapper{_number - other._number}; + } +}; + +inline MagicWrapper operator + (MagicWrapper lhs, MagicWrapper rhs) { + return MagicWrapper{lhs._number + rhs._number}; +} + +#endif // TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_HELPER_H diff --git a/test/Interop/Cxx/implementation-only-imports/Inputs/module.modulemap b/test/Interop/Cxx/implementation-only-imports/Inputs/module.modulemap new file mode 100644 index 0000000000000..b3d9edc456782 --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/Inputs/module.modulemap @@ -0,0 +1,24 @@ +module UserA { + header "user-a.h" + export * +} + +module UserB { + header "user-b.h" + export * +} + +module UserC { + header "user-c.h" + export * +} + +module DeclA { + header "decl-a.h" + export * +} + +module DeclB { + header "decl-b.h" + export * +} diff --git a/test/Interop/Cxx/implementation-only-imports/Inputs/use-module-a.swift b/test/Interop/Cxx/implementation-only-imports/Inputs/use-module-a.swift new file mode 100644 index 0000000000000..f806673847548 --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/Inputs/use-module-a.swift @@ -0,0 +1 @@ +@_exported import UserA diff --git a/test/Interop/Cxx/implementation-only-imports/Inputs/use-module-b.swift b/test/Interop/Cxx/implementation-only-imports/Inputs/use-module-b.swift new file mode 100644 index 0000000000000..7708e676ab393 --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/Inputs/use-module-b.swift @@ -0,0 +1 @@ +@_exported import UserB diff --git a/test/Interop/Cxx/implementation-only-imports/Inputs/user-a.h b/test/Interop/Cxx/implementation-only-imports/Inputs/user-a.h new file mode 100644 index 0000000000000..fb7daccebef6d --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/Inputs/user-a.h @@ -0,0 +1,6 @@ +#ifndef TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_A_H +#define TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_A_H + +#include "helper.h" + +#endif // TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_A_H diff --git a/test/Interop/Cxx/implementation-only-imports/Inputs/user-b.h b/test/Interop/Cxx/implementation-only-imports/Inputs/user-b.h new file mode 100644 index 0000000000000..1daeacb030ee3 --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/Inputs/user-b.h @@ -0,0 +1,6 @@ +#ifndef TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_B_H +#define TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_B_H + +#include "helper.h" + +#endif // TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_B_H diff --git a/test/Interop/Cxx/implementation-only-imports/Inputs/user-c.h b/test/Interop/Cxx/implementation-only-imports/Inputs/user-c.h new file mode 100644 index 0000000000000..db273238536a2 --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/Inputs/user-c.h @@ -0,0 +1,6 @@ +#ifndef TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_C_H +#define TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_C_H + +class MagicWrapper; + +#endif // TEST_INTEROP_CXX_IMPLEMENTATION_ONLY_IMPORTS_INPUTS_USER_C_H diff --git a/test/Interop/Cxx/implementation-only-imports/check-constructor-visibility-inversed.swift b/test/Interop/Cxx/implementation-only-imports/check-constructor-visibility-inversed.swift new file mode 100644 index 0000000000000..40ed6da45458f --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/check-constructor-visibility-inversed.swift @@ -0,0 +1,17 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/FortyTwo.swiftmodule -I %S/Inputs %s -enable-cxx-interop + +// Swift should consider all sources for a decl and recognize that the +// decl is not hidden behind @_implementationOnly in all modules. + +// This test, as well as `check-constructor-visibility.swift` checks +// that the constructor decl can be found when at least one of the +// modules is not `@_implementationOnly`. + +@_implementationOnly import UserA +import UserB + +@_inlineable +public func createAWrapper() { + let _ = MagicWrapper() +} diff --git a/test/Interop/Cxx/implementation-only-imports/check-constructor-visibility.swift b/test/Interop/Cxx/implementation-only-imports/check-constructor-visibility.swift new file mode 100644 index 0000000000000..e2fe2fe0ee3c2 --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/check-constructor-visibility.swift @@ -0,0 +1,17 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/FortyTwo.swiftmodule -I %S/Inputs %s -enable-cxx-interop + +// Swift should consider all sources for a decl and recognize that the +// decl is not hidden behind @_implementationOnly in all modules. + +// This test, as well as `check-constructor-visibility-inversed.swift` checks +// that the constructor decl can be found when at least one of the +// modules is not `@_implementationOnly`. + +import UserA +@_implementationOnly import UserB + +@_inlineable +public func createAWrapper() { + let _ = MagicWrapper() +} diff --git a/test/Interop/Cxx/implementation-only-imports/check-decls-are-identical.swift b/test/Interop/Cxx/implementation-only-imports/check-decls-are-identical.swift new file mode 100644 index 0000000000000..d43ce85a1c15b --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/check-decls-are-identical.swift @@ -0,0 +1,15 @@ +// RUN: %empty-directory(%t) +// RUN: not %target-swift-frontend -emit-module -o %t/FortyTwo.swiftmodule -I %S/Inputs -enable-cxx-interop %s 2>&1 | %FileCheck %s + +// This test checks that Swift recognizes that the DeclA and DeclB provide +// different implementations for `getFortySomething()` + +@_implementationOnly import DeclA +import DeclB + +@_inlineable +public func callFortySomething() -> CInt { + return getFortySomething() +} + +// CHECK: 'getFortySomething' has different definitions in different modules diff --git a/test/Interop/Cxx/implementation-only-imports/check-function-transitive-visibility-inversed.swift b/test/Interop/Cxx/implementation-only-imports/check-function-transitive-visibility-inversed.swift new file mode 100644 index 0000000000000..77def9dd320ae --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/check-function-transitive-visibility-inversed.swift @@ -0,0 +1,21 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir %t/use_module_a %t/use_module_b +// 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 +// 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 + +// 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 + +// Swift should consider all sources for a decl and recognize that the +// decl is not hidden behind @_implementationOnly in all modules. + +// This test, as well as `check-function-transitive-visibility.swift` +// ensures that Swift looks into the transitive visible modules as well +// when looking for the `getFortyTwo()` decl. + +@_implementationOnly import UseModuleA +import UseModuleB + +@inlinable +public func callFortyTwo() -> CInt { + return getFortyTwo() +} diff --git a/test/Interop/Cxx/implementation-only-imports/check-function-transitive-visibility.swift b/test/Interop/Cxx/implementation-only-imports/check-function-transitive-visibility.swift new file mode 100644 index 0000000000000..efb75d73401d2 --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/check-function-transitive-visibility.swift @@ -0,0 +1,22 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir %t/use_module_a %t/use_module_b +// 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 +// 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 + +// 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 + + +// Swift should consider all sources for a decl and recognize that the +// decl is not hidden behind @_implementationOnly in all modules. + +// This test, as well as `check-function-transitive-visibility-inversed.swift` +// ensures that Swift looks into the transitive visible modules as well +// when looking for the `getFortyTwo()` decl. + +import UseModuleA +@_implementationOnly import UseModuleB + +@inlinable +public func callFortyTwo() -> CInt { + return getFortyTwo() +} diff --git a/test/Interop/Cxx/implementation-only-imports/check-function-visibility-inversed.swift b/test/Interop/Cxx/implementation-only-imports/check-function-visibility-inversed.swift new file mode 100644 index 0000000000000..0f24a16bf8567 --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/check-function-visibility-inversed.swift @@ -0,0 +1,17 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/FortyTwo.swiftmodule -I %S/Inputs -enable-cxx-interop %s + +// Swift should consider all sources for a decl and recognize that the +// decl is not hidden behind @_implementationOnly in all modules. + +// This test, as well as `check-function-visibility.swift` +// checks that the `getFortyTwo()` decl can be found when at least one of the +// modules is not `@_implementationOnly`. + +import UserA +@_implementationOnly import UserB + +@_inlineable +public func callFortyTwo() -> CInt { + return getFortyTwo() +} diff --git a/test/Interop/Cxx/implementation-only-imports/check-function-visibility.swift b/test/Interop/Cxx/implementation-only-imports/check-function-visibility.swift new file mode 100644 index 0000000000000..2b3d6989851d0 --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/check-function-visibility.swift @@ -0,0 +1,17 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/FortyTwo.swiftmodule -I %S/Inputs -enable-cxx-interop %s + +// Swift should consider all sources for a decl and recognize that the +// decl is not hidden behind @_implementationOnly in all modules. + +// This test, as well as `check-function-visibility-inversed.swift` +// checks that the `getFortyTwo()` decl can be found when at least one of the +// modules is not `@_implementationOnly`. + +@_implementationOnly import UserA +import UserB + +@_inlineable +public func callFortyTwo() -> CInt { + return getFortyTwo() +} diff --git a/test/Interop/Cxx/implementation-only-imports/check-operator-visibility-inversed.swift b/test/Interop/Cxx/implementation-only-imports/check-operator-visibility-inversed.swift new file mode 100644 index 0000000000000..bec834521a146 --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/check-operator-visibility-inversed.swift @@ -0,0 +1,29 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/FortyTwo.swiftmodule -I %S/Inputs %s -enable-cxx-interop + +// Swift should consider all sources for a decl and recognize that the +// decl is not hidden behind @_implementationOnly in all modules. + +// This test, as well as `check-operator-visibility.swift` checks +// that the operator decl can be found when at least one of the +// modules is not `@_implementationOnly`. + + +import UserA +@_implementationOnly import UserB + +// Operator `+` is a non-member function. +@_inlineable +public func addWrappers() { + let wrapperA = MagicWrapper() + let wrapperB = MagicWrapper() + let _ = wrapperA + wrapperB +} + +// Operator `-` is a member function. +@_inlineable +public func subtractWrappers() { + var wrapperA = MagicWrapper() + let wrapperB = MagicWrapper() + let _ = wrapperA - wrapperB +} diff --git a/test/Interop/Cxx/implementation-only-imports/check-operator-visibility.swift b/test/Interop/Cxx/implementation-only-imports/check-operator-visibility.swift new file mode 100644 index 0000000000000..40ea146ce442e --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/check-operator-visibility.swift @@ -0,0 +1,28 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/FortyTwo.swiftmodule -I %S/Inputs %s -enable-cxx-interop + +// Swift should consider all sources for a decl and recognize that the +// decl is not hidden behind @_implementationOnly in all modules. + +// This test, as well as `check-operator-visibility-inversed.swift` checks +// that the operator decl can be found when at least one of the +// modules is not `@_implementationOnly`. + +@_implementationOnly import UserA +import UserB + +// Operator `+` is a non-member function. +@_inlineable +public func addWrappers() { + let wrapperA = MagicWrapper() + let wrapperB = MagicWrapper() + let _ = wrapperA + wrapperB +} + +// Operator `-` is a member function. +@_inlineable +public func subtractWrappers() { + var wrapperA = MagicWrapper() + let wrapperB = MagicWrapper() + let _ = wrapperA - wrapperB +} diff --git a/test/Interop/Cxx/implementation-only-imports/skip-forward-declarations.swift b/test/Interop/Cxx/implementation-only-imports/skip-forward-declarations.swift new file mode 100644 index 0000000000000..5655581e3df2c --- /dev/null +++ b/test/Interop/Cxx/implementation-only-imports/skip-forward-declarations.swift @@ -0,0 +1,15 @@ +// RUN: %empty-directory(%t) +// RUN: not %target-swift-frontend -emit-module -o %t/FortyTwo.swiftmodule -I %S/Inputs -enable-cxx-interop %s 2>&1 | %FileCheck %s + +// This test checks that forward declarations are not considered +// when determining the visibility of the decl. + +@_implementationOnly import UserA +import UserC + +@_inlineable +public func createAWrapper() { + let _ = MagicWrapper() +} + +// CHECK: struct 'MagicWrapper' cannot be used in an '@inlinable' function because 'UserA' was imported implementation-only