mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Sema: Embedded can reference non-publicly imported conformances
rdar://163965839
This commit is contained in:
@@ -442,7 +442,7 @@ TypeChecker::diagnoseConformanceExportability(SourceLoc loc,
|
||||
});
|
||||
|
||||
auto originKind = getDisallowedOriginKind(ext, where);
|
||||
if (originKind == DisallowedOriginKind::None)
|
||||
if (where.canReferenceOrigin(originKind))
|
||||
return false;
|
||||
|
||||
auto reason = where.getExportabilityReason();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "TypeCheckAvailability.h"
|
||||
#include "MiscDiagnostics.h"
|
||||
#include "TypeCheckAccess.h"
|
||||
#include "TypeCheckConcurrency.h"
|
||||
#include "TypeCheckObjC.h"
|
||||
#include "TypeCheckType.h"
|
||||
@@ -234,6 +235,20 @@ bool ExportContext::mustOnlyReferenceExportedDecls() const {
|
||||
return Exported || FragileKind.kind != FragileFunctionKind::None;
|
||||
}
|
||||
|
||||
bool ExportContext::canReferenceOrigin(DisallowedOriginKind originKind) const {
|
||||
if (originKind == DisallowedOriginKind::None)
|
||||
return true;
|
||||
|
||||
// Non public imports aren't hidden dependencies in embedded mode,
|
||||
// don't enforce them on implicitly always emit into client code.
|
||||
if (originKind == DisallowedOriginKind::NonPublicImport &&
|
||||
getFragileFunctionKind().kind ==
|
||||
FragileFunctionKind::EmbeddedAlwaysEmitIntoClient)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<ExportabilityReason>
|
||||
ExportContext::getExportabilityReason() const {
|
||||
if (Exported)
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace swift {
|
||||
class TypeRepr;
|
||||
class UnsafeUse;
|
||||
class ValueDecl;
|
||||
enum class DisallowedOriginKind : uint8_t;
|
||||
|
||||
enum class DeclAvailabilityFlag : uint8_t {
|
||||
/// Do not diagnose uses of protocols in versions before they were introduced.
|
||||
@@ -192,6 +193,10 @@ public:
|
||||
/// because it is the function body context of an inlinable function.
|
||||
bool mustOnlyReferenceExportedDecls() const;
|
||||
|
||||
/// If true, the context reference a dependency of \p originKind without
|
||||
/// restriction.
|
||||
bool canReferenceOrigin(DisallowedOriginKind originKind) const;
|
||||
|
||||
/// Get the ExportabilityReason for diagnostics. If this is 'None', there
|
||||
/// are no restrictions on referencing unexported declarations.
|
||||
std::optional<ExportabilityReason> getExportabilityReason() const;
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/NormalLibrary.swiftmodule \
|
||||
// RUN: %S/Inputs/implementation-only-import-in-decls-public-helper.swift \
|
||||
// RUN: -swift-version 5 -target arm64-apple-none-macho \
|
||||
// RUN: -enable-experimental-feature Embedded
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/BADLibrary.swiftmodule \
|
||||
// RUN: %S/Inputs/implementation-only-import-in-decls-helper.swift -I %t \
|
||||
// RUN: -swift-version 5 -target arm64-apple-none-macho \
|
||||
// RUN: -enable-experimental-feature Embedded
|
||||
|
||||
/// Access-level on imports allow references from implicitly inlinable code.
|
||||
// RUN: %target-typecheck-verify-swift -I %t \
|
||||
// RUN: -swift-version 5 -target arm64-apple-none-macho \
|
||||
// RUN: -enable-experimental-feature Embedded \
|
||||
// RUN: -verify-additional-prefix access-level-
|
||||
|
||||
/// @_implementationOnly rejects references from implicitly inlinable code.
|
||||
// RUN: %target-typecheck-verify-swift -I %t \
|
||||
// RUN: -swift-version 5 -target arm64-apple-none-macho \
|
||||
// RUN: -enable-experimental-feature Embedded \
|
||||
// RUN: -D IOI -verify-additional-prefix ioi-
|
||||
|
||||
// REQUIRES: swift_feature_Embedded
|
||||
// REQUIRES: embedded_stdlib_cross_compiling
|
||||
|
||||
#if IOI
|
||||
@_implementationOnly import BADLibrary // expected-ioi-warning {{using '@_implementationOnly' without enabling library evolution for 'main' may lead to instability during execution}}
|
||||
#else
|
||||
internal import BADLibrary // expected-access-level-note 35 {{imported as 'internal' from 'BADLibrary' here}}
|
||||
#endif
|
||||
import NormalLibrary
|
||||
|
||||
public typealias NormalProtoAssoc<T: NormalProto> = T.Assoc
|
||||
@inlinable func testConformanceInTypealias() {
|
||||
let x: NormalProtoAssoc<NormalStruct>? = nil // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
_ = x
|
||||
_ = NormalProtoAssoc<NormalStruct>() // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
}
|
||||
|
||||
func internalConformanceInTypealias() {
|
||||
let x: NormalProtoAssoc<NormalStruct>? = nil // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}}
|
||||
_ = x
|
||||
_ = NormalProtoAssoc<NormalStruct>() // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}}
|
||||
}
|
||||
|
||||
@_neverEmitIntoClient
|
||||
func internalConformanceInTypealiasNEIC() {
|
||||
let x: NormalProtoAssoc<NormalStruct>? = nil // okay
|
||||
_ = x
|
||||
_ = NormalProtoAssoc<NormalStruct>() // okay
|
||||
}
|
||||
|
||||
public struct NormalProtoAssocHolder<T: NormalProto> {
|
||||
public var value: T.Assoc?
|
||||
public init() {}
|
||||
public init(_ value: T?) {}
|
||||
}
|
||||
@inlinable func testConformanceInBoundGeneric() {
|
||||
let x: NormalProtoAssocHolder<NormalStruct>? = nil // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
_ = x
|
||||
// FIXME: We get this error twice: once for the TypeExpr and once for the implicit init.
|
||||
_ = NormalProtoAssocHolder<NormalStruct>() // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
_ = NormalProtoAssocHolder(nil as NormalStruct?) // expected-error 2{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
}
|
||||
|
||||
func internalConformanceInBoundGeneric() {
|
||||
let x: NormalProtoAssocHolder<NormalStruct>? = nil // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}}
|
||||
_ = x
|
||||
_ = NormalProtoAssocHolder<NormalStruct>() // expected-ioi-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}}
|
||||
_ = NormalProtoAssocHolder(nil as NormalStruct?) // expected-ioi-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}}
|
||||
}
|
||||
|
||||
@_neverEmitIntoClient
|
||||
func internalConformanceInBoundGenericNEIC() {
|
||||
let x: NormalProtoAssocHolder<NormalStruct>? = nil // okay
|
||||
_ = x
|
||||
_ = NormalProtoAssocHolder<NormalStruct>() // okay
|
||||
_ = NormalProtoAssocHolder(nil as NormalStruct?) // okay
|
||||
}
|
||||
|
||||
@inlinable func testDowncast(_ x: Any) -> Bool {
|
||||
let normal = x is NormalProtoAssocHolder<NormalStruct> // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
let alias = x is NormalProtoAssoc<NormalStruct> // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
return normal || alias
|
||||
}
|
||||
|
||||
func internalDowncast(_ x: Any) -> Bool {
|
||||
let normal = x is NormalProtoAssocHolder<NormalStruct> // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
|
||||
let alias = x is NormalProtoAssoc<NormalStruct> // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
|
||||
return normal || alias
|
||||
}
|
||||
|
||||
@_neverEmitIntoClient
|
||||
func internalDowncastNEIC(_ x: Any) -> Bool {
|
||||
let normal = x is NormalProtoAssocHolder<NormalStruct> // okay
|
||||
let alias = x is NormalProtoAssoc<NormalStruct> // okay
|
||||
return normal || alias
|
||||
}
|
||||
|
||||
@inlinable func testSwitch(_ x: Any) {
|
||||
switch x {
|
||||
case let holder as NormalProtoAssocHolder<NormalStruct>: // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
_ = holder
|
||||
break
|
||||
case is NormalProtoAssoc<NormalStruct>: // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func internalSwitch(_ x: Any) {
|
||||
switch x {
|
||||
case let holder as NormalProtoAssocHolder<NormalStruct>: // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
|
||||
_ = holder
|
||||
break
|
||||
case is NormalProtoAssoc<NormalStruct>: // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@_neverEmitIntoClient
|
||||
func internalSwitchNEIC(_ x: Any) {
|
||||
switch x {
|
||||
case let holder as NormalProtoAssocHolder<NormalStruct>: // okay
|
||||
_ = holder
|
||||
break
|
||||
case is NormalProtoAssoc<NormalStruct>: // okay
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public enum NormalProtoEnumUser<T: NormalProto> {
|
||||
case a
|
||||
}
|
||||
|
||||
@inlinable func testEnum() {
|
||||
// FIXME: We get this error twice: once for the pattern and once for the implicit TypeExpr.
|
||||
let x: NormalProtoEnumUser<NormalStruct> = .a // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
_ = x
|
||||
// FIXME: We get this error twice: once for the TypeExpr and once for the case.
|
||||
_ = NormalProtoEnumUser<NormalStruct>.a // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
}
|
||||
|
||||
func internalEnum() {
|
||||
let x: NormalProtoEnumUser<NormalStruct> = .a // expected-ioi-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
|
||||
_ = x
|
||||
_ = NormalProtoEnumUser<NormalStruct>.a // expected-ioi-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
|
||||
}
|
||||
|
||||
@_neverEmitIntoClient
|
||||
func internalEnumNEIC() {
|
||||
let x: NormalProtoEnumUser<NormalStruct> = .a // okay
|
||||
_ = x
|
||||
_ = NormalProtoEnumUser<NormalStruct>.a // okay
|
||||
}
|
||||
|
||||
@usableFromInline func testFuncImpl<T: NormalProto>(_: T.Type) {}
|
||||
|
||||
@inlinable func testFunc() {
|
||||
testFuncImpl(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
}
|
||||
|
||||
func internalFunc() {
|
||||
testFuncImpl(NormalStruct.self) // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
|
||||
}
|
||||
|
||||
@_neverEmitIntoClient
|
||||
func internalFuncNEIC() {
|
||||
testFuncImpl(NormalStruct.self) // okay
|
||||
}
|
||||
|
||||
public struct ForTestingMembers {
|
||||
public init() {}
|
||||
public init<T: NormalProto>(_: T.Type) {}
|
||||
|
||||
public subscript<T: NormalProto>(_: T.Type) -> Int {
|
||||
get { return 0 }
|
||||
set {}
|
||||
}
|
||||
|
||||
public func method<T: NormalProto>(_: T.Type) {}
|
||||
}
|
||||
|
||||
@inlinable func testMembers() {
|
||||
_ = ForTestingMembers(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
_ = ForTestingMembers.init(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
|
||||
_ = ForTestingMembers()[NormalStruct.self] // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
var instance = ForTestingMembers()
|
||||
instance[NormalStruct.self] = 1 // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
|
||||
ForTestingMembers().method(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
}
|
||||
|
||||
extension NormalProtoAssocHolder {
|
||||
public static func testAnotherConformance<U: NormalProto>(_: U.Type) {}
|
||||
}
|
||||
|
||||
@inlinable func testMultipleConformances() {
|
||||
NormalProtoAssocHolder<NormalStruct>.testAnotherConformance(NormalClass.self)
|
||||
// expected-error@-1 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
// expected-error@-2 {{cannot use conformance of 'NormalClass' to 'NormalProto' here; 'BADLibrary'}}
|
||||
}
|
||||
|
||||
@inlinable func localTypeAlias() {
|
||||
typealias LocalUser = NormalProtoAssocHolder<NormalStruct> // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
typealias LocalGenericUser<T> = (T, NormalProtoAssocHolder<NormalStruct>) // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
|
||||
typealias LocalProtoAssoc<T: NormalProto> = T.Assoc
|
||||
_ = LocalProtoAssoc<NormalStruct>() // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
}
|
||||
|
||||
@inlinable func localFunctions() {
|
||||
func local(_: NormalProtoAssocHolder<NormalStruct>) {} // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
func localReturn() -> NormalProtoAssocHolder<NormalStruct> { fatalError() } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
let _ = { (_: NormalProtoAssocHolder<NormalStruct>) in return } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
let _ = { () -> NormalProtoAssocHolder<NormalStruct> in fatalError() } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
}
|
||||
|
||||
@inlinable public func signatureOfInlinable(_: NormalProtoAssocHolder<NormalStruct>) {} // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
|
||||
public func testDefaultArgument(_: Int = NormalProtoAssoc<NormalStruct>()) {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
|
||||
|
||||
|
||||
public class SubclassOfNormalClass: NormalClass {}
|
||||
|
||||
@inlinable public func testInheritedConformance() {
|
||||
_ = NormalProtoAssocHolder<SubclassOfNormalClass>.self // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' here; 'BADLibrary'}}
|
||||
}
|
||||
@inlinable public func testSpecializedConformance() {
|
||||
_ = NormalProtoAssocHolder<GenericStruct<Int>>.self // expected-error {{cannot use conformance of 'GenericStruct<T>' to 'NormalProto' here; 'BADLibrary'}}
|
||||
}
|
||||
Reference in New Issue
Block a user