Skip to content

Commit b860e76

Browse files
committed
AST: Introduce the @_backDeploy function attribute:
- Parse the attribute and diagnose parsing issues - Serialize the attribute
1 parent fe436ed commit b860e76

File tree

15 files changed

+350
-3
lines changed

15 files changed

+350
-3
lines changed

docs/ReferenceGuides/UnderscoredAttributes.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ Most notably, default argument expressions are implicitly
3939
`@_alwaysEmitIntoClient`, which means that adding a default argument to a
4040
function which did not have one previously does not break ABI.
4141

42+
## `@_backDeploy(availabilitySpec ...)`
43+
44+
Causes the body of a function to be emitted into the module interface to be
45+
available for inlining in clients with deployment targets lower than the formal
46+
availability of the function. When inlined, the body of the function is
47+
transformed such that it calls the library's copy of the function if it is
48+
available at runtime. Otherwise, the copy of the original function body is
49+
executed.
50+
4251
## `@_assemblyVision`
4352

4453
Forces emission of assembly vision remarks for a function or method, showing

include/swift/AST/Attr.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,12 @@ DECL_ATTR(exclusivity, Exclusivity,
713713
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
714714
128)
715715

716+
DECL_ATTR(_backDeploy, BackDeploy,
717+
OnAbstractFunction |
718+
AllowMultipleAttributes | LongAttribute | UserInaccessible |
719+
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIBreakingToRemove,
720+
129)
721+
716722
// If you're adding a new underscored attribute here, please document it in
717723
// docs/ReferenceGuides/UnderscoredAttributes.md.
718724

include/swift/AST/Attr.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2172,6 +2172,30 @@ class UnavailableFromAsyncAttr : public DeclAttribute {
21722172
}
21732173
};
21742174

2175+
/// The @_backDeploy(...) attribute, used to make function declarations available
2176+
/// for back deployment to older OSes via emission into the client binary.
2177+
class BackDeployAttr: public DeclAttribute {
2178+
public:
2179+
BackDeployAttr(SourceLoc AtLoc, SourceRange Range,
2180+
PlatformKind Platform,
2181+
const llvm::VersionTuple Version,
2182+
bool Implicit)
2183+
: DeclAttribute(DAK_BackDeploy, AtLoc, Range, Implicit),
2184+
Platform(Platform),
2185+
Version(Version) {}
2186+
2187+
/// The platform the symbol is available for back deployment on.
2188+
const PlatformKind Platform;
2189+
2190+
/// The earliest platform version that may use the back deployed implementation.
2191+
const llvm::VersionTuple Version;
2192+
2193+
static bool classof(const DeclAttribute *DA) {
2194+
return DA->getKind() == DAK_BackDeploy;
2195+
}
2196+
};
2197+
2198+
21752199
/// Attributes that may be applied to declarations.
21762200
class DeclAttributes {
21772201
/// Linked list of declaration attributes.

include/swift/AST/DiagnosticsParse.def

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,6 +1531,15 @@ WARNING(attr_availability_nonspecific_platform_unexpected_version,none,
15311531
"unexpected version number in '%0' attribute for non-specific platform "
15321532
"'*'", (StringRef))
15331533

1534+
WARNING(attr_availability_wildcard_ignored,none,
1535+
"* as platform name has no effect in '%0' attribute", (StringRef))
1536+
1537+
ERROR(attr_availability_need_platform_version,none,
1538+
"expected at least one platform version in in '%0' attribute", (StringRef))
1539+
1540+
WARNING(attr_availability_platform_version_major_minor_only,none,
1541+
"'%0' only uses major and minor version number", (StringRef))
1542+
15341543
// availability macro
15351544
ERROR(attr_availability_wildcard_in_macro, none,
15361545
"future platforms identified by '*' cannot be used in "
@@ -1548,12 +1557,15 @@ ERROR(attr_availability_duplicate,none,
15481557
(StringRef, StringRef))
15491558

15501559
// originallyDefinedIn
1560+
// FIXME: Refactor to share between attributes
15511561
ERROR(originally_defined_in_missing_rparen,none,
15521562
"expected ')' in @_originallyDefinedIn argument list", ())
15531563

1564+
// FIXME: Refactor to share between attributes
15541565
ERROR(originally_defined_in_unrecognized_platform,none,
15551566
"unrecognized platform name in @_originallyDefinedIn argument list", ())
15561567

1568+
// FIXME: This is unused and can be removed
15571569
ERROR(originally_defined_in_unrecognized_property,none,
15581570
"unrecognized property in @_originallyDefinedIn argument list", ())
15591571

@@ -1564,15 +1576,19 @@ ERROR(originally_defined_in_need_original_module_name,none,
15641576
ERROR(originally_defined_in_need_nonempty_module_name,none,
15651577
"original module name cannot be empty in @_originallyDefinedIn", ())
15661578

1579+
// FIXME: Refactor to share between attributes
15671580
ERROR(originally_defined_in_need_platform_version,none,
15681581
"expected at least one platform version in @_originallyDefinedIn", ())
15691582

1583+
// FIXME: Refactor to share between attributes
15701584
WARNING(originally_defined_in_major_minor_only,none,
15711585
"@_originallyDefinedIn only uses major and minor version number", ())
15721586

1587+
// FIXME: Refactor to share between attributes
15731588
WARNING(originally_defined_in_missing_platform_name,none,
15741589
"* as platform name has no effect", ())
15751590

1591+
// FIXME: Refactor to share between attributes
15761592
WARNING(originally_defined_in_swift_version, none,
15771593
"Swift language version checks has no effect "
15781594
"in @_originallyDefinedIn", ())
@@ -1581,6 +1597,10 @@ WARNING(originally_defined_in_package_description, none,
15811597
"PackageDescription version checks has no effect "
15821598
"in @_originallyDefinedIn", ())
15831599

1600+
// backDeploy
1601+
ERROR(attr_back_deploy_missing_rparen,none,
1602+
"expected ')' in '@_backDeploy' argument list", ())
1603+
15841604
// convention
15851605
ERROR(convention_attribute_expected_lparen,none,
15861606
"expected '(' after 'convention' attribute", ())

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,18 +1597,21 @@ WARNING(option_set_zero_constant,none,
15971597
NOTE(option_set_empty_set_init,none,
15981598
"use [] to silence this warning", ())
15991599

1600+
// FIXME: Refactor to share between attributes
16001601
ERROR(originally_defined_in_dupe_platform,none,
16011602
"duplicate version number for platform %0", (StringRef))
16021603

16031604
ERROR(originally_definedin_topleve_decl,none,
16041605
"@%0 is only applicable to top-level decl", (StringRef))
16051606

1607+
// FIXME: Refactor to share between attributes
16061608
ERROR(originally_definedin_need_available,none,
16071609
"need @available attribute for @%0", (StringRef))
16081610

16091611
ERROR(originally_definedin_must_not_before_available_version,none,
16101612
"symbols are moved to the current module before they were available in the OSs", (StringRef))
16111613

1614+
// FIXME: Refactor to share between attributes
16121615
WARNING(originally_defined_in_on_non_public,
16131616
none, "@%0 does not have any effect on "
16141617
"%select{private|fileprivate|internal|%error|%error}1 declarations",

lib/AST/Attr.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,16 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
11881188
break;
11891189
}
11901190

1191+
case DAK_BackDeploy: {
1192+
Printer.printAttrName("@_backDeploy");
1193+
Printer << "(";
1194+
auto Attr = cast<BackDeployAttr>(this);
1195+
Printer << platformString(Attr->Platform) << " " <<
1196+
Attr->Version.getAsString();
1197+
Printer << ")";
1198+
break;
1199+
}
1200+
11911201
case DAK_Count:
11921202
llvm_unreachable("exceed declaration attribute kinds");
11931203

@@ -1356,6 +1366,8 @@ StringRef DeclAttribute::getAttrName() const {
13561366
return "_typeSequence";
13571367
case DAK_UnavailableFromAsync:
13581368
return "_unavailableFromAsync";
1369+
case DAK_BackDeploy:
1370+
return "_backDeploy";
13591371
}
13601372
llvm_unreachable("bad DeclAttrKind");
13611373
}

lib/Parse/ParseDecl.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2855,6 +2855,85 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
28552855
message, AtLoc, SourceRange(Loc, Tok.getLoc()), false));
28562856
break;
28572857
}
2858+
case DAK_BackDeploy: {
2859+
auto LeftLoc = Tok.getLoc();
2860+
if (!consumeIf(tok::l_paren)) {
2861+
diagnose(Loc, diag::attr_expected_lparen, AttrName,
2862+
DeclAttribute::isDeclModifier(DK));
2863+
return false;
2864+
}
2865+
SourceLoc RightLoc;
2866+
bool SuppressLaterDiags = false;
2867+
llvm::SmallVector<std::pair<PlatformKind, llvm::VersionTuple>, 4>
2868+
PlatformAndVersions;
2869+
2870+
StringRef AttrName = "@_backDeploy";
2871+
if (parseList(tok::r_paren, LeftLoc, RightLoc, false,
2872+
diag::attr_back_deploy_missing_rparen,
2873+
SyntaxKind::Unknown, [&]() -> ParserStatus {
2874+
// FIXME(backDeploy): Parse availability macros (e.g. SwiftStdlib: 5.1)
2875+
2876+
// Parse a platform and version tuple (e.g. 'macOS 13.13').
2877+
if ((Tok.is(tok::identifier) || Tok.is(tok::oper_binary_spaced)) &&
2878+
(peekToken().is(tok::floating_literal) ||
2879+
peekToken().is(tok::integer_literal))) {
2880+
PlatformKind Platform;
2881+
// Parse platform name.
2882+
auto Plat = platformFromString(Tok.getText());
2883+
if (!Plat.hasValue()) {
2884+
diagnose(Tok.getLoc(), diag::attr_availability_unknown_platform,
2885+
Tok.getText(), AttrName);
2886+
SuppressLaterDiags = true;
2887+
return makeParserError();
2888+
} else {
2889+
consumeToken();
2890+
Platform = *Plat;
2891+
}
2892+
// Parse version number
2893+
llvm::VersionTuple VerTuple;
2894+
SourceRange VersionRange;
2895+
if (parseVersionTuple(VerTuple, VersionRange,
2896+
Diagnostic(diag::attr_availability_expected_version, AttrName))) {
2897+
SuppressLaterDiags = true;
2898+
return makeParserError();
2899+
} else {
2900+
if (VerTuple.getSubminor().hasValue() ||
2901+
VerTuple.getBuild().hasValue()) {
2902+
diagnose(Tok.getLoc(),
2903+
diag::attr_availability_platform_version_major_minor_only,
2904+
AttrName);
2905+
}
2906+
// * as platform name isn't supported.
2907+
if (Platform == PlatformKind::none) {
2908+
diagnose(AtLoc, diag::attr_availability_wildcard_ignored, AttrName);
2909+
} else {
2910+
PlatformAndVersions.emplace_back(Platform, VerTuple);
2911+
}
2912+
return makeParserSuccess();
2913+
}
2914+
}
2915+
diagnose(AtLoc, diag::attr_availability_need_platform_version, AttrName);
2916+
SuppressLaterDiags = true;
2917+
return makeParserError();
2918+
}).isErrorOrHasCompletion() || SuppressLaterDiags) {
2919+
return false;
2920+
}
2921+
2922+
if (PlatformAndVersions.empty()) {
2923+
diagnose(AtLoc, diag::attr_availability_need_platform_version, AttrName);
2924+
return false;
2925+
}
2926+
2927+
assert(!PlatformAndVersions.empty());
2928+
AttrRange = SourceRange(Loc, Tok.getLoc());
2929+
for (auto &Item: PlatformAndVersions) {
2930+
Attributes.add(new (Context) BackDeployAttr(AtLoc, AttrRange,
2931+
Item.first,
2932+
Item.second,
2933+
/*IsImplicit*/false));
2934+
}
2935+
break;
2936+
}
28582937
}
28592938

28602939
if (DuplicateAttribute) {

lib/Sema/TypeCheckAttr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
118118
IGNORED_ATTR(InheritActorContext)
119119
IGNORED_ATTR(Isolated)
120120
IGNORED_ATTR(Preconcurrency)
121+
IGNORED_ATTR(BackDeploy)
121122
#undef IGNORED_ATTR
122123

123124
void visitAlignmentAttr(AlignmentAttr *attr) {
@@ -275,6 +276,8 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
275276
void visitUnavailableFromAsyncAttr(UnavailableFromAsyncAttr *attr);
276277

277278
void visitPrimaryAssociatedTypeAttr(PrimaryAssociatedTypeAttr *attr);
279+
280+
void checkBackDeployAttrs(Decl *D, ArrayRef<BackDeployAttr *> Attrs);
278281
};
279282

280283
} // end anonymous namespace
@@ -3460,6 +3463,11 @@ void AttributeChecker::checkOriginalDefinedInAttrs(Decl *D,
34603463
}
34613464
}
34623465

3466+
void AttributeChecker::checkBackDeployAttrs(Decl *D,
3467+
ArrayRef<BackDeployAttr *> Attrs) {
3468+
// FIXME(backDeploy): Diagnose incompatible uses of `@_backDeploy
3469+
}
3470+
34633471
Type TypeChecker::checkReferenceOwnershipAttr(VarDecl *var, Type type,
34643472
ReferenceOwnershipAttr *attr) {
34653473
auto &Diags = var->getASTContext().Diags;

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,6 +1567,8 @@ namespace {
15671567

15681568
UNINTERESTING_ATTR(PrimaryAssociatedType)
15691569

1570+
UNINTERESTING_ATTR(BackDeploy)
1571+
15701572
#undef UNINTERESTING_ATTR
15711573

15721574
void visitAvailableAttr(AvailableAttr *attr) {

lib/Serialization/Deserialization.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4772,6 +4772,21 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() {
47724772
break;
47734773
}
47744774

4775+
case decls_block::BackDeploy_DECL_ATTR: {
4776+
bool isImplicit;
4777+
unsigned Platform;
4778+
DEF_VER_TUPLE_PIECES(Version);
4779+
serialization::decls_block::BackDeployDeclAttrLayout::readRecord(
4780+
scratch, isImplicit, LIST_VER_TUPLE_PIECES(Version), Platform);
4781+
llvm::VersionTuple Version;
4782+
DECODE_VER_TUPLE(Version)
4783+
Attr = new (ctx) BackDeployAttr(SourceLoc(), SourceRange(),
4784+
(PlatformKind)Platform,
4785+
Version,
4786+
isImplicit);
4787+
break;
4788+
}
4789+
47754790
#define SIMPLE_DECL_ATTR(NAME, CLASS, ...) \
47764791
case decls_block::CLASS##_DECL_ATTR: { \
47774792
bool isImplicit; \

0 commit comments

Comments
 (0)