diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index acc4944aff20d..70f012e2377b0 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7570,13 +7570,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 diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index c0a593477ab89..60916e8a2789b 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -4719,13 +4719,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()) { - 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()) { - 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 @@ -4777,19 +4777,9 @@ void AttributeChecker::checkBackDeployedAttrs( continue; } - if (auto *VarD = dyn_cast(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; } @@ -4806,12 +4796,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(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(D)) { + if (!AFD->hasBody()) { + diagnoseAndRemoveAttr(Attr, diag::back_deployed_requires_body, Attr, + VD); + continue; + } + } + + if (Ctx.LangOpts.DisableAvailabilityChecking) continue; auto availability = diff --git a/test/ModuleInterface/BackDeployedAttrBad.swiftinterface b/test/ModuleInterface/BackDeployedAttrBad.swiftinterface new file mode 100644 index 0000000000000..20e88dc76cc51 --- /dev/null +++ b/test/ModuleInterface/BackDeployedAttrBad.swiftinterface @@ -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 diff --git a/test/ModuleInterface/BackDeployedAttrGood.swiftinterface b/test/ModuleInterface/BackDeployedAttrGood.swiftinterface new file mode 100644 index 0000000000000..f743a07890bef --- /dev/null +++ b/test/ModuleInterface/BackDeployedAttrGood.swiftinterface @@ -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 diff --git a/test/Serialization/ignore-opaque-underlying-type-back-deploy.swift b/test/Serialization/ignore-opaque-underlying-type-back-deploy.swift index 6f7563f1b9a68..b015423c5eda4 100644 --- a/test/Serialization/ignore-opaque-underlying-type-back-deploy.swift +++ b/test/Serialization/ignore-opaque-underlying-type-back-deploy.swift @@ -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() } } diff --git a/test/attr/attr_backDeployed.swift b/test/attr/attr_backDeployed.swift index bd9ce4d86f0df..d1f051f5cc742 100644 --- a/test/attr/attr_backDeployed.swift +++ b/test/attr/attr_backDeployed.swift @@ -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() }