Skip to content

Commit 7ea778f

Browse files
committed
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.
1 parent f6bf596 commit 7ea778f

File tree

6 files changed

+86
-30
lines changed

6 files changed

+86
-30
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7567,13 +7567,17 @@ ERROR(cannot_convert_default_value_type_to_argument_type, none,
75677567
// MARK: Back deployment
75687568
//------------------------------------------------------------------------------
75697569

7570-
ERROR(attr_incompatible_with_back_deploy,none,
7571-
"'%0' cannot be applied to a back deployed %1",
7572-
(DeclAttribute, DescriptiveDeclKind))
7570+
ERROR(attr_incompatible_with_back_deployed,none,
7571+
"'%0' cannot be applied to a back deployed %kind1",
7572+
(DeclAttribute, const Decl *))
75737573

7574-
WARNING(backdeployed_opaque_result_not_supported,none,
7575-
"'%0' is unsupported on a %1 with a 'some' return type",
7576-
(DeclAttribute, DescriptiveDeclKind))
7574+
WARNING(back_deployed_opaque_result_not_supported,none,
7575+
"'%0' cannot be applied to %kind1 because it has a 'some' return type",
7576+
(DeclAttribute, const ValueDecl *))
7577+
7578+
ERROR(back_deployed_requires_body,none,
7579+
"'%0' requires that %kind1 have a body",
7580+
(DeclAttribute, const ValueDecl *))
75777581

75787582
//------------------------------------------------------------------------------
75797583
// MARK: Implicit opening of existential types

lib/Sema/TypeCheckAttr.cpp

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4873,21 +4873,23 @@ void AttributeChecker::checkBackDeployedAttrs(
48734873
// back deployment, which is to use the ABI version of the declaration when it
48744874
// is available.
48754875
if (auto *AEICA = D->getAttrs().getAttribute<AlwaysEmitIntoClientAttr>()) {
4876-
diagnoseAndRemoveAttr(AEICA, diag::attr_incompatible_with_back_deploy,
4877-
AEICA, D->getDescriptiveKind());
4876+
diagnoseAndRemoveAttr(AEICA, diag::attr_incompatible_with_back_deployed,
4877+
AEICA, D);
48784878
}
48794879

48804880
if (auto *TA = D->getAttrs().getAttribute<TransparentAttr>()) {
4881-
diagnoseAndRemoveAttr(TA, diag::attr_incompatible_with_back_deploy, TA,
4882-
D->getDescriptiveKind());
4881+
diagnoseAndRemoveAttr(TA, diag::attr_incompatible_with_back_deployed, TA,
4882+
D);
48834883
}
48844884

48854885
// Only functions, methods, computed properties, and subscripts are
48864886
// back-deployable, so D should be ValueDecl.
48874887
auto *VD = cast<ValueDecl>(D);
48884888
std::map<PlatformKind, SourceLoc> seenPlatforms;
48894889

4890-
auto *ActiveAttr = D->getAttrs().getBackDeployed(Ctx, false);
4890+
const BackDeployedAttr *ActiveAttr = nullptr;
4891+
if (D->getBackDeployedBeforeOSVersion(Ctx))
4892+
ActiveAttr = D->getAttrs().getBackDeployed(Ctx, false);
48914893

48924894
for (auto *Attr : Attrs) {
48934895
// Back deployment only makes sense for public declarations.
@@ -4931,19 +4933,9 @@ void AttributeChecker::checkBackDeployedAttrs(
49314933
continue;
49324934
}
49334935

4934-
if (auto *VarD = dyn_cast<VarDecl>(D)) {
4935-
// There must be a function body to back deploy so for vars we require
4936-
// that they be computed in order to allow back deployment.
4937-
if (VarD->hasStorageOrWrapsStorage()) {
4938-
diagnoseAndRemoveAttr(Attr, diag::attr_not_on_stored_properties, Attr);
4939-
continue;
4940-
}
4941-
}
4942-
49434936
if (VD->getOpaqueResultTypeDecl()) {
4944-
diagnoseAndRemoveAttr(Attr,
4945-
diag::backdeployed_opaque_result_not_supported,
4946-
Attr, D->getDescriptiveKind())
4937+
diagnoseAndRemoveAttr(
4938+
Attr, diag::back_deployed_opaque_result_not_supported, Attr, VD)
49474939
.warnInSwiftInterface(D->getDeclContext());
49484940
continue;
49494941
}
@@ -4960,12 +4952,29 @@ void AttributeChecker::checkBackDeployedAttrs(
49604952
continue;
49614953
}
49624954

4963-
if (Ctx.LangOpts.DisableAvailabilityChecking)
4955+
// The remaining diagnostics can only be diagnosed for attributes that
4956+
// apply to the active platform.
4957+
if (Attr != ActiveAttr)
49644958
continue;
49654959

4966-
// Availability conflicts can only be diagnosed for attributes that apply
4967-
// to the active platform.
4968-
if (Attr != ActiveAttr)
4960+
if (auto *VarD = dyn_cast<VarDecl>(D)) {
4961+
// There must be a function body to back deploy so for vars we require
4962+
// that they be computed in order to allow back deployment.
4963+
if (VarD->hasStorageOrWrapsStorage()) {
4964+
diagnoseAndRemoveAttr(Attr, diag::attr_not_on_stored_properties, Attr);
4965+
continue;
4966+
}
4967+
}
4968+
4969+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
4970+
if (!AFD->hasBody()) {
4971+
diagnoseAndRemoveAttr(Attr, diag::back_deployed_requires_body, Attr,
4972+
VD);
4973+
continue;
4974+
}
4975+
}
4976+
4977+
if (Ctx.LangOpts.DisableAvailabilityChecking)
49694978
continue;
49704979

49714980
auto availability =
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
// RUN: not %target-swift-typecheck-module-from-interface(%t/Test.swiftinterface) -module-name Test 2>&1 | %FileCheck %s
4+
5+
// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=visionos
6+
7+
// This test uses split-file because the check lines cannot appear as comments
8+
// in the interface (they'd match themselves in the diagnostic output).
9+
// FIXME: -verify should work for -typecheck-module-from-interface
10+
11+
// CHECK: Test.swiftinterface:5:2: error: '@backDeployed' requires that global function 'backDeployedFuncWithoutBody()' have a body
12+
// CHECK: Test.swiftinterface:9:2: error: '@backDeployed' must not be used on stored properties
13+
14+
//--- Test.swiftinterface
15+
// swift-interface-format-version: 1.0
16+
// swift-module-flags:
17+
18+
@available(macOS 14.4, iOS 17.4, watchOS 10.4, tvOS 17.4, visionOS 1.1, *)
19+
@backDeployed(before: macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0)
20+
public func backDeployedFuncWithoutBody()
21+
22+
@available(macOS 14.4, iOS 17.4, watchOS 10.4, tvOS 17.4, visionOS 1.1, *)
23+
@backDeployed(before: macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0)
24+
public var backDeployedVarWithoutBody: Int
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// swift-interface-format-version: 1.0
2+
// swift-module-flags:
3+
4+
// RUN: %target-swift-typecheck-module-from-interface(%s) -module-name Test
5+
// REQUIRES: OS=macosx
6+
7+
// Since the following declarations are only back deployed on iOS, their bodies
8+
// should be missing in a `.swiftinterface` compiled for macOS
9+
10+
@available(iOS 17.4, *)
11+
@backDeployed(before: iOS 18.0)
12+
public func backDeployedFuncOniOSWithoutBody()
13+
14+
@available(iOS 17.4, *)
15+
@backDeployed(before: iOS 18.0)
16+
public var backDeployedVarWithoutBody: Int

test/Serialization/ignore-opaque-underlying-type-back-deploy.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public struct EV : V {
5757
@available(SwiftStdlib 5.1, *)
5858
public extension V {
5959
// CHECK: Loading underlying information for opaque type of 'backdeployedOpaqueFunc()'
60-
@backDeployed(before: SwiftStdlib 5.1) // expected-warning 4 {{'@backDeployed' is unsupported on a instance method with a 'some' return type}}
60+
@backDeployed(before: SwiftStdlib 5.1) // expected-warning 4 {{'@backDeployed' cannot be applied to instance method 'backdeployedOpaqueFunc()' because it has a 'some' return type}}
6161
func backdeployedOpaqueFunc() -> some V { EV() }
6262
}
6363

test/attr/attr_backDeployed.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,9 @@ public enum CannotBackDeployEnum {
251251
@backDeployed(before: macOS 12.0) // expected-error {{'@backDeployed' must not be used on stored properties}}
252252
public var cannotBackDeployTopLevelVar = 79
253253

254+
@backDeployed(before: iOS 15.0) // OK, this can only be diagnosed when compiling for iOS
255+
public var cannotBackDeployTopLevelVarOniOS = 79
256+
254257
@backDeployed(before: macOS 12.0) // expected-error {{'@backDeployed' attribute cannot be applied to this declaration}}
255258
extension TopLevelStruct {}
256259

@@ -266,13 +269,13 @@ public struct ConformsToTopLevelProtocol: TopLevelProtocol {
266269
}
267270

268271
@available(SwiftStdlib 5.1, *)
269-
@backDeployed(before: macOS 12.0) // expected-warning {{'@backDeployed' is unsupported on a var with a 'some' return type}}
272+
@backDeployed(before: macOS 12.0) // expected-warning {{'@backDeployed' cannot be applied to var 'cannotBackDeployVarWithOpaqueResultType' because it has a 'some' return type}}
270273
public var cannotBackDeployVarWithOpaqueResultType: some TopLevelProtocol {
271274
return ConformsToTopLevelProtocol()
272275
}
273276

274277
@available(SwiftStdlib 5.1, *)
275-
@backDeployed(before: macOS 12.0) // expected-warning {{'@backDeployed' is unsupported on a global function with a 'some' return type}}
278+
@backDeployed(before: macOS 12.0) // expected-warning {{'@backDeployed' cannot be applied to global function 'cannotBackDeployFuncWithOpaqueResultType()' because it has a 'some' return type}}
276279
public func cannotBackDeployFuncWithOpaqueResultType() -> some TopLevelProtocol {
277280
return ConformsToTopLevelProtocol()
278281
}

0 commit comments

Comments
 (0)