mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #77737 from xymus/restrict-spi-operators
Sema: Restrict use of SPI operators to files importing the corresponding SPI group
This commit is contained in:
@@ -561,6 +561,9 @@ EXPERIMENTAL_FEATURE(CheckImplementationOnly, true)
|
||||
/// report references to implementation-only imported modules.
|
||||
EXPERIMENTAL_FEATURE(CheckImplementationOnlyStrict, false)
|
||||
|
||||
/// Check that use sites have the required @_spi import for operators.
|
||||
EXPERIMENTAL_FEATURE(EnforceSPIOperatorGroup, true)
|
||||
|
||||
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
|
||||
#undef EXPERIMENTAL_FEATURE
|
||||
#undef UPCOMING_FEATURE
|
||||
|
||||
@@ -5536,9 +5536,19 @@ static bool checkAccess(const DeclContext *useDC, const ValueDecl *VD,
|
||||
return srcPkg && usePkg && usePkg->isSamePackageAs(srcPkg);
|
||||
}
|
||||
case AccessLevel::Public:
|
||||
case AccessLevel::Open:
|
||||
case AccessLevel::Open: {
|
||||
if (VD->getASTContext().LangOpts.hasFeature(
|
||||
Feature::EnforceSPIOperatorGroup) &&
|
||||
VD->isOperator() && VD->isSPI()) {
|
||||
const DeclContext *useFile = useDC->getModuleScopeContext();
|
||||
if (useFile->getParentModule() == sourceDC->getParentModule())
|
||||
return true;
|
||||
auto *useSF = dyn_cast<SourceFile>(useFile);
|
||||
return !useSF || useSF->isImportedAsSPI(VD);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
llvm_unreachable("bad access level");
|
||||
}
|
||||
|
||||
|
||||
@@ -146,6 +146,7 @@ UNINTERESTING_FEATURE(SameElementRequirements)
|
||||
UNINTERESTING_FEATURE(SendingArgsAndResults)
|
||||
UNINTERESTING_FEATURE(CheckImplementationOnly)
|
||||
UNINTERESTING_FEATURE(CheckImplementationOnlyStrict)
|
||||
UNINTERESTING_FEATURE(EnforceSPIOperatorGroup)
|
||||
|
||||
static bool findUnderscoredLifetimeAttr(Decl *decl) {
|
||||
auto hasUnderscoredLifetimeAttr = [](Decl *decl) {
|
||||
|
||||
@@ -4,6 +4,10 @@ public protocol PublicProto {
|
||||
associatedtype Assoc
|
||||
}
|
||||
|
||||
public struct PublicType {
|
||||
public init() { }
|
||||
}
|
||||
|
||||
public func publicFunc() { print("publicFunc") }
|
||||
|
||||
func internalFunc() {}
|
||||
@@ -94,3 +98,6 @@ public enum PublicEnum {
|
||||
case publicCase
|
||||
@_spi(HelperSPI) case spiCase
|
||||
}
|
||||
|
||||
@_spi(HelperSPI) public func -(_ s1: PublicType, _ s2: PublicType) -> PublicType { s1 }
|
||||
@_spi(HelperSPI) public func +(_ s1: PublicType, _ s2: PublicType) -> PublicType { s1 }
|
||||
|
||||
@@ -115,11 +115,20 @@ public func publicFuncWithDefaultValue(_ p: SPIClass = SPIClass()) {} // expecte
|
||||
@_spi(S)
|
||||
public func spiFuncWithDefaultValue(_ p: SPIClass = SPIClass()) {}
|
||||
|
||||
public struct PublicType {
|
||||
public init() { }
|
||||
}
|
||||
@_spi(S) public func -(_ s1: PublicType, _ s2: PublicType) -> PublicType { s1 }
|
||||
|
||||
public let o1 = PublicType()
|
||||
public let o2 = PublicType()
|
||||
|
||||
@inlinable
|
||||
public func inlinablePublic() {
|
||||
spiFunc() // expected-error {{global function 'spiFunc()' cannot be used in an '@inlinable' function because it is SPI}}
|
||||
let _ = SPIClass() // expected-error {{class 'SPIClass' cannot be used in an '@inlinable' function because it is SPI}}
|
||||
// expected-error@-1 {{initializer 'init()' cannot be used in an '@inlinable' function because it is SPI}}
|
||||
let _ = o1 - o2 // expected-error {{operator function '-' cannot be used in an '@inlinable' function because it is SPI}}
|
||||
}
|
||||
|
||||
@_spi(S)
|
||||
@@ -127,8 +136,11 @@ public func inlinablePublic() {
|
||||
public func inlinableSPI() {
|
||||
spiFunc()
|
||||
let _ = SPIClass()
|
||||
let _ = o1 - o2
|
||||
}
|
||||
|
||||
@_spi(S) func internalFunc() {} // expected-error {{internal global function cannot be declared '@_spi' because only public and open declarations can be '@_spi'}}
|
||||
|
||||
@_spi(S) package func packageFunc() {} // expected-error {{package global function cannot be declared '@_spi' because only public and open declarations can be '@_spi'}}
|
||||
|
||||
let _ = o1 - o2
|
||||
|
||||
@@ -29,16 +29,16 @@
|
||||
|
||||
/// Test the textual interfaces generated from this test.
|
||||
// RUN: %target-swift-frontend -typecheck %s -emit-module-interface-path %t/Main.swiftinterface -emit-private-module-interface-path %t/Main.private.swiftinterface -enable-library-evolution -swift-version 5 -I %t -module-name Main
|
||||
// RUN: %FileCheck -check-prefix=CHECK-PUBLIC %s < %t/Main.swiftinterface
|
||||
// RUN: %FileCheck -check-prefix=CHECK-PRIVATE %s < %t/Main.private.swiftinterface
|
||||
// RUN: cat %t/Main.swiftinterface | %FileCheck -check-prefix=CHECK-PUBLIC %s
|
||||
// RUN: cat %t/Main.private.swiftinterface | %FileCheck -check-prefix=CHECK-PRIVATE %s
|
||||
// RUN: %target-swift-frontend -typecheck-module-from-interface -I %t %t/Main.swiftinterface
|
||||
// RUN: %target-swift-frontend -typecheck-module-from-interface -I %t %t/Main.private.swiftinterface -module-name Main
|
||||
|
||||
/// Both the public and private textual interfaces should have
|
||||
/// SPI information with `-library-level spi`.
|
||||
// RUN: %target-swift-frontend -typecheck %s -emit-module-interface-path %t/SPIModule.swiftinterface -emit-private-module-interface-path %t/SPIModule.private.swiftinterface -enable-library-evolution -swift-version 5 -I %t -module-name SPIModule -library-level spi
|
||||
// RUN: %FileCheck -check-prefix=CHECK-PRIVATE %s < %t/SPIModule.swiftinterface
|
||||
// RUN: %FileCheck -check-prefix=CHECK-PRIVATE %s < %t/SPIModule.private.swiftinterface
|
||||
// RUN: cat %t/SPIModule.swiftinterface | %FileCheck -check-prefix=CHECK-PRIVATE %s
|
||||
// RUN: cat %t/SPIModule.private.swiftinterface | %FileCheck -check-prefix=CHECK-PRIVATE %s
|
||||
// RUN: %target-swift-frontend -typecheck-module-from-interface -I %t %t/SPIModule.swiftinterface
|
||||
// RUN: %target-swift-frontend -typecheck-module-from-interface -I %t %t/SPIModule.private.swiftinterface -module-name SPIModule
|
||||
|
||||
@@ -238,6 +238,11 @@ extension IOIPublicStruct : LocalPublicProto {}
|
||||
// CHECK-PRIVATE: @_spi(S) private var spiTypeInFrozen1
|
||||
}
|
||||
|
||||
public struct OpType {}
|
||||
@_spi(S) public func +(_ s1: OpType, _ s2: OpType) -> OpType { s1 }
|
||||
// CHECK-PRIVATE: @_spi(S) public func + (s1: {{.*}}.OpType, s2: {{.*}}.OpType) -> {{.*}}.OpType
|
||||
// CHECK-PUBLIC-NOT: func +
|
||||
|
||||
// The dummy conformance should be only in the private swiftinterface for
|
||||
// SPI extensions.
|
||||
@_spi(LocalSPI)
|
||||
|
||||
@@ -6,17 +6,21 @@
|
||||
// RUN: %target-swift-frontend -emit-module %S/Inputs/spi_helper.swift -module-name SPIHelper -emit-module-path %t/SPIHelper.swiftmodule -emit-module-interface-path %t/SPIHelper.swiftinterface -emit-private-module-interface-path %t/SPIHelper.private.swiftinterface -enable-library-evolution -swift-version 5 -parse-as-library
|
||||
|
||||
/// Reading from swiftmodule
|
||||
// RUN: %target-typecheck-verify-swift -verify-ignore-unrelated -I %t -verify-ignore-unknown
|
||||
// RUN: %target-typecheck-verify-swift -verify-ignore-unrelated -I %t -verify-ignore-unknown \
|
||||
// RUN: -enable-experimental-feature EnforceSPIOperatorGroup
|
||||
|
||||
/// Reading from .private.swiftinterface
|
||||
// RUN: rm %t/SPIHelper.swiftmodule
|
||||
// RUN: %target-typecheck-verify-swift -verify-ignore-unrelated -I %t -verify-ignore-unknown
|
||||
// RUN: %target-typecheck-verify-swift -verify-ignore-unrelated -I %t -verify-ignore-unknown \
|
||||
// RUN: -enable-experimental-feature EnforceSPIOperatorGroup
|
||||
|
||||
/// Reading from the public .swiftinterface should raise errors on missing
|
||||
/// declarations.
|
||||
// RUN: rm %t/SPIHelper.private.swiftinterface
|
||||
// RUN: not %target-swift-frontend -typecheck -I %t %s
|
||||
|
||||
// REQUIRES: swift_feature_EnforceSPIOperatorGroup
|
||||
|
||||
import SPIHelper
|
||||
|
||||
// Use the public API
|
||||
@@ -40,8 +44,14 @@ otherApiFunc() // expected-error {{cannot find 'otherApiFunc' in scope}}
|
||||
public func publicUseOfSPI(param: SPIClass) -> SPIClass {} // expected-error 2{{cannot find type 'SPIClass' in scope}}
|
||||
public func publicUseOfSPI2() -> [SPIClass] {} // expected-error {{cannot find type 'SPIClass' in scope}}
|
||||
|
||||
public let o1 = PublicType()
|
||||
public let o2 = PublicType()
|
||||
|
||||
@inlinable
|
||||
func inlinable() -> SPIClass { // expected-error {{cannot find type 'SPIClass' in scope}}
|
||||
public func inlinable() -> SPIClass { // expected-error {{cannot find type 'SPIClass' in scope}}
|
||||
spiFunc() // expected-error {{cannot find 'spiFunc' in scope}}
|
||||
_ = SPIClass() // expected-error {{cannot find 'SPIClass' in scope}}
|
||||
let _ = o1 - o2 // expected-error {{binary operator '-' cannot be applied to two 'PublicType' operands}}
|
||||
}
|
||||
|
||||
let _ = o1 - o2 // expected-error {{binary operator '-' cannot be applied to two 'PublicType' operands}}
|
||||
|
||||
@@ -61,10 +61,16 @@ public func inlinable1() -> SPIClass { // expected-error {{class 'SPIClass' cann
|
||||
_ = [SPIClass]() // expected-error {{class 'SPIClass' cannot be used in an '@inlinable' function because it is an SPI imported from 'SPIHelper'}}
|
||||
}
|
||||
|
||||
public let o1 = PublicType()
|
||||
public let o2 = PublicType()
|
||||
|
||||
@_spi(S)
|
||||
@inlinable
|
||||
public func inlinable2() -> SPIClass {
|
||||
spiFunc()
|
||||
_ = SPIClass()
|
||||
_ = [SPIClass]()
|
||||
let _ = o1 - o2
|
||||
}
|
||||
|
||||
let _ = o1 - o2
|
||||
|
||||
Reference in New Issue
Block a user