Skip to content

Commit 8da37b0

Browse files
authored
Merge pull request #41734 from tshortli/accept-availability-macros-in-back-deploy-attr
Add availability macro support to @_backDeploy
2 parents 2855198 + b292512 commit 8da37b0

File tree

6 files changed

+112
-151
lines changed

6 files changed

+112
-151
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,46 +1561,16 @@ ERROR(attr_availability_duplicate,none,
15611561
(StringRef, StringRef))
15621562

15631563
// originallyDefinedIn
1564-
// FIXME(backDeploy): Refactor to share with back deployment attr
15651564
ERROR(originally_defined_in_missing_rparen,none,
15661565
"expected ')' in @_originallyDefinedIn argument list", ())
15671566

1568-
// FIXME(backDeploy): Refactor to share with back deployment attr
1569-
ERROR(originally_defined_in_unrecognized_platform,none,
1570-
"unrecognized platform name in @_originallyDefinedIn argument list", ())
1571-
1572-
// FIXME: This is unused and can be removed
1573-
ERROR(originally_defined_in_unrecognized_property,none,
1574-
"unrecognized property in @_originallyDefinedIn argument list", ())
1575-
15761567
ERROR(originally_defined_in_need_original_module_name,none,
15771568
"expected 'module: \"original\"' in the first argument to "
15781569
"@_originallyDefinedIn", ())
15791570

15801571
ERROR(originally_defined_in_need_nonempty_module_name,none,
15811572
"original module name cannot be empty in @_originallyDefinedIn", ())
15821573

1583-
// FIXME(backDeploy): Refactor to share with back deployment attr
1584-
ERROR(originally_defined_in_need_platform_version,none,
1585-
"expected at least one platform version in @_originallyDefinedIn", ())
1586-
1587-
// FIXME(backDeploy): Refactor to share with back deployment attr
1588-
WARNING(originally_defined_in_major_minor_only,none,
1589-
"@_originallyDefinedIn only uses major and minor version number", ())
1590-
1591-
// FIXME(backDeploy): Refactor to share with back deployment attr
1592-
WARNING(originally_defined_in_missing_platform_name,none,
1593-
"* as platform name has no effect", ())
1594-
1595-
// FIXME(backDeploy): Refactor to share with back deployment attr
1596-
WARNING(originally_defined_in_swift_version, none,
1597-
"Swift language version checks has no effect "
1598-
"in @_originallyDefinedIn", ())
1599-
1600-
WARNING(originally_defined_in_package_description, none,
1601-
"PackageDescription version checks has no effect "
1602-
"in @_originallyDefinedIn", ())
1603-
16041574
// backDeploy
16051575
ERROR(attr_back_deploy_missing_rparen,none,
16061576
"expected ')' in '@_backDeploy' argument list", ())

lib/Parse/ParseDecl.cpp

Lines changed: 50 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,34 +1743,59 @@ void Parser::parseAllAvailabilityMacroArguments() {
17431743

17441744
ParserStatus Parser::parsePlatformVersionInList(StringRef AttrName,
17451745
llvm::SmallVector<PlatformAndVersion, 4> &PlatformAndVersions) {
1746-
// FIXME(backDeploy): Parse availability macros (e.g. SwiftStdlib: 5.1)
17471746
SyntaxParsingContext argumentContext(SyntaxContext,
17481747
SyntaxKind::AvailabilityVersionRestriction);
17491748

1749+
// Check for availability macros first.
1750+
if (peekAvailabilityMacroName()) {
1751+
SmallVector<AvailabilitySpec *, 4> Specs;
1752+
ParserStatus MacroStatus = parseAvailabilityMacro(Specs);
1753+
if (MacroStatus.isError())
1754+
return MacroStatus;
1755+
1756+
for (auto *Spec : Specs) {
1757+
auto *PlatformVersionSpec =
1758+
dyn_cast<PlatformVersionConstraintAvailabilitySpec>(Spec);
1759+
// Since peekAvailabilityMacroName() only matches defined availability
1760+
// macros, we don't expect to get any other kind of spec here.
1761+
assert(PlatformVersionSpec && "Unexpected AvailabilitySpec kind");
1762+
1763+
auto Platform = PlatformVersionSpec->getPlatform();
1764+
auto Version = PlatformVersionSpec->getVersion();
1765+
if (Version.getSubminor().hasValue() || Version.getBuild().hasValue()) {
1766+
diagnose(PlatformVersionSpec->getVersionSrcRange().Start,
1767+
diag::attr_availability_platform_version_major_minor_only,
1768+
AttrName);
1769+
}
1770+
PlatformAndVersions.emplace_back(Platform, Version);
1771+
}
1772+
1773+
return makeParserSuccess();
1774+
}
1775+
17501776
// Expect a possible platform name (e.g. 'macOS' or '*').
17511777
if (!Tok.isAny(tok::identifier, tok::oper_binary_spaced)) {
17521778
diagnose(Tok, diag::attr_availability_expected_platform, AttrName);
17531779
return makeParserError();
17541780
}
17551781

17561782
// Parse the platform name.
1757-
auto MaybePlatform = platformFromString(Tok.getText());
1783+
StringRef platformText = Tok.getText();
1784+
auto MaybePlatform = platformFromString(platformText);
17581785
SourceLoc PlatformLoc = Tok.getLoc();
1759-
if (!MaybePlatform.hasValue()) {
1760-
diagnose(PlatformLoc, diag::attr_availability_unknown_platform,
1761-
Tok.getText(), AttrName);
1762-
return makeParserError();
1763-
}
17641786
consumeToken();
1765-
PlatformKind Platform = *MaybePlatform;
17661787

1767-
// Wildcards ('*') aren't supported in this kind of list. If this list
1768-
// entry is just a wildcard, skip it. Wildcards with a version are
1769-
// diagnosed below.
1770-
if (Platform == PlatformKind::none && Tok.isAny(tok::comma, tok::r_paren)) {
1788+
if (!MaybePlatform.hasValue()) {
1789+
diagnose(PlatformLoc, diag::attr_availability_unknown_platform,
1790+
platformText, AttrName);
1791+
} else if (*MaybePlatform == PlatformKind::none) {
1792+
// Wildcards ('*') aren't supported in this kind of list.
17711793
diagnose(PlatformLoc, diag::attr_availability_wildcard_ignored,
17721794
AttrName);
1773-
return makeParserSuccess();
1795+
1796+
// If this list entry is just a wildcard, skip it.
1797+
if (Tok.isAny(tok::comma, tok::r_paren))
1798+
return makeParserSuccess();
17741799
}
17751800

17761801
// Parse version number.
@@ -1789,13 +1814,13 @@ ParserStatus Parser::parsePlatformVersionInList(StringRef AttrName,
17891814
AttrName);
17901815
}
17911816

1792-
// Wildcards ('*') aren't supported in this kind of list.
1793-
if (Platform == PlatformKind::none) {
1794-
diagnose(PlatformLoc, diag::attr_availability_wildcard_ignored,
1795-
AttrName);
1796-
} else {
1797-
PlatformAndVersions.emplace_back(Platform, VerTuple);
1817+
if (MaybePlatform.hasValue()) {
1818+
auto Platform = *MaybePlatform;
1819+
if (Platform != PlatformKind::none) {
1820+
PlatformAndVersions.emplace_back(Platform, VerTuple);
1821+
}
17981822
}
1823+
17991824
return makeParserSuccess();
18001825
}
18011826

@@ -2448,91 +2473,11 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
24482473
}
24492474
// Parse 'OSX 13.13'.
24502475
case NextSegmentKind::PlatformVersion: {
2451-
SyntaxParsingContext argumentContext(SyntaxContext,
2452-
SyntaxKind::AvailabilityVersionRestriction);
2453-
if ((Tok.is(tok::identifier) || Tok.is(tok::oper_binary_spaced)) &&
2454-
(peekToken().isAny(tok::integer_literal, tok::floating_literal) ||
2455-
peekAvailabilityMacroName())) {
2456-
2457-
PlatformKind Platform;
2458-
2459-
if (peekAvailabilityMacroName()) {
2460-
// Handle availability macros first.
2461-
//
2462-
// The logic to search for macros and platform name could
2463-
// likely be handled by parseAvailabilitySpecList
2464-
// if we don't rely on parseList here.
2465-
SmallVector<AvailabilitySpec *, 4> Specs;
2466-
ParserStatus MacroStatus = parseAvailabilityMacro(Specs);
2467-
if (MacroStatus.isError())
2468-
return MacroStatus;
2469-
2470-
for (auto *Spec : Specs) {
2471-
if (auto *PlatformVersionSpec =
2472-
dyn_cast<PlatformVersionConstraintAvailabilitySpec>(Spec)) {
2473-
auto Platform = PlatformVersionSpec->getPlatform();
2474-
auto Version = PlatformVersionSpec->getVersion();
2475-
if (Version.getSubminor().hasValue() ||
2476-
Version.getBuild().hasValue()) {
2477-
diagnose(Tok.getLoc(), diag::originally_defined_in_major_minor_only);
2478-
}
2479-
PlatformAndVersions.emplace_back(Platform, Version);
2480-
2481-
} else if (auto *PlatformAgnostic =
2482-
dyn_cast<PlatformAgnosticVersionConstraintAvailabilitySpec>(Spec)) {
2483-
diagnose(PlatformAgnostic->getPlatformAgnosticNameLoc(),
2484-
PlatformAgnostic->isLanguageVersionSpecific() ?
2485-
diag::originally_defined_in_swift_version :
2486-
diag::originally_defined_in_package_description);
2487-
2488-
} else if (auto *OtherPlatform =
2489-
dyn_cast<OtherPlatformAvailabilitySpec>(Spec)) {
2490-
diagnose(OtherPlatform->getStarLoc(),
2491-
diag::originally_defined_in_missing_platform_name);
2492-
2493-
} else {
2494-
llvm_unreachable("Unexpected AvailabilitySpec kind.");
2495-
}
2496-
}
2497-
2498-
return makeParserSuccess();
2499-
}
2500-
2501-
// Parse platform name.
2502-
auto Plat = platformFromString(Tok.getText());
2503-
if (!Plat.hasValue()) {
2504-
diagnose(Tok.getLoc(),
2505-
diag::originally_defined_in_unrecognized_platform);
2506-
SuppressLaterDiags = true;
2507-
return makeParserError();
2508-
} else {
2509-
consumeToken();
2510-
Platform = *Plat;
2511-
}
2512-
// Parse version number
2513-
llvm::VersionTuple VerTuple;
2514-
SourceRange VersionRange;
2515-
if (parseVersionTuple(VerTuple, VersionRange,
2516-
Diagnostic(diag::attr_availability_expected_version, AttrName))) {
2517-
SuppressLaterDiags = true;
2518-
return makeParserError();
2519-
} else {
2520-
if (VerTuple.getSubminor().hasValue() ||
2521-
VerTuple.getBuild().hasValue()) {
2522-
diagnose(Tok.getLoc(), diag::originally_defined_in_major_minor_only);
2523-
}
2524-
// * as platform name isn't supported.
2525-
if (Platform == PlatformKind::none) {
2526-
diagnose(AtLoc, diag::originally_defined_in_missing_platform_name);
2527-
} else {
2528-
PlatformAndVersions.emplace_back(Platform, VerTuple);
2529-
}
2530-
return makeParserSuccess();
2531-
}
2532-
}
2533-
diagnose(AtLoc, diag::originally_defined_in_need_platform_version);
2534-
SuppressLaterDiags = true;
2535-
return makeParserError();
2476+
ParserStatus ListItemStatus =
2477+
parsePlatformVersionInList(AttrName, PlatformAndVersions);
2478+
if (ListItemStatus.isErrorOrHasCompletion())
2479+
SuppressLaterDiags = true;
2480+
return ListItemStatus;
25362481
}
25372482
}
25382483
llvm_unreachable("invalid next segment kind");
@@ -2544,7 +2489,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
25442489
return false;
25452490
}
25462491
if (PlatformAndVersions.empty()) {
2547-
diagnose(AtLoc, diag::originally_defined_in_need_platform_version);
2492+
diagnose(AtLoc, diag::attr_availability_need_platform_version, AttrName);
25482493
return false;
25492494
}
25502495

test/ModuleInterface/back-deploy-attr.swift

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,19 @@
22

33
// Ensure @_backDeploy attributes and function bodies are printed in
44
// swiftinterface files.
5-
// RUN: %target-swiftc_driver -emit-module -o %t/Test.swiftmodule -emit-module-interface-path %t/Test.swiftinterface -enable-library-evolution -verify-emitted-module-interface -module-name Test %s
5+
// RUN: %target-swiftc_driver -emit-module -o %t/Test.swiftmodule -emit-module-interface-path %t/Test.swiftinterface %s -enable-library-evolution -verify-emitted-module-interface -module-name Test \
6+
// RUN: -Xfrontend -define-availability -Xfrontend "_macOS12_1:macOS 12.1" \
7+
// RUN: -Xfrontend -define-availability -Xfrontend "_myProject 1.0:macOS 12.1, iOS 15.1"
68
// RUN: %FileCheck %s --check-prefix FROMSOURCE --check-prefix CHECK < %t/Test.swiftinterface
79

810
// FIXME(backDeploy): Remove this step in favor of a test that exercises using
911
// a back deployed API from a test library so that we can avoid -merge-modules
1012

1113
// Ensure @_backDeploy attributes and function bodies are present after
1214
// deserializing .swiftmodule files.
13-
// RUN: %target-swift-frontend -emit-module -o /dev/null -merge-modules %t/Test.swiftmodule -disable-objc-attr-requires-foundation-module -emit-module-interface-path %t/TestFromModule.swiftinterface -module-name Test
15+
// RUN: %target-swift-frontend -emit-module -o /dev/null -merge-modules %t/Test.swiftmodule -disable-objc-attr-requires-foundation-module -emit-module-interface-path %t/TestFromModule.swiftinterface -module-name Test \
16+
// RUN: -define-availability "_macOS12_1:macOS 12.1" \
17+
// RUN: -define-availability "_myProject 1.0:macOS 12.1, iOS 15.1"
1418
// RUN: %FileCheck %s --check-prefix FROMMODULE --check-prefix CHECK < %t/TestFromModule.swiftinterface
1519

1620
public struct TopLevelStruct {
@@ -66,10 +70,25 @@ public struct TopLevelStruct {
6670
}
6771

6872
// CHECK: @_backDeploy(macOS 12.0)
69-
// FROMSOURCE: public func backDeployTopLevelFunc() -> Swift.Int { return 47 }
70-
// FROMMODULE: public func backDeployTopLevelFunc() -> Swift.Int
73+
// FROMSOURCE: public func backDeployTopLevelFunc1() -> Swift.Int { return 47 }
74+
// FROMMODULE: public func backDeployTopLevelFunc1() -> Swift.Int
7175
@available(macOS 11.0, *)
7276
@_backDeploy(macOS 12.0)
73-
public func backDeployTopLevelFunc() -> Int { return 47 }
77+
public func backDeployTopLevelFunc1() -> Int { return 47 }
7478

75-
// FIXME(backDeploy): Availability macros should be supported
79+
// MARK: - Availability macros
80+
81+
// CHECK: @_backDeploy(macOS 12.1)
82+
// FROMSOURCE: public func backDeployTopLevelFunc2() -> Swift.Int { return 48 }
83+
// FROMMODULE: public func backDeployTopLevelFunc2() -> Swift.Int
84+
@available(macOS 11.0, *)
85+
@_backDeploy(_macOS12_1)
86+
public func backDeployTopLevelFunc2() -> Int { return 48 }
87+
88+
// CHECK: @_backDeploy(macOS 12.1)
89+
// CHECK: @_backDeploy(iOS 15.1)
90+
// FROMSOURCE: public func backDeployTopLevelFunc3() -> Swift.Int { return 49 }
91+
// FROMMODULE: public func backDeployTopLevelFunc3() -> Swift.Int
92+
@available(macOS 11.0, iOS 14.0, *)
93+
@_backDeploy(_myProject 1.0)
94+
public func backDeployTopLevelFunc3() -> Int { return 49 }

test/Parse/original_defined_in_attr.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,21 @@ public func foo() {}
77
@_originallyDefinedIn(modulename: "foo", OSX 13.13) // expected-error {{expected 'module: "original"' in the first argument to @_originallyDefinedIn}}
88
public func foo1() {}
99

10-
@_originallyDefinedIn(module: "foo", OSX 13.13.3) // expected-warning {{@_originallyDefinedIn only uses major and minor version number}} expected-error {{'@_originallyDefinedIn' requires that 'ToplevelClass' have explicit availability for macOS}}
10+
@_originallyDefinedIn(module: "foo", OSX 13.13.3) // expected-warning {{'@_originallyDefinedIn' only uses major and minor version number}}
11+
// expected-error@-1 {{'@_originallyDefinedIn' requires that 'ToplevelClass' have explicit availability for macOS}}
1112
public class ToplevelClass {}
1213

13-
@_originallyDefinedIn(module: "foo") // expected-error {{expected at least one platform version in @_originallyDefinedIn}}
14+
@_originallyDefinedIn(module: "foo") // expected-error {{expected at least one platform version in '@_originallyDefinedIn' attribute}}
1415
public class ToplevelClass1 {}
1516

1617
@_originallyDefinedIn(OSX 13.13.3) // expected-error {{expected 'module: "original"' in the first argument to @_originallyDefinedIn}}
1718
public class ToplevelClass2 {}
1819

19-
@_originallyDefinedIn(module: "foo", // expected-error {{expected at least one platform version in @_originallyDefinedIn}}
20-
public class ToplevelClass3 {}
20+
@_originallyDefinedIn(module: "foo",
21+
public class ToplevelClass3 {} // expected-error {{expected platform in '@_originallyDefinedIn' attribute}}
2122
2223
@available(OSX 13.10, *)
23-
@_originallyDefinedIn(module: "foo", * 13.13) // expected-warning {{* as platform name has no effect}} expected-error {{expected at least one platform version in @_originallyDefinedIn}}
24+
@_originallyDefinedIn(module: "foo", * 13.13) // expected-warning {{* as platform name has no effect}} expected-error {{expected at least one platform version in '@_originallyDefinedIn' attribute}}
2425
@_originallyDefinedIn(module: "foo", OSX 13.13, iOS 7.0)
2526
@_originallyDefinedIn(module: "foo", OSX 13.14, * 7.0) // expected-warning {{* as platform name has no effect}} expected-error {{'@_originallyDefinedIn' contains multiple versions for macOS}}
2627
public class ToplevelClass4 {

test/Sema/diag_originally_definedin.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,16 @@ public class C {
1717
public class D {}
1818

1919
@available(macOS 10.9, *)
20-
@_originallyDefinedIn(module: "original", _myProject 2.0) // expected-error {{expected at least one platform version in @_originallyDefinedIn}}
21-
// expected-error @-1 {{reference to undefined version '2.0' for availability macro '_myProject'}}
20+
@_originallyDefinedIn(module: "original", _myProject 2.0) // expected-error {{reference to undefined version '2.0' for availability macro '_myProject'}}
2221
public func macroVersionned() {}
2322

2423
// Fallback to the default diagnostic when the macro is unknown.
2524
@available(macOS 10.9, *)
26-
@_originallyDefinedIn(module: "original", _unknownMacro) // expected-error {{expected at least one platform version in @_originallyDefinedIn}}
25+
@_originallyDefinedIn(module: "original", _unknownMacro) // expected-warning {{unknown platform '_unknownMacro' for attribute '@_originallyDefinedIn'}}
26+
// expected-error@-1 {{expected version number in '@_originallyDefinedIn' attribute}}
2727
public func macroUnknown() {}
28+
29+
@available(macOS 10.9, *)
30+
@_originallyDefinedIn(module: "original", swift 5.1) // expected-warning {{unknown platform 'swift' for attribute '@_originallyDefinedIn'}}
31+
// expected-error@-1 {{expected at least one platform version in '@_originallyDefinedIn' attribute}}
32+
public func swiftVersionMacro() {}

test/attr/attr_backDeploy.swift

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %target-typecheck-verify-swift -parse-as-library
1+
// RUN: %target-typecheck-verify-swift -parse-as-library \
2+
// RUN: -define-availability "_myProject 2.0:macOS 12.0"
23

34
// MARK: - Valid declarations
45

@@ -192,6 +193,7 @@ public func transparentFunc() {}
192193

193194
// MARK: - Attribute parsing
194195

196+
@available(macOS 11.0, *)
195197
@_backDeploy(macOS 12.0, unknownOS 1.0) // expected-warning {{unknown platform 'unknownOS' for attribute '@_backDeploy'}}
196198
public func unknownOSFunc() {}
197199

@@ -230,8 +232,27 @@ public func trailingWildcardFunc() {}
230232
@_backDeploy(macOS 12.0, *, iOS 15.0) // expected-warning {{* as platform name has no effect in '@_backDeploy' attribute}}
231233
public func embeddedWildcardFunc() {}
232234

235+
@_backDeploy(_myProject 3.0) // expected-error {{reference to undefined version '3.0' for availability macro '_myProject'}}
236+
public func macroVersionned() {}
237+
238+
@_backDeploy(_myProject) // expected-error {{reference to undefined version '0' for availability macro '_myProject'}}
239+
public func missingMacroVersion() {}
240+
241+
// Fall back to the default diagnostic when the macro is unknown.
242+
@_backDeploy(_unknownMacro) // expected-warning {{unknown platform '_unknownMacro' for attribute '@_backDeploy'}}
243+
// expected-error@-1 {{expected version number in '@_backDeploy' attribute}}
244+
public func unknownMacroMissingVersion() {}
245+
246+
@_backDeploy(_unknownMacro 1.0) // expected-warning {{unknown platform '_unknownMacro' for attribute '@_backDeploy'}}
247+
// expected-error@-1 {{expected at least one platform version in '@_backDeploy' attribute}}
248+
public func unknownMacroVersionned() {}
249+
250+
@available(macOS 11.0, *)
251+
@_backDeploy(_unknownMacro 1.0, _myProject 2.0) // expected-warning {{unknown platform '_unknownMacro' for attribute '@_backDeploy'}}
252+
public func knownAndUnknownMacroVersionned() {}
253+
233254
@_backDeploy() // expected-error {{expected at least one platform version in '@_backDeploy' attribute}}
234-
public func zeroPlatformVersionsFunc() {}
255+
public func emptyPlatformVersionsFunc() {}
235256

236257
@_backDeploy // expected-error {{expected '(' in '_backDeploy' attribute}}
237258
public func expectedLeftParenFunc() {}

0 commit comments

Comments
 (0)