mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Sema: Diagnose @backDeployed functions with missing bodies in swiftinterfaces.
A `@backDeployed` function printed in a `.swiftinterface` must have a function body so that SILGen can emit a fallback copy to call when the back deployed function is unavailable. Previously, the compiler would crash in SILGen when compiling an interface containing a back deployed function without a body. Resolves rdar://141593108.
This commit is contained in:
@@ -7567,13 +7567,17 @@ ERROR(cannot_convert_default_value_type_to_argument_type, none,
|
||||
// MARK: Back deployment
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ERROR(attr_incompatible_with_back_deploy,none,
|
||||
"'%0' cannot be applied to a back deployed %1",
|
||||
(DeclAttribute, DescriptiveDeclKind))
|
||||
ERROR(attr_incompatible_with_back_deployed,none,
|
||||
"'%0' cannot be applied to a back deployed %kind1",
|
||||
(DeclAttribute, const Decl *))
|
||||
|
||||
WARNING(backdeployed_opaque_result_not_supported,none,
|
||||
"'%0' is unsupported on a %1 with a 'some' return type",
|
||||
(DeclAttribute, DescriptiveDeclKind))
|
||||
WARNING(back_deployed_opaque_result_not_supported,none,
|
||||
"'%0' cannot be applied to %kind1 because it has a 'some' return type",
|
||||
(DeclAttribute, const ValueDecl *))
|
||||
|
||||
ERROR(back_deployed_requires_body,none,
|
||||
"'%0' requires that %kind1 have a body",
|
||||
(DeclAttribute, const ValueDecl *))
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// MARK: Implicit opening of existential types
|
||||
|
||||
@@ -4873,13 +4873,13 @@ void AttributeChecker::checkBackDeployedAttrs(
|
||||
// back deployment, which is to use the ABI version of the declaration when it
|
||||
// is available.
|
||||
if (auto *AEICA = D->getAttrs().getAttribute<AlwaysEmitIntoClientAttr>()) {
|
||||
diagnoseAndRemoveAttr(AEICA, diag::attr_incompatible_with_back_deploy,
|
||||
AEICA, D->getDescriptiveKind());
|
||||
diagnoseAndRemoveAttr(AEICA, diag::attr_incompatible_with_back_deployed,
|
||||
AEICA, D);
|
||||
}
|
||||
|
||||
if (auto *TA = D->getAttrs().getAttribute<TransparentAttr>()) {
|
||||
diagnoseAndRemoveAttr(TA, diag::attr_incompatible_with_back_deploy, TA,
|
||||
D->getDescriptiveKind());
|
||||
diagnoseAndRemoveAttr(TA, diag::attr_incompatible_with_back_deployed, TA,
|
||||
D);
|
||||
}
|
||||
|
||||
// Only functions, methods, computed properties, and subscripts are
|
||||
@@ -4887,7 +4887,9 @@ void AttributeChecker::checkBackDeployedAttrs(
|
||||
auto *VD = cast<ValueDecl>(D);
|
||||
std::map<PlatformKind, SourceLoc> seenPlatforms;
|
||||
|
||||
auto *ActiveAttr = D->getAttrs().getBackDeployed(Ctx, false);
|
||||
const BackDeployedAttr *ActiveAttr = nullptr;
|
||||
if (D->getBackDeployedBeforeOSVersion(Ctx))
|
||||
ActiveAttr = D->getAttrs().getBackDeployed(Ctx, false);
|
||||
|
||||
for (auto *Attr : Attrs) {
|
||||
// Back deployment only makes sense for public declarations.
|
||||
@@ -4931,19 +4933,9 @@ void AttributeChecker::checkBackDeployedAttrs(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto *VarD = dyn_cast<VarDecl>(D)) {
|
||||
// There must be a function body to back deploy so for vars we require
|
||||
// that they be computed in order to allow back deployment.
|
||||
if (VarD->hasStorageOrWrapsStorage()) {
|
||||
diagnoseAndRemoveAttr(Attr, diag::attr_not_on_stored_properties, Attr);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (VD->getOpaqueResultTypeDecl()) {
|
||||
diagnoseAndRemoveAttr(Attr,
|
||||
diag::backdeployed_opaque_result_not_supported,
|
||||
Attr, D->getDescriptiveKind())
|
||||
diagnoseAndRemoveAttr(
|
||||
Attr, diag::back_deployed_opaque_result_not_supported, Attr, VD)
|
||||
.warnInSwiftInterface(D->getDeclContext());
|
||||
continue;
|
||||
}
|
||||
@@ -4960,12 +4952,29 @@ void AttributeChecker::checkBackDeployedAttrs(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Ctx.LangOpts.DisableAvailabilityChecking)
|
||||
// The remaining diagnostics can only be diagnosed for attributes that
|
||||
// apply to the active platform.
|
||||
if (Attr != ActiveAttr)
|
||||
continue;
|
||||
|
||||
// Availability conflicts can only be diagnosed for attributes that apply
|
||||
// to the active platform.
|
||||
if (Attr != ActiveAttr)
|
||||
if (auto *VarD = dyn_cast<VarDecl>(D)) {
|
||||
// There must be a function body to back deploy so for vars we require
|
||||
// that they be computed in order to allow back deployment.
|
||||
if (VarD->hasStorageOrWrapsStorage()) {
|
||||
diagnoseAndRemoveAttr(Attr, diag::attr_not_on_stored_properties, Attr);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
|
||||
if (!AFD->hasBody()) {
|
||||
diagnoseAndRemoveAttr(Attr, diag::back_deployed_requires_body, Attr,
|
||||
VD);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (Ctx.LangOpts.DisableAvailabilityChecking)
|
||||
continue;
|
||||
|
||||
auto availability =
|
||||
|
||||
24
test/ModuleInterface/BackDeployedAttrBad.swiftinterface
Normal file
24
test/ModuleInterface/BackDeployedAttrBad.swiftinterface
Normal file
@@ -0,0 +1,24 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: split-file %s %t
|
||||
// RUN: not %target-swift-typecheck-module-from-interface(%t/Test.swiftinterface) -module-name Test 2>&1 | %FileCheck %s
|
||||
|
||||
// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=visionos
|
||||
|
||||
// This test uses split-file because the check lines cannot appear as comments
|
||||
// in the interface (they'd match themselves in the diagnostic output).
|
||||
// FIXME: -verify should work for -typecheck-module-from-interface
|
||||
|
||||
// CHECK: Test.swiftinterface:5:2: error: '@backDeployed' requires that global function 'backDeployedFuncWithoutBody()' have a body
|
||||
// CHECK: Test.swiftinterface:9:2: error: '@backDeployed' must not be used on stored properties
|
||||
|
||||
//--- Test.swiftinterface
|
||||
// swift-interface-format-version: 1.0
|
||||
// swift-module-flags:
|
||||
|
||||
@available(macOS 14.4, iOS 17.4, watchOS 10.4, tvOS 17.4, visionOS 1.1, *)
|
||||
@backDeployed(before: macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0)
|
||||
public func backDeployedFuncWithoutBody()
|
||||
|
||||
@available(macOS 14.4, iOS 17.4, watchOS 10.4, tvOS 17.4, visionOS 1.1, *)
|
||||
@backDeployed(before: macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0)
|
||||
public var backDeployedVarWithoutBody: Int
|
||||
16
test/ModuleInterface/BackDeployedAttrGood.swiftinterface
Normal file
16
test/ModuleInterface/BackDeployedAttrGood.swiftinterface
Normal file
@@ -0,0 +1,16 @@
|
||||
// swift-interface-format-version: 1.0
|
||||
// swift-module-flags:
|
||||
|
||||
// RUN: %target-swift-typecheck-module-from-interface(%s) -module-name Test
|
||||
// REQUIRES: OS=macosx
|
||||
|
||||
// Since the following declarations are only back deployed on iOS, their bodies
|
||||
// should be missing in a `.swiftinterface` compiled for macOS
|
||||
|
||||
@available(iOS 17.4, *)
|
||||
@backDeployed(before: iOS 18.0)
|
||||
public func backDeployedFuncOniOSWithoutBody()
|
||||
|
||||
@available(iOS 17.4, *)
|
||||
@backDeployed(before: iOS 18.0)
|
||||
public var backDeployedVarWithoutBody: Int
|
||||
@@ -57,7 +57,7 @@ public struct EV : V {
|
||||
@available(SwiftStdlib 5.1, *)
|
||||
public extension V {
|
||||
// CHECK: Loading underlying information for opaque type of 'backdeployedOpaqueFunc()'
|
||||
@backDeployed(before: SwiftStdlib 5.1) // expected-warning 4 {{'@backDeployed' is unsupported on a instance method with a 'some' return type}}
|
||||
@backDeployed(before: SwiftStdlib 5.1) // expected-warning 4 {{'@backDeployed' cannot be applied to instance method 'backdeployedOpaqueFunc()' because it has a 'some' return type}}
|
||||
func backdeployedOpaqueFunc() -> some V { EV() }
|
||||
}
|
||||
|
||||
|
||||
@@ -251,6 +251,9 @@ public enum CannotBackDeployEnum {
|
||||
@backDeployed(before: macOS 12.0) // expected-error {{'@backDeployed' must not be used on stored properties}}
|
||||
public var cannotBackDeployTopLevelVar = 79
|
||||
|
||||
@backDeployed(before: iOS 15.0) // OK, this can only be diagnosed when compiling for iOS
|
||||
public var cannotBackDeployTopLevelVarOniOS = 79
|
||||
|
||||
@backDeployed(before: macOS 12.0) // expected-error {{'@backDeployed' attribute cannot be applied to this declaration}}
|
||||
extension TopLevelStruct {}
|
||||
|
||||
@@ -266,13 +269,13 @@ public struct ConformsToTopLevelProtocol: TopLevelProtocol {
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.1, *)
|
||||
@backDeployed(before: macOS 12.0) // expected-warning {{'@backDeployed' is unsupported on a var with a 'some' return type}}
|
||||
@backDeployed(before: macOS 12.0) // expected-warning {{'@backDeployed' cannot be applied to var 'cannotBackDeployVarWithOpaqueResultType' because it has a 'some' return type}}
|
||||
public var cannotBackDeployVarWithOpaqueResultType: some TopLevelProtocol {
|
||||
return ConformsToTopLevelProtocol()
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.1, *)
|
||||
@backDeployed(before: macOS 12.0) // expected-warning {{'@backDeployed' is unsupported on a global function with a 'some' return type}}
|
||||
@backDeployed(before: macOS 12.0) // expected-warning {{'@backDeployed' cannot be applied to global function 'cannotBackDeployFuncWithOpaqueResultType()' because it has a 'some' return type}}
|
||||
public func cannotBackDeployFuncWithOpaqueResultType() -> some TopLevelProtocol {
|
||||
return ConformsToTopLevelProtocol()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user