Skip to content

Commit 8bd0080

Browse files
authored
Merge pull request #63394 from tshortli/se0376-rename-backdeploy-5.8
[5.8][SE-0376] Rename `@_backDeploy(before:)` to `@backDeployed(before:)`
2 parents 8b4068b + 0e52979 commit 8bd0080

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+984
-546
lines changed

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,33 @@ _**Note:** This is in reverse chronological order, so newer entries are added to
44

55
## Swift 5.8
66

7+
* [SE-0376][]:
8+
9+
The `@backDeployed(before:)` attribute may now be used to extend the availability of a function to OS releases prior to the introduction of that function as ABI.
10+
11+
For example, suppose that `struct Temperature` was introduced in a macOS SDK framework in macOS 12. Later in macOS 13 the framework authors decided to add a `degreesFahrenheit` property as a convenience:
12+
13+
```swift
14+
@available(macOS 12, *)
15+
public struct Temperature {
16+
public var degreesCelsius: Double
17+
18+
// ...
19+
}
20+
21+
extension Temperature {
22+
@available(macOS 12, *)
23+
@backDeployed(before: macOS 13)
24+
public var degreesFahrenheit: Double {
25+
return (degreesCelsius * 9 / 5) + 32
26+
}
27+
}
28+
```
29+
30+
Adding the `@backDeployed` attribute to `degreesFahrenheit` enables the framework author to make this new declaration available to apps with a minimum deployment target of macOS 12, even though the ABI entry point for `degreesFahrenheit` is only present in macOS 13 and up.
31+
32+
When a function with `@backDeployed` is called, the compiler wraps the invocation of the function in a thunk. The thunk checks whether the library entry point for the declaration is available at runtime, and invokes it if it is. Otherwise, a copy of the function that was emitted into the client is called instead.
33+
734
* [#56139][]:
835

936
Сollection downcasts in cast patterns are now supported. For example:
@@ -9611,6 +9638,7 @@ using the `.dynamicType` member to retrieve the type of an expression should mig
96119638
[SE-0362]: <https://github.com/apple/swift-evolution/blob/main/proposals/0362-piecemeal-future-features.md>
96129639
[SE-0365]: <https://github.com/apple/swift-evolution/blob/main/proposals/0365-implicit-self-weak-capture.md>
96139640
[SE-0370]: <https://github.com/apple/swift-evolution/blob/main/proposals/0370-pointer-family-initialization-improvements.md>
9641+
[SE-0376]: <https://github.com/apple/swift-evolution/blob/main/proposals/0376-function-back-deployment.md>
96149642

96159643
[#42697]: <https://github.com/apple/swift/issues/42697>
96169644
[#42728]: <https://github.com/apple/swift/issues/42728>

docs/ReferenceGuides/UnderscoredAttributes.md

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,7 @@ Adding this attribute to a type leads to remarks being emitted for all methods.
5353

5454
## `@_backDeploy(before: ...)`
5555

56-
Causes the body of a function to be emitted into the module interface to be
57-
available for emission into clients with deployment targets lower than the
58-
ABI availability of the function. When the client's deployment target is
59-
before the function's ABI availability, the compiler replaces calls to that
60-
function with a call to a thunk that checks at runtime whether the original
61-
library function is available. If the original is available then it is
62-
called. Otherwise, the fallback copy of the function that was emitted into the
63-
client is called instead.
64-
65-
For more details, see the [pitch thread](https://forums.swift.org/t/pitch-function-back-deployment/55769/)
66-
in the forums.
56+
The spelling of `@backDeployed(before:)` prior to the acceptance of [SE-0376](https://github.com/apple/swift-evolution/blob/main/proposals/0376-function-back-deployment.md).
6757

6858
## `@_borrowed`
6959

include/swift/AST/Attr.h

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2214,15 +2214,12 @@ class UnavailableFromAsyncAttr : public DeclAttribute {
22142214

22152215
/// The @_backDeploy(...) attribute, used to make function declarations available
22162216
/// for back deployment to older OSes via emission into the client binary.
2217-
class BackDeployAttr: public DeclAttribute {
2217+
class BackDeployedAttr : public DeclAttribute {
22182218
public:
2219-
BackDeployAttr(SourceLoc AtLoc, SourceRange Range,
2220-
PlatformKind Platform,
2221-
const llvm::VersionTuple Version,
2222-
bool Implicit)
2223-
: DeclAttribute(DAK_BackDeploy, AtLoc, Range, Implicit),
2224-
Platform(Platform),
2225-
Version(Version) {}
2219+
BackDeployedAttr(SourceLoc AtLoc, SourceRange Range, PlatformKind Platform,
2220+
const llvm::VersionTuple Version, bool Implicit)
2221+
: DeclAttribute(DAK_BackDeployed, AtLoc, Range, Implicit),
2222+
Platform(Platform), Version(Version) {}
22262223

22272224
/// The platform the symbol is available for back deployment on.
22282225
const PlatformKind Platform;
@@ -2234,7 +2231,7 @@ class BackDeployAttr: public DeclAttribute {
22342231
bool isActivePlatform(const ASTContext &ctx) const;
22352232

22362233
static bool classof(const DeclAttribute *DA) {
2237-
return DA->getKind() == DAK_BackDeploy;
2234+
return DA->getKind() == DAK_BackDeployed;
22382235
}
22392236
};
22402237

@@ -2367,9 +2364,9 @@ class DeclAttributes {
23672364
/// otherwise.
23682365
const AvailableAttr *getNoAsync(const ASTContext &ctx) const;
23692366

2370-
/// Returns the \c @_backDeploy attribute that is active for the current
2367+
/// Returns the `@backDeployed` attribute that is active for the current
23712368
/// platform.
2372-
const BackDeployAttr *getBackDeploy(const ASTContext &ctx) const;
2369+
const BackDeployedAttr *getBackDeployed(const ASTContext &ctx) const;
23732370

23742371
SWIFT_DEBUG_DUMPER(dump(const Decl *D = nullptr));
23752372
void print(ASTPrinter &Printer, const PrintOptions &Options,

include/swift/AST/Decl.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -853,9 +853,9 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
853853
Optional<llvm::VersionTuple> getIntroducedOSVersion(PlatformKind Kind) const;
854854

855855
/// Returns the OS version in which the decl became ABI as specified by the
856-
/// @_backDeploy attribute.
856+
/// @backDeployed attribute.
857857
Optional<llvm::VersionTuple>
858-
getBackDeployBeforeOSVersion(ASTContext &Ctx) const;
858+
getBackDeployedBeforeOSVersion(ASTContext &Ctx) const;
859859

860860
/// Returns the starting location of the entire declaration.
861861
SourceLoc getStartLoc() const { return getSourceRange().Start; }
@@ -6740,8 +6740,8 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
67406740
/// \return the synthesized thunk, or null if the base of the call has
67416741
/// diagnosed errors during type checking.
67426742
FuncDecl *getDistributedThunk() const;
6743-
6744-
/// Returns 'true' if the function has (or inherits) the @c @_backDeploy
6743+
6744+
/// Returns 'true' if the function has (or inherits) the `@backDeployed`
67456745
/// attribute.
67466746
bool isBackDeployed() const;
67476747

include/swift/AST/DiagnosticsParse.def

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,11 +1582,11 @@ ERROR(originally_defined_in_need_nonempty_module_name,none,
15821582

15831583
// backDeploy
15841584
ERROR(attr_back_deploy_expected_before_label,none,
1585-
"expected 'before:' in '@_backDeploy' attribute", ())
1585+
"expected 'before:' in '@backDeployed' attribute", ())
15861586
ERROR(attr_back_deploy_expected_colon_after_before,none,
1587-
"expected ':' after 'before' in '@_backDeploy' attribute", ())
1587+
"expected ':' after 'before' in '@backDeployed' attribute", ())
15881588
ERROR(attr_back_deploy_missing_rparen,none,
1589-
"expected ')' in '@_backDeploy' argument list", ())
1589+
"expected ')' in '@backDeployed' argument list", ())
15901590

15911591
// convention
15921592
ERROR(convention_attribute_expected_lparen,none,

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3311,6 +3311,14 @@ ERROR(attr_incompatible_with_non_final,none,
33113311
"'%0' cannot be applied to a non-final %1",
33123312
(DeclAttribute, DescriptiveDeclKind))
33133313

3314+
ERROR(attr_incompatible_with_override,none,
3315+
"'%0' cannot be combined with 'override'",
3316+
(DeclAttribute))
3317+
3318+
ERROR(attr_incompatible_with_objc,none,
3319+
"'%0' must not be used on an '@objc' %1",
3320+
(DeclAttribute, DescriptiveDeclKind))
3321+
33143322
ERROR(final_not_on_accessors,none,
33153323
"'final' cannot be applied to accessors, it must be put on the "
33163324
"%select{var|let|subscript}0", (unsigned))
@@ -6001,7 +6009,7 @@ ERROR(usable_from_inline_attr_in_protocol,none,
60016009
"an '@_alwaysEmitIntoClient' function|" \
60026010
"a default argument value|" \
60036011
"a property initializer in a '@frozen' type|" \
6004-
"a '@_backDeploy' function'}"
6012+
"a '@backDeployed' function'}"
60056013

60066014
#define DECL_OR_ACCESSOR "%select{%0|%0 for}"
60076015

include/swift/Parse/Parser.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,9 +1086,10 @@ class Parser {
10861086
ParserResult<TransposeAttr> parseTransposeAttribute(SourceLoc AtLoc,
10871087
SourceLoc Loc);
10881088

1089-
/// Parse the @_backDeploy attribute.
1090-
bool parseBackDeployAttribute(DeclAttributes &Attributes, StringRef AttrName,
1091-
SourceLoc AtLoc, SourceLoc Loc);
1089+
/// Parse the @backDeployed attribute.
1090+
bool parseBackDeployedAttribute(DeclAttributes &Attributes,
1091+
StringRef AttrName, SourceLoc AtLoc,
1092+
SourceLoc Loc);
10921093

10931094
/// Parse the @_documentation attribute.
10941095
ParserResult<DocumentationAttr> parseDocumentationAttribute(SourceLoc AtLoc,

include/swift/SIL/SILDeclRef.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ struct SILDeclRef {
378378
bool isNoinline() const;
379379
/// True if the function has __always inline attribute.
380380
bool isAlwaysInline() const;
381-
/// True if the function has the @_backDeploy attribute.
381+
/// True if the function has the @backDeployed attribute.
382382
bool isBackDeployed() const;
383383

384384
/// Return the expected linkage for a definition of this declaration.

lib/AST/Attr.cpp

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -398,23 +398,24 @@ const AvailableAttr *DeclAttributes::getNoAsync(const ASTContext &ctx) const {
398398
return bestAttr;
399399
}
400400

401-
const BackDeployAttr *
402-
DeclAttributes::getBackDeploy(const ASTContext &ctx) const {
403-
const BackDeployAttr *bestAttr = nullptr;
401+
const BackDeployedAttr *
402+
DeclAttributes::getBackDeployed(const ASTContext &ctx) const {
403+
const BackDeployedAttr *bestAttr = nullptr;
404404

405405
for (auto attr : *this) {
406-
auto *backDeployAttr = dyn_cast<BackDeployAttr>(attr);
407-
if (!backDeployAttr)
406+
auto *backDeployedAttr = dyn_cast<BackDeployedAttr>(attr);
407+
if (!backDeployedAttr)
408408
continue;
409409

410-
if (backDeployAttr->isInvalid() || !backDeployAttr->isActivePlatform(ctx))
410+
if (backDeployedAttr->isInvalid() ||
411+
!backDeployedAttr->isActivePlatform(ctx))
411412
continue;
412413

413414
// We have an attribute that is active for the platform, but
414415
// is it more specific than our current best?
415-
if (!bestAttr || inheritsAvailabilityFromPlatform(backDeployAttr->Platform,
416-
bestAttr->Platform)) {
417-
bestAttr = backDeployAttr;
416+
if (!bestAttr || inheritsAvailabilityFromPlatform(
417+
backDeployedAttr->Platform, bestAttr->Platform)) {
418+
bestAttr = backDeployedAttr;
418419
}
419420
}
420421

@@ -541,6 +542,26 @@ static void printShortFormAvailable(ArrayRef<const DeclAttribute *> Attrs,
541542
Printer.printNewline();
542543
}
543544

545+
static void printShortFormBackDeployed(ArrayRef<const DeclAttribute *> Attrs,
546+
ASTPrinter &Printer,
547+
const PrintOptions &Options) {
548+
assert(!Attrs.empty());
549+
// TODO: Print `@backDeployed` in swiftinterfaces (rdar://104920183)
550+
Printer << "@_backDeploy(before: ";
551+
bool isFirst = true;
552+
553+
for (auto *DA : Attrs) {
554+
if (!isFirst)
555+
Printer << ", ";
556+
auto *attr = cast<BackDeployedAttr>(DA);
557+
Printer << platformString(attr->Platform) << " "
558+
<< attr->Version.getAsString();
559+
isFirst = false;
560+
}
561+
Printer << ")";
562+
Printer.printNewline();
563+
}
564+
544565
/// The kind of a parameter in a `wrt:` differentiation parameters clause:
545566
/// either a differentiability parameter or a linearity parameter. Used for
546567
/// printing `@differentiable`, `@derivative`, and `@transpose` attributes.
@@ -752,6 +773,7 @@ void DeclAttributes::print(ASTPrinter &Printer, const PrintOptions &Options,
752773
AttributeVector shortAvailableAttributes;
753774
const DeclAttribute *swiftVersionAvailableAttribute = nullptr;
754775
const DeclAttribute *packageDescriptionVersionAvailableAttribute = nullptr;
776+
AttributeVector backDeployedAttributes;
755777
AttributeVector longAttributes;
756778
AttributeVector attributes;
757779
AttributeVector modifiers;
@@ -789,6 +811,7 @@ void DeclAttributes::print(ASTPrinter &Printer, const PrintOptions &Options,
789811
}
790812

791813
AttributeVector &which = DA->isDeclModifier() ? modifiers :
814+
isa<BackDeployedAttr>(DA) ? backDeployedAttributes :
792815
isShortAvailable(DA) ? shortAvailableAttributes :
793816
DA->isLongAttribute() ? longAttributes :
794817
attributes;
@@ -801,6 +824,8 @@ void DeclAttributes::print(ASTPrinter &Printer, const PrintOptions &Options,
801824
printShortFormAvailable(packageDescriptionVersionAvailableAttribute, Printer, Options);
802825
if (!shortAvailableAttributes.empty())
803826
printShortFormAvailable(shortAvailableAttributes, Printer, Options);
827+
if (!backDeployedAttributes.empty())
828+
printShortFormBackDeployed(backDeployedAttributes, Printer, Options);
804829

805830
for (auto DA : longAttributes)
806831
DA->print(Printer, Options, D);
@@ -1299,10 +1324,11 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
12991324
break;
13001325
}
13011326

1302-
case DAK_BackDeploy: {
1327+
case DAK_BackDeployed: {
1328+
// TODO: Print `@backDeployed` in swiftinterfaces (rdar://104920183)
13031329
Printer.printAttrName("@_backDeploy");
13041330
Printer << "(before: ";
1305-
auto Attr = cast<BackDeployAttr>(this);
1331+
auto Attr = cast<BackDeployedAttr>(this);
13061332
Printer << platformString(Attr->Platform) << " " <<
13071333
Attr->Version.getAsString();
13081334
Printer << ")";
@@ -1477,8 +1503,8 @@ StringRef DeclAttribute::getAttrName() const {
14771503
return "transpose";
14781504
case DAK_UnavailableFromAsync:
14791505
return "_unavailableFromAsync";
1480-
case DAK_BackDeploy:
1481-
return "_backDeploy";
1506+
case DAK_BackDeployed:
1507+
return "backDeployed";
14821508
case DAK_Expose:
14831509
return "_expose";
14841510
case DAK_Documentation:
@@ -1726,7 +1752,7 @@ bool AvailableAttr::isActivePlatform(const ASTContext &ctx) const {
17261752
return isPlatformActive(Platform, ctx.LangOpts);
17271753
}
17281754

1729-
bool BackDeployAttr::isActivePlatform(const ASTContext &ctx) const {
1755+
bool BackDeployedAttr::isActivePlatform(const ASTContext &ctx) const {
17301756
return isPlatformActive(Platform, ctx.LangOpts);
17311757
}
17321758

lib/AST/Decl.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -389,13 +389,13 @@ Decl::getIntroducedOSVersion(PlatformKind Kind) const {
389389
}
390390

391391
Optional<llvm::VersionTuple>
392-
Decl::getBackDeployBeforeOSVersion(ASTContext &Ctx) const {
393-
if (auto *attr = getAttrs().getBackDeploy(Ctx))
392+
Decl::getBackDeployedBeforeOSVersion(ASTContext &Ctx) const {
393+
if (auto *attr = getAttrs().getBackDeployed(Ctx))
394394
return attr->Version;
395395

396-
// Accessors may inherit `@_backDeploy`.
396+
// Accessors may inherit `@backDeployed`.
397397
if (auto *AD = dyn_cast<AccessorDecl>(this))
398-
return AD->getStorage()->getBackDeployBeforeOSVersion(Ctx);
398+
return AD->getStorage()->getBackDeployedBeforeOSVersion(Ctx);
399399

400400
return None;
401401
}
@@ -943,8 +943,8 @@ AvailabilityContext Decl::getAvailabilityForLinkage() const {
943943
ASTContext &ctx = getASTContext();
944944

945945
// When computing availability for linkage, use the "before" version from
946-
// the @_backDeploy attribute, if present.
947-
if (auto backDeployVersion = getBackDeployBeforeOSVersion(ctx))
946+
// the @backDeployed attribute, if present.
947+
if (auto backDeployVersion = getBackDeployedBeforeOSVersion(ctx))
948948
return AvailabilityContext{VersionRange::allGTE(*backDeployVersion)};
949949

950950
auto containingContext =
@@ -7983,12 +7983,12 @@ bool AbstractFunctionDecl::isSendable() const {
79837983
}
79847984

79857985
bool AbstractFunctionDecl::isBackDeployed() const {
7986-
if (getAttrs().hasAttribute<BackDeployAttr>())
7986+
if (getAttrs().hasAttribute<BackDeployedAttr>())
79877987
return true;
79887988

79897989
// Property and subscript accessors inherit the attribute.
79907990
if (auto *AD = dyn_cast<AccessorDecl>(this)) {
7991-
if (AD->getStorage()->getAttrs().hasAttribute<BackDeployAttr>())
7991+
if (AD->getStorage()->getAttrs().hasAttribute<BackDeployedAttr>())
79927992
return true;
79937993
}
79947994

0 commit comments

Comments
 (0)