Skip to content

Commit ebfb94e

Browse files
committed
Parse: Refactor platform version tuple list parsing for @_backDeploy into a separate function and improve diagnostics.
1 parent b860e76 commit ebfb94e

File tree

4 files changed

+110
-60
lines changed

4 files changed

+110
-60
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,8 @@ WARNING(attr_availability_invalid_duplicate,none,
15031503
"'%0' argument has already been specified", (StringRef))
15041504
WARNING(attr_availability_unknown_platform,none,
15051505
"unknown platform '%0' for attribute '%1'", (StringRef, StringRef))
1506+
ERROR(attr_availability_expected_platform,none,
1507+
"expected platform in '%0' attribute", (StringRef))
15061508
ERROR(attr_availability_invalid_renamed,none,
15071509
"'renamed' argument of '%0' attribute must be an operator, identifier, "
15081510
"or full function name, optionally prefixed by a type name", (StringRef))

include/swift/Parse/Parser.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,6 +1846,16 @@ class Parser {
18461846
bool &DiscardAttribute, SourceRange &attrRange,
18471847
SourceLoc AtLoc, SourceLoc Loc,
18481848
llvm::function_ref<void(AvailableAttr *)> addAttribute);
1849+
1850+
using PlatformAndVersion = std::pair<PlatformKind, llvm::VersionTuple>;
1851+
1852+
/// Parse a platform and version tuple (e.g. "macOS 12.0") and append it to the
1853+
/// given vector. Wildcards ('*') parse successfully but are ignored. Assumes
1854+
/// that the tuples are part of a comma separated list ending with a trailing
1855+
/// ')'.
1856+
ParserStatus parsePlatformVersionInList(StringRef AttrName,
1857+
llvm::SmallVector<PlatformAndVersion, 4> &PlatformAndVersions);
1858+
18491859
//===--------------------------------------------------------------------===//
18501860
// Code completion second pass.
18511861

lib/Parse/ParseDecl.cpp

Lines changed: 73 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,6 +1738,64 @@ void Parser::parseAllAvailabilityMacroArguments() {
17381738
AvailabilityMacrosComputed = true;
17391739
}
17401740

1741+
ParserStatus Parser::parsePlatformVersionInList(StringRef AttrName,
1742+
llvm::SmallVector<PlatformAndVersion, 4> &PlatformAndVersions) {
1743+
// FIXME(backDeploy): Parse availability macros (e.g. SwiftStdlib: 5.1)
1744+
SyntaxParsingContext argumentContext(SyntaxContext,
1745+
SyntaxKind::AvailabilityVersionRestriction);
1746+
1747+
// Expect a possible platform name (e.g. 'macOS' or '*').
1748+
if (!Tok.isAny(tok::identifier, tok::oper_binary_spaced)) {
1749+
diagnose(Tok, diag::attr_availability_expected_platform, AttrName);
1750+
return makeParserError();
1751+
}
1752+
1753+
// Parse the platform name.
1754+
auto MaybePlatform = platformFromString(Tok.getText());
1755+
SourceLoc PlatformLoc = Tok.getLoc();
1756+
if (!MaybePlatform.hasValue()) {
1757+
diagnose(PlatformLoc, diag::attr_availability_unknown_platform,
1758+
Tok.getText(), AttrName);
1759+
return makeParserError();
1760+
}
1761+
consumeToken();
1762+
PlatformKind Platform = *MaybePlatform;
1763+
1764+
// Wildcards ('*') aren't supported in this kind of list. If this list
1765+
// entry is just a wildcard, skip it. Wildcards with a version are
1766+
// diagnosed below.
1767+
if (Platform == PlatformKind::none && Tok.isAny(tok::comma, tok::r_paren)) {
1768+
diagnose(PlatformLoc, diag::attr_availability_wildcard_ignored,
1769+
AttrName);
1770+
return makeParserSuccess();
1771+
}
1772+
1773+
// Parse version number.
1774+
llvm::VersionTuple VerTuple;
1775+
SourceRange VersionRange;
1776+
if (parseVersionTuple(VerTuple, VersionRange,
1777+
Diagnostic(diag::attr_availability_expected_version, AttrName))) {
1778+
return makeParserError();
1779+
}
1780+
1781+
// Diagnose specification of patch versions (e.g. '13.0.1').
1782+
if (VerTuple.getSubminor().hasValue() ||
1783+
VerTuple.getBuild().hasValue()) {
1784+
diagnose(VersionRange.Start,
1785+
diag::attr_availability_platform_version_major_minor_only,
1786+
AttrName);
1787+
}
1788+
1789+
// Wildcards ('*') aren't supported in this kind of list.
1790+
if (Platform == PlatformKind::none) {
1791+
diagnose(PlatformLoc, diag::attr_availability_wildcard_ignored,
1792+
AttrName);
1793+
} else {
1794+
PlatformAndVersions.emplace_back(Platform, VerTuple);
1795+
}
1796+
return makeParserSuccess();
1797+
}
1798+
17411799
/// Processes a parsed option name by attempting to match it to a list of
17421800
/// alternative name/value pairs provided by a chain of \c when() calls, ending
17431801
/// in either \c whenOmitted() if omitting the option is allowed, or
@@ -2862,65 +2920,27 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
28622920
DeclAttribute::isDeclModifier(DK));
28632921
return false;
28642922
}
2865-
SourceLoc RightLoc;
2923+
28662924
bool SuppressLaterDiags = false;
2867-
llvm::SmallVector<std::pair<PlatformKind, llvm::VersionTuple>, 4>
2868-
PlatformAndVersions;
2869-
2925+
SourceLoc RightLoc;
2926+
llvm::SmallVector<PlatformAndVersion, 4> PlatformAndVersions;
28702927
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) {
2928+
ParserStatus Status = parseList(tok::r_paren, LeftLoc, RightLoc, false,
2929+
diag::attr_back_deploy_missing_rparen,
2930+
SyntaxKind::Unknown, [&]() -> ParserStatus {
2931+
ParserStatus ListItemStatus =
2932+
parsePlatformVersionInList(AttrName, PlatformAndVersions);
2933+
if (ListItemStatus.isErrorOrHasCompletion())
2934+
SuppressLaterDiags = true;
2935+
return ListItemStatus;
2936+
});
2937+
2938+
if (Status.isErrorOrHasCompletion() || SuppressLaterDiags) {
29192939
return false;
29202940
}
29212941

29222942
if (PlatformAndVersions.empty()) {
2923-
diagnose(AtLoc, diag::attr_availability_need_platform_version, AttrName);
2943+
diagnose(Loc, diag::attr_availability_need_platform_version, AttrName);
29242944
return false;
29252945
}
29262946

test/attr/backDeploy.swift

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,25 @@ public var cannotBackDeployTopLevelVar = 79
6666
@_backDeploy(macOS 11.0, unknownOS 1.0) // expected-warning {{unknown platform 'unknownOS' for attribute '@_backDeploy'}}
6767
public func unknownOSFunc() {}
6868

69-
// FIXME(backDeploy): The error here should be specific about the missing version for iOS
7069
@available(macOS 12.0, *)
71-
@_backDeploy(macOS 11.0, iOS) // expected-error {{expected at least one platform version in in '@_backDeploy' attribute}}
72-
public func missingVersionForPlatformFunc() {}
70+
@_backDeploy(@) // expected-error {{expected platform in '@_backDeploy' attribute}}
71+
public func badPlatformFunc1() {}
72+
73+
@available(macOS 12.0, *)
74+
@_backDeploy(@ 12.0) // expected-error {{expected platform in '@_backDeploy' attribute}}
75+
public func badPlatformFunc2() {}
76+
77+
@available(macOS 12.0, *)
78+
@_backDeploy(macOS) // expected-error {{expected version number in '@_backDeploy' attribute}}
79+
public func missingVersionFunc1() {}
80+
81+
@available(macOS 12.0, *)
82+
@_backDeploy(macOS 11.0, iOS) // expected-error {{expected version number in '@_backDeploy' attribute}}
83+
public func missingVersionFunc2() {}
84+
85+
@available(macOS 12.0, *)
86+
@_backDeploy(macOS, iOS) // expected-error 2{{expected version number in '@_backDeploy' attribute}}
87+
public func missingVersionFunc3() {}
7388

7489
@available(macOS 12.0, *)
7590
@_backDeploy(macOS 11.0, iOS 14.0,) // expected-error {{unexpected ',' separator}}
@@ -81,12 +96,15 @@ public func patchVersionFunc() {}
8196

8297
@available(macOS 12.0, *)
8398
@_backDeploy(macOS 11.0, * 9.0) // expected-warning {{* as platform name has no effect in '@_backDeploy' attribute}}
84-
public func wildcardPlatformNameFunc() {}
99+
public func wildcardWithVersionFunc() {}
100+
101+
@available(macOS 12.0, *)
102+
@_backDeploy(macOS 11.0, *) // expected-warning {{* as platform name has no effect in '@_backDeploy' attribute}}
103+
public func trailingWildcardFunc() {}
85104

86-
// FIXME(backDeploy): The error here should be about * being ignored
87105
@available(macOS 12.0, *)
88-
@_backDeploy(macOS 11.0, *) // expected-error {{expected at least one platform version in in '@_backDeploy' attribute}}
89-
public func trailingWildcardPlatformFunc() {}
106+
@_backDeploy(macOS 11.0, *, iOS 14.0) // expected-warning {{* as platform name has no effect in '@_backDeploy' attribute}}
107+
public func embeddedWildcardFunc() {}
90108

91109
// FIXME(backDeploy): Expect error for duplicate platforms in same attribute
92110
@available(macOS 12.0, *)

0 commit comments

Comments
 (0)