Skip to content

Commit 8fde58f

Browse files
authored
Merge pull request swiftlang#63357 from tshortli/se0376-rename-backdeploy
[SE-0376] Rename `@_backDeploy(before:)` to `@backDeployed(before:)`
2 parents 04d7938 + d44c9f2 commit 8fde58f

Some content is hidden

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

44 files changed

+628
-600
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
@@ -2219,15 +2219,12 @@ class UnavailableFromAsyncAttr : public DeclAttribute {
22192219

22202220
/// The @_backDeploy(...) attribute, used to make function declarations available
22212221
/// for back deployment to older OSes via emission into the client binary.
2222-
class BackDeployAttr: public DeclAttribute {
2222+
class BackDeployedAttr : public DeclAttribute {
22232223
public:
2224-
BackDeployAttr(SourceLoc AtLoc, SourceRange Range,
2225-
PlatformKind Platform,
2226-
const llvm::VersionTuple Version,
2227-
bool Implicit)
2228-
: DeclAttribute(DAK_BackDeploy, AtLoc, Range, Implicit),
2229-
Platform(Platform),
2230-
Version(Version) {}
2224+
BackDeployedAttr(SourceLoc AtLoc, SourceRange Range, PlatformKind Platform,
2225+
const llvm::VersionTuple Version, bool Implicit)
2226+
: DeclAttribute(DAK_BackDeployed, AtLoc, Range, Implicit),
2227+
Platform(Platform), Version(Version) {}
22312228

22322229
/// The platform the symbol is available for back deployment on.
22332230
const PlatformKind Platform;
@@ -2239,7 +2236,7 @@ class BackDeployAttr: public DeclAttribute {
22392236
bool isActivePlatform(const ASTContext &ctx) const;
22402237

22412238
static bool classof(const DeclAttribute *DA) {
2242-
return DA->getKind() == DAK_BackDeploy;
2239+
return DA->getKind() == DAK_BackDeployed;
22432240
}
22442241
};
22452242

@@ -2419,9 +2416,9 @@ class DeclAttributes {
24192416
/// otherwise.
24202417
const AvailableAttr *getNoAsync(const ASTContext &ctx) const;
24212418

2422-
/// Returns the \c @_backDeploy attribute that is active for the current
2419+
/// Returns the `@backDeployed` attribute that is active for the current
24232420
/// platform.
2424-
const BackDeployAttr *getBackDeploy(const ASTContext &ctx) const;
2421+
const BackDeployedAttr *getBackDeployed(const ASTContext &ctx) const;
24252422

24262423
SWIFT_DEBUG_DUMPER(dump(const Decl *D = nullptr));
24272424
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
@@ -884,9 +884,9 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
884884
Optional<llvm::VersionTuple> getIntroducedOSVersion(PlatformKind Kind) const;
885885

886886
/// Returns the OS version in which the decl became ABI as specified by the
887-
/// @_backDeploy attribute.
887+
/// @backDeployed attribute.
888888
Optional<llvm::VersionTuple>
889-
getBackDeployBeforeOSVersion(ASTContext &Ctx) const;
889+
getBackDeployedBeforeOSVersion(ASTContext &Ctx) const;
890890

891891
/// Returns the starting location of the entire declaration.
892892
SourceLoc getStartLoc() const { return getSourceRange().Start; }
@@ -6808,8 +6808,8 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
68086808
/// \return the synthesized thunk, or null if the base of the call has
68096809
/// diagnosed errors during type checking.
68106810
FuncDecl *getDistributedThunk() const;
6811-
6812-
/// Returns 'true' if the function has (or inherits) the @c @_backDeploy
6811+
6812+
/// Returns 'true' if the function has (or inherits) the `@backDeployed`
68136813
/// attribute.
68146814
bool isBackDeployed() const;
68156815

include/swift/AST/DiagnosticsParse.def

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

15941594
// backDeploy
15951595
ERROR(attr_back_deploy_expected_before_label,none,
1596-
"expected 'before:' in '@_backDeploy' attribute", ())
1596+
"expected 'before:' in '@backDeployed' attribute", ())
15971597
ERROR(attr_back_deploy_expected_colon_after_before,none,
1598-
"expected ':' after 'before' in '@_backDeploy' attribute", ())
1598+
"expected ':' after 'before' in '@backDeployed' attribute", ())
15991599
ERROR(attr_back_deploy_missing_rparen,none,
1600-
"expected ')' in '@_backDeploy' argument list", ())
1600+
"expected ')' in '@backDeployed' argument list", ())
16011601

16021602
// convention
16031603
ERROR(convention_attribute_expected_lparen,none,

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6072,7 +6072,7 @@ ERROR(usable_from_inline_attr_in_protocol,none,
60726072
"an '@_alwaysEmitIntoClient' function|" \
60736073
"a default argument value|" \
60746074
"a property initializer in a '@frozen' type|" \
6075-
"a '@_backDeploy' function'}"
6075+
"a '@backDeployed' function'}"
60766076

60776077
#define DECL_OR_ACCESSOR "%select{%0|%0 for}"
60786078

include/swift/Parse/Parser.h

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

1101-
/// Parse the @_backDeploy attribute.
1102-
bool parseBackDeployAttribute(DeclAttributes &Attributes, StringRef AttrName,
1103-
SourceLoc AtLoc, SourceLoc Loc);
1101+
/// Parse the @backDeployed attribute.
1102+
bool parseBackDeployedAttribute(DeclAttributes &Attributes,
1103+
StringRef AttrName, SourceLoc AtLoc,
1104+
SourceLoc Loc);
11041105

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

include/swift/SIL/SILDeclRef.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ struct SILDeclRef {
390390
bool isNoinline() const;
391391
/// True if the function has __always inline attribute.
392392
bool isAlwaysInline() const;
393-
/// True if the function has the @_backDeploy attribute.
393+
/// True if the function has the @backDeployed attribute.
394394
bool isBackDeployed() const;
395395

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

lib/AST/Attr.cpp

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -400,23 +400,24 @@ const AvailableAttr *DeclAttributes::getNoAsync(const ASTContext &ctx) const {
400400
return bestAttr;
401401
}
402402

403-
const BackDeployAttr *
404-
DeclAttributes::getBackDeploy(const ASTContext &ctx) const {
405-
const BackDeployAttr *bestAttr = nullptr;
403+
const BackDeployedAttr *
404+
DeclAttributes::getBackDeployed(const ASTContext &ctx) const {
405+
const BackDeployedAttr *bestAttr = nullptr;
406406

407407
for (auto attr : *this) {
408-
auto *backDeployAttr = dyn_cast<BackDeployAttr>(attr);
409-
if (!backDeployAttr)
408+
auto *backDeployedAttr = dyn_cast<BackDeployedAttr>(attr);
409+
if (!backDeployedAttr)
410410
continue;
411411

412-
if (backDeployAttr->isInvalid() || !backDeployAttr->isActivePlatform(ctx))
412+
if (backDeployedAttr->isInvalid() ||
413+
!backDeployedAttr->isActivePlatform(ctx))
413414
continue;
414415

415416
// We have an attribute that is active for the platform, but
416417
// is it more specific than our current best?
417-
if (!bestAttr || inheritsAvailabilityFromPlatform(backDeployAttr->Platform,
418-
bestAttr->Platform)) {
419-
bestAttr = backDeployAttr;
418+
if (!bestAttr || inheritsAvailabilityFromPlatform(
419+
backDeployedAttr->Platform, bestAttr->Platform)) {
420+
bestAttr = backDeployedAttr;
420421
}
421422
}
422423

@@ -547,13 +548,14 @@ static void printShortFormBackDeployed(ArrayRef<const DeclAttribute *> Attrs,
547548
ASTPrinter &Printer,
548549
const PrintOptions &Options) {
549550
assert(!Attrs.empty());
551+
// TODO: Print `@backDeployed` in swiftinterfaces (rdar://104920183)
550552
Printer << "@_backDeploy(before: ";
551553
bool isFirst = true;
552554

553555
for (auto *DA : Attrs) {
554556
if (!isFirst)
555557
Printer << ", ";
556-
auto *attr = cast<BackDeployAttr>(DA);
558+
auto *attr = cast<BackDeployedAttr>(DA);
557559
Printer << platformString(attr->Platform) << " "
558560
<< attr->Version.getAsString();
559561
isFirst = false;
@@ -773,7 +775,7 @@ void DeclAttributes::print(ASTPrinter &Printer, const PrintOptions &Options,
773775
AttributeVector shortAvailableAttributes;
774776
const DeclAttribute *swiftVersionAvailableAttribute = nullptr;
775777
const DeclAttribute *packageDescriptionVersionAvailableAttribute = nullptr;
776-
AttributeVector backDeployAttributes;
778+
AttributeVector backDeployedAttributes;
777779
AttributeVector longAttributes;
778780
AttributeVector attributes;
779781
AttributeVector modifiers;
@@ -811,7 +813,7 @@ void DeclAttributes::print(ASTPrinter &Printer, const PrintOptions &Options,
811813
}
812814

813815
AttributeVector &which = DA->isDeclModifier() ? modifiers :
814-
isa<BackDeployAttr>(DA) ? backDeployAttributes :
816+
isa<BackDeployedAttr>(DA) ? backDeployedAttributes :
815817
isShortAvailable(DA) ? shortAvailableAttributes :
816818
DA->isLongAttribute() ? longAttributes :
817819
attributes;
@@ -824,8 +826,8 @@ void DeclAttributes::print(ASTPrinter &Printer, const PrintOptions &Options,
824826
printShortFormAvailable(packageDescriptionVersionAvailableAttribute, Printer, Options);
825827
if (!shortAvailableAttributes.empty())
826828
printShortFormAvailable(shortAvailableAttributes, Printer, Options);
827-
if (!backDeployAttributes.empty())
828-
printShortFormBackDeployed(backDeployAttributes, Printer, Options);
829+
if (!backDeployedAttributes.empty())
830+
printShortFormBackDeployed(backDeployedAttributes, Printer, Options);
829831

830832
for (auto DA : longAttributes)
831833
DA->print(Printer, Options, D);
@@ -1324,10 +1326,11 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
13241326
break;
13251327
}
13261328

1327-
case DAK_BackDeploy: {
1329+
case DAK_BackDeployed: {
1330+
// TODO: Print `@backDeployed` in swiftinterfaces (rdar://104920183)
13281331
Printer.printAttrName("@_backDeploy");
13291332
Printer << "(before: ";
1330-
auto Attr = cast<BackDeployAttr>(this);
1333+
auto Attr = cast<BackDeployedAttr>(this);
13311334
Printer << platformString(Attr->Platform) << " " <<
13321335
Attr->Version.getAsString();
13331336
Printer << ")";
@@ -1534,8 +1537,8 @@ StringRef DeclAttribute::getAttrName() const {
15341537
return "transpose";
15351538
case DAK_UnavailableFromAsync:
15361539
return "_unavailableFromAsync";
1537-
case DAK_BackDeploy:
1538-
return "_backDeploy";
1540+
case DAK_BackDeployed:
1541+
return "backDeployed";
15391542
case DAK_Expose:
15401543
return "_expose";
15411544
case DAK_Documentation:
@@ -1791,7 +1794,7 @@ bool AvailableAttr::isActivePlatform(const ASTContext &ctx) const {
17911794
return isPlatformActive(Platform, ctx.LangOpts);
17921795
}
17931796

1794-
bool BackDeployAttr::isActivePlatform(const ASTContext &ctx) const {
1797+
bool BackDeployedAttr::isActivePlatform(const ASTContext &ctx) const {
17951798
return isPlatformActive(Platform, ctx.LangOpts);
17961799
}
17971800

lib/AST/Decl.cpp

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

419419
Optional<llvm::VersionTuple>
420-
Decl::getBackDeployBeforeOSVersion(ASTContext &Ctx) const {
421-
if (auto *attr = getAttrs().getBackDeploy(Ctx))
420+
Decl::getBackDeployedBeforeOSVersion(ASTContext &Ctx) const {
421+
if (auto *attr = getAttrs().getBackDeployed(Ctx))
422422
return attr->Version;
423423

424-
// Accessors may inherit `@_backDeploy`.
424+
// Accessors may inherit `@backDeployed`.
425425
if (auto *AD = dyn_cast<AccessorDecl>(this))
426-
return AD->getStorage()->getBackDeployBeforeOSVersion(Ctx);
426+
return AD->getStorage()->getBackDeployedBeforeOSVersion(Ctx);
427427

428428
return None;
429429
}
@@ -971,8 +971,8 @@ AvailabilityContext Decl::getAvailabilityForLinkage() const {
971971
ASTContext &ctx = getASTContext();
972972

973973
// When computing availability for linkage, use the "before" version from
974-
// the @_backDeploy attribute, if present.
975-
if (auto backDeployVersion = getBackDeployBeforeOSVersion(ctx))
974+
// the @backDeployed attribute, if present.
975+
if (auto backDeployVersion = getBackDeployedBeforeOSVersion(ctx))
976976
return AvailabilityContext{VersionRange::allGTE(*backDeployVersion)};
977977

978978
auto containingContext =
@@ -8065,12 +8065,12 @@ bool AbstractFunctionDecl::isSendable() const {
80658065
}
80668066

80678067
bool AbstractFunctionDecl::isBackDeployed() const {
8068-
if (getAttrs().hasAttribute<BackDeployAttr>())
8068+
if (getAttrs().hasAttribute<BackDeployedAttr>())
80698069
return true;
80708070

80718071
// Property and subscript accessors inherit the attribute.
80728072
if (auto *AD = dyn_cast<AccessorDecl>(this)) {
8073-
if (AD->getStorage()->getAttrs().hasAttribute<BackDeployAttr>())
8073+
if (AD->getStorage()->getAttrs().hasAttribute<BackDeployedAttr>())
80748074
return true;
80758075
}
80768076

0 commit comments

Comments
 (0)