Merge pull request #23835 from devincoughlin/blocks-runtime-stubs-variant-suffix
[CMake] Change tests BlocksRuntimeStub to use VARIANT_SUFFIX
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 89315e0..bb34f25 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -4099,6 +4099,11 @@
"should not be referenced from " FRAGILE_FUNC_KIND "3",
(DescriptiveDeclKind, DeclName, AccessLevel, unsigned, bool))
+ERROR(inlinable_decl_ref_implementation_only,
+ none, "%0 %1 cannot be used in an inlinable "
+ "function because its module was imported implementation-only",
+ (DescriptiveDeclKind, DeclName))
+
#undef FRAGILE_FUNC_KIND
NOTE(resilience_decl_declared_here_public,
diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h
index 35a96b8..1a79036 100644
--- a/include/swift/AST/Module.h
+++ b/include/swift/AST/Module.h
@@ -959,6 +959,10 @@
/// May be -1, to indicate no association with a buffer.
int BufferID;
+ /// Does this source file have any implementation-only imports?
+ /// If not, we can fast-path module checks.
+ bool HasImplementationOnlyImports = false;
+
/// The list of protocol conformances that were "used" within this
/// source file.
llvm::SetVector<NormalProtocolConformance *> UsedConformances;
@@ -1047,6 +1051,12 @@
hasTestableOrPrivateImport(AccessLevel accessLevel, const ValueDecl *ofDecl,
ImportQueryKind kind = TestableAndPrivate) const;
+ bool hasImplementationOnlyImports() const {
+ return HasImplementationOnlyImports;
+ }
+
+ bool isImportedImplementationOnly(const ModuleDecl *module) const;
+
void clearLookupCache();
void cacheVisibleDecls(SmallVectorImpl<ValueDecl *> &&globals) const;
diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp
index 2012e41..7b4d782 100644
--- a/lib/AST/Module.cpp
+++ b/lib/AST/Module.cpp
@@ -1421,6 +1421,14 @@
assert(iter == newBuf.end());
Imports = newBuf;
+
+ // Update the HasImplementationOnlyImports flag.
+ if (!HasImplementationOnlyImports) {
+ for (auto &desc : IM) {
+ if (desc.importOptions.contains(ImportFlags::ImplementationOnly))
+ HasImplementationOnlyImports = true;
+ }
+ }
}
bool SourceFile::hasTestableOrPrivateImport(
@@ -1485,6 +1493,43 @@
});
}
+bool SourceFile::isImportedImplementationOnly(const ModuleDecl *module) const {
+ // Implementation-only imports are (currently) always source-file-specific,
+ // so if we don't have any, we know the search is complete.
+ if (!hasImplementationOnlyImports())
+ return false;
+
+ auto isImportedBy = [](const ModuleDecl *dest, const ModuleDecl *src) {
+ // Fast path.
+ if (dest == src) return true;
+
+ // Walk the transitive imports, respecting visibility.
+ // This return true if the search *didn't* short-circuit, and it short
+ // circuits if we found `dest`, so we need to invert the sense before
+ // returning.
+ return !const_cast<ModuleDecl*>(src)
+ ->forAllVisibleModules({}, [dest](ModuleDecl::ImportedModule im) {
+ // Continue searching as long as we haven't found `dest` yet.
+ return im.second != dest;
+ });
+ };
+
+ // Look at the imports of this source file.
+ for (auto &desc : Imports) {
+ // Ignore implementation-only imports.
+ if (desc.importOptions.contains(ImportFlags::ImplementationOnly))
+ continue;
+
+ // If the module is imported this way, it's not imported
+ // implementation-only.
+ if (isImportedBy(module, desc.module.second))
+ return false;
+ }
+
+ // Now check this file's enclosing module in case there are re-exports.
+ return !isImportedBy(module, getParentModule());
+}
+
void SourceFile::clearLookupCache() {
if (!Cache)
return;
diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp
index d87a8fa..10bc318 100644
--- a/lib/Sema/ResilienceDiagnostics.cpp
+++ b/lib/Sema/ResilienceDiagnostics.cpp
@@ -102,6 +102,8 @@
const DeclContext *DC,
FragileFunctionKind Kind,
bool TreatUsableFromInlineAsPublic) {
+ // Do some important fast-path checks that apply to all cases.
+
// Local declarations are OK.
if (D->getDeclContext()->isLocalContext())
return false;
@@ -110,6 +112,23 @@
if (isa<AbstractTypeParamDecl>(D))
return false;
+ // Check whether the declaration is accessible.
+ if (diagnoseInlinableDeclRefAccess(loc, D, DC, Kind,
+ TreatUsableFromInlineAsPublic))
+ return true;
+
+ // Check whether the declaration comes from a publically-imported module.
+ if (diagnoseDeclRefExportability(loc, D, DC))
+ return true;
+
+ return false;
+}
+
+bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
+ const ValueDecl *D,
+ const DeclContext *DC,
+ FragileFunctionKind Kind,
+ bool TreatUsableFromInlineAsPublic) {
// Public declarations are OK.
if (D->getFormalAccessScope(/*useDC=*/nullptr,
TreatUsableFromInlineAsPublic).isPublic())
@@ -178,3 +197,38 @@
return (downgradeToWarning == DowngradeToWarning::No);
}
+bool TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
+ const ValueDecl *D,
+ const DeclContext *DC) {
+ // We're only interested in diagnosing uses from source files.
+ auto userSF = DC->getParentSourceFile();
+ if (!userSF)
+ return false;
+
+ // If the source file doesn't have any implementation-only imports,
+ // we can fast-path this. In the current language design, we never
+ // need to consider the possibility of implementation-only imports
+ // from other source files in the module (or indirectly in other modules).
+ // TODO: maybe check whether D is from a bridging header?
+ if (!userSF->hasImplementationOnlyImports())
+ return false;
+
+ auto userModule = userSF->getParentModule();
+ auto definingModule = D->getModuleContext();
+
+ // Nothing to diagnose in the very common case of the same module.
+ if (userModule == definingModule)
+ return false;
+
+ // Nothing to diagnose in the very common case that the module is
+ // imported for use in signatures.
+ if (!userSF->isImportedImplementationOnly(definingModule))
+ return false;
+
+ // TODO: different diagnostics
+ diagnose(loc, diag::inlinable_decl_ref_implementation_only,
+ D->getDescriptiveKind(), D->getFullName());
+
+ // TODO: notes explaining why
+ return true;
+}
diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h
index 9d9a433..7aabd5d 100644
--- a/lib/Sema/TypeChecker.h
+++ b/lib/Sema/TypeChecker.h
@@ -1933,6 +1933,19 @@
FragileFunctionKind Kind,
bool TreatUsableFromInlineAsPublic);
+private:
+ bool diagnoseInlinableDeclRefAccess(SourceLoc loc, const ValueDecl *D,
+ const DeclContext *DC,
+ FragileFunctionKind Kind,
+ bool TreatUsableFromInlineAsPublic);
+
+public:
+ /// Given that a declaration is used from a particular context which
+ /// exposes it in the interface of the current module, diagnose if it cannot
+ /// reasonably be shared.
+ bool diagnoseDeclRefExportability(SourceLoc loc, const ValueDecl *D,
+ const DeclContext *DC);
+
/// Given that \p DC is within a fragile context for some reason, describe
/// why.
///
diff --git a/test/Sema/Inputs/implementation-only-imports/directs.swift b/test/Sema/Inputs/implementation-only-imports/directs.swift
new file mode 100644
index 0000000..4053dce
--- /dev/null
+++ b/test/Sema/Inputs/implementation-only-imports/directs.swift
@@ -0,0 +1,30 @@
+@_exported import indirects
+
+public struct StructFromDirect {
+ public func method() {}
+ public var property: Int {
+ get { return 0 }
+ set {}
+ }
+ public subscript(index: Int) -> Int {
+ get { return 0 }
+ set {}
+ }
+}
+public typealias AliasFromDirect = StructFromDirect
+public typealias GenericAliasFromDirect<T> = (StructFromDirect, T)
+
+public func globalFunctionFromDirect() {}
+public var globalVariableFromDirect = 0
+
+extension StructFromIndirect {
+ public func extensionMethodFromDirect() {}
+ public var extensionPropertyFromDirect: Int {
+ get { return 0 }
+ set {}
+ }
+ public subscript(extensionSubscript index: Int) -> Int {
+ get { return 0 }
+ set {}
+ }
+}
diff --git a/test/Sema/Inputs/implementation-only-imports/indirects.swift b/test/Sema/Inputs/implementation-only-imports/indirects.swift
new file mode 100644
index 0000000..08becd2
--- /dev/null
+++ b/test/Sema/Inputs/implementation-only-imports/indirects.swift
@@ -0,0 +1,8 @@
+public struct StructFromIndirect {
+ public init() {}
+}
+public typealias AliasFromIndirect = StructFromIndirect
+public typealias GenericAliasFromIndirect<T> = (StructFromIndirect, T)
+
+public func globalFunctionFromIndirect() {}
+public var globalVariableFromIndirect = 0
diff --git a/test/Sema/Inputs/implementation-only-imports/secondary_file.swift b/test/Sema/Inputs/implementation-only-imports/secondary_file.swift
new file mode 100644
index 0000000..1827822
--- /dev/null
+++ b/test/Sema/Inputs/implementation-only-imports/secondary_file.swift
@@ -0,0 +1 @@
+@_exported import indirects
diff --git a/test/Sema/implementation-only-import-inlinable-indirect.swift b/test/Sema/implementation-only-import-inlinable-indirect.swift
new file mode 100644
index 0000000..c577ea9
--- /dev/null
+++ b/test/Sema/implementation-only-import-inlinable-indirect.swift
@@ -0,0 +1,43 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -o %t/indirects.swiftmodule %S/Inputs/implementation-only-imports/indirects.swift
+// RUN: %target-swift-frontend -emit-module -o %t/directs.swiftmodule -I %t %S/Inputs/implementation-only-imports/directs.swift
+
+// RUN: %target-swift-frontend -typecheck -verify %s -I %t
+
+@_implementationOnly import directs
+
+// Types
+
+@inlinable
+public func testStructFromIndirect() {
+ _ = StructFromIndirect() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testAliasFromIndirect() {
+ _ = AliasFromIndirect() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testGenericAliasFromIndirect() {
+ _ = GenericAliasFromIndirect<Int>() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+// Functions
+
+@inlinable
+public func testFunctionFromIndirect() {
+ globalFunctionFromIndirect() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+// Variables
+
+@inlinable
+public func testVariableFromIndirect_get() {
+ _ = globalVariableFromIndirect // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testVariableFromIndirect_set() {
+ globalVariableFromIndirect = 5 // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
diff --git a/test/Sema/implementation-only-import-inlinable-multifile.swift b/test/Sema/implementation-only-import-inlinable-multifile.swift
new file mode 100644
index 0000000..53bc5ff
--- /dev/null
+++ b/test/Sema/implementation-only-import-inlinable-multifile.swift
@@ -0,0 +1,104 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -o %t/indirects.swiftmodule %S/Inputs/implementation-only-imports/indirects.swift
+// RUN: %target-swift-frontend -emit-module -o %t/directs.swiftmodule -I %t %S/Inputs/implementation-only-imports/directs.swift
+
+// RUN: %target-swift-frontend -typecheck -verify -primary-file %s %S/Inputs/implementation-only-imports/secondary_file.swift -I %t
+
+@_implementationOnly import directs
+// 'indirects' is imported for re-export in a secondary file
+
+// Types
+
+@inlinable
+public func testStructFromDirect() {
+ _ = StructFromDirect() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testStructFromIndirect() {
+ _ = StructFromIndirect()
+}
+
+@inlinable
+public func testAliasFromDirect() {
+ _ = AliasFromDirect() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testAliasFromIndirect() {
+ _ = AliasFromIndirect()
+}
+
+@inlinable
+public func testGenericAliasFromDirect() {
+ _ = GenericAliasFromDirect<Int>() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testGenericAliasFromIndirect() {
+ let tmp: GenericAliasFromIndirect<Int>?
+ _ = tmp
+}
+
+// Functions
+
+@inlinable
+public func testFunctionFromDirect() {
+ globalFunctionFromDirect() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testFunctionFromIndirect() {
+ globalFunctionFromIndirect()
+}
+
+// Variables
+
+@inlinable
+public func testVariableFromDirect_get() {
+ _ = globalVariableFromDirect // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testVariableFromIndirect_get() {
+ _ = globalVariableFromIndirect
+}
+
+@inlinable
+public func testVariableFromDirect_set() {
+ globalVariableFromDirect = 5 // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testVariableFromIndirect_set() {
+ globalVariableFromIndirect = 5
+}
+
+// Extensions
+
+@inlinable
+public func testExtensionMethod(s: inout StructFromIndirect) {
+ s.extensionMethodFromDirect() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testExtensionProperty_get(s: inout StructFromIndirect) {
+ _ = s.extensionPropertyFromDirect // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testExtensionProperty_set(s: inout StructFromIndirect) {
+ s.extensionPropertyFromDirect = 5 // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testExtensionSubscript_get(s: inout StructFromIndirect) {
+ // FIXME: why is this error being double-emitted?
+ _ = s[extensionSubscript: 0] // expected-error 2 {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testExtensionSubscript_set(s: inout StructFromIndirect) {
+ // FIXME: why is this error being double-emitted?
+ s[extensionSubscript: 0] = 5 // expected-error 2 {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
diff --git a/test/Sema/implementation-only-import-inlinable.swift b/test/Sema/implementation-only-import-inlinable.swift
new file mode 100644
index 0000000..e843caf
--- /dev/null
+++ b/test/Sema/implementation-only-import-inlinable.swift
@@ -0,0 +1,104 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -o %t/indirects.swiftmodule %S/Inputs/implementation-only-imports/indirects.swift
+// RUN: %target-swift-frontend -emit-module -o %t/directs.swiftmodule -I %t %S/Inputs/implementation-only-imports/directs.swift
+
+// RUN: %target-swift-frontend -typecheck -verify %s -I %t
+
+@_implementationOnly import directs
+import indirects
+
+// Types
+
+@inlinable
+public func testStructFromDirect() {
+ _ = StructFromDirect() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testStructFromIndirect() {
+ _ = StructFromIndirect()
+}
+
+@inlinable
+public func testAliasFromDirect() {
+ _ = AliasFromDirect() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testAliasFromIndirect() {
+ _ = AliasFromIndirect()
+}
+
+@inlinable
+public func testGenericAliasFromDirect() {
+ _ = GenericAliasFromDirect<Int>() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testGenericAliasFromIndirect() {
+ let tmp: GenericAliasFromIndirect<Int>?
+ _ = tmp
+}
+
+// Functions
+
+@inlinable
+public func testFunctionFromDirect() {
+ globalFunctionFromDirect() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testFunctionFromIndirect() {
+ globalFunctionFromIndirect()
+}
+
+// Variables
+
+@inlinable
+public func testVariableFromDirect_get() {
+ _ = globalVariableFromDirect // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testVariableFromIndirect_get() {
+ _ = globalVariableFromIndirect
+}
+
+@inlinable
+public func testVariableFromDirect_set() {
+ globalVariableFromDirect = 5 // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testVariableFromIndirect_set() {
+ globalVariableFromIndirect = 5
+}
+
+// Extensions
+
+@inlinable
+public func testExtensionMethod(s: inout StructFromIndirect) {
+ s.extensionMethodFromDirect() // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testExtensionProperty_get(s: inout StructFromIndirect) {
+ _ = s.extensionPropertyFromDirect // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testExtensionProperty_set(s: inout StructFromIndirect) {
+ s.extensionPropertyFromDirect = 5 // expected-error {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testExtensionSubscript_get(s: inout StructFromIndirect) {
+ // FIXME: why is this error being double-emitted?
+ _ = s[extensionSubscript: 0] // expected-error 2 {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}
+
+@inlinable
+public func testExtensionSubscript_set(s: inout StructFromIndirect) {
+ // FIXME: why is this error being double-emitted?
+ s[extensionSubscript: 0] = 5 // expected-error 2 {{cannot be used in an inlinable function because its module was imported implementation-only}}
+}