Skip to content

Commit 78560c7

Browse files
authored
Merge pull request #18895 from dingobye/sr8598
[Parser] Improve diagnostics for special platforms in available attribute.
2 parents 468d9c3 + 033f6ac commit 78560c7

File tree

5 files changed

+107
-19
lines changed

5 files changed

+107
-19
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,20 @@ ERROR(attr_availability_expected_equal,none,
13281328
ERROR(attr_availability_expected_version,none,
13291329
"expected version number in '%0' attribute", (StringRef))
13301330

1331+
WARNING(attr_availability_swift_expected_option,none,
1332+
"expected 'introduced', 'deprecated', or 'obsoleted' in '%0' attribute "
1333+
"for platform 'swift'", (StringRef))
1334+
WARNING(attr_availability_swift_expected_deprecated_version,none,
1335+
"expected version number with 'deprecated' in '%0' attribute for "
1336+
"platform 'swift'", (StringRef))
1337+
WARNING(attr_availability_swift_infeasible_option,none,
1338+
"'%0' cannot be used in '%1' attribute for platform 'swift'",
1339+
(StringRef, StringRef))
1340+
1341+
WARNING(attr_availability_nonspecific_platform_unexpected_version,none,
1342+
"unexpected version number in '%0' attribute for non-specific platform "
1343+
"'*'", (StringRef))
1344+
13311345
// autoclosure
13321346
ERROR(attr_autoclosure_expected_r_paren,PointsToFirstBadToken,
13331347
"expected ')' in @autoclosure", ())

lib/Parse/ParseDecl.cpp

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -315,11 +315,19 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
315315
return true;
316316
};
317317

318+
struct VersionArg {
319+
llvm::VersionTuple Version;
320+
SourceRange Range;
321+
SourceLoc DelimiterLoc;
322+
bool empty() const {
323+
return Version.empty();
324+
}
325+
};
326+
318327
StringRef Platform = Tok.getText();
319328

320329
StringRef Message, Renamed;
321-
llvm::VersionTuple Introduced, Deprecated, Obsoleted;
322-
SourceRange IntroducedRange, DeprecatedRange, ObsoletedRange;
330+
VersionArg Introduced, Deprecated, Obsoleted;
323331
auto PlatformAgnostic = PlatformAgnosticAvailabilityKind::None;
324332

325333
SyntaxParsingContext AvailabilitySpecContext(
@@ -443,7 +451,9 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
443451
case IsIntroduced:
444452
case IsObsoleted: {
445453
// Items with version arguments.
454+
SourceLoc DelimiterLoc;
446455
if (findAttrValueDelimiter()) {
456+
DelimiterLoc = Tok.getLoc();
447457
consumeToken();
448458
} else {
449459
diagnose(Tok, diag::attr_availability_expected_equal, AttrName,
@@ -454,24 +464,19 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
454464
break;
455465
}
456466

457-
auto &VersionArg =
467+
auto &VerArg =
458468
(ArgumentKind == IsIntroduced)
459469
? Introduced
460470
: (ArgumentKind == IsDeprecated) ? Deprecated : Obsoleted;
461471

462-
auto &VersionRange = (ArgumentKind == IsIntroduced)
463-
? IntroducedRange
464-
: (ArgumentKind == IsDeprecated)
465-
? DeprecatedRange
466-
: ObsoletedRange;
467-
468472
if (parseVersionTuple(
469-
VersionArg, VersionRange,
473+
VerArg.Version, VerArg.Range,
470474
Diagnostic(diag::attr_availability_expected_version, AttrName))) {
471475
AnyArgumentInvalid = true;
472476
if (peekToken().isAny(tok::r_paren, tok::comma))
473477
consumeToken();
474478
}
479+
VerArg.DelimiterLoc = DelimiterLoc;
475480

476481
SyntaxContext->createNodeInPlace(SyntaxKind::AvailabilityLabeledArgument);
477482

@@ -511,10 +516,26 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
511516
bool SomeVersion = (!Introduced.empty() ||
512517
!Deprecated.empty() ||
513518
!Obsoleted.empty());
514-
if (!PlatformKind.hasValue() &&
515-
Platform == "swift" &&
516-
SomeVersion &&
517-
PlatformAgnostic == PlatformAgnosticAvailabilityKind::None) {
519+
if (!PlatformKind.hasValue() && Platform == "swift") {
520+
if (PlatformAgnostic == PlatformAgnosticAvailabilityKind::Deprecated) {
521+
diagnose(AttrLoc,
522+
diag::attr_availability_swift_expected_deprecated_version,
523+
AttrName);
524+
return nullptr;
525+
}
526+
if (PlatformAgnostic == PlatformAgnosticAvailabilityKind::Unavailable) {
527+
diagnose(AttrLoc, diag::attr_availability_swift_infeasible_option,
528+
"unavailable", AttrName);
529+
return nullptr;
530+
}
531+
assert(PlatformAgnostic == PlatformAgnosticAvailabilityKind::None);
532+
533+
if (!SomeVersion) {
534+
diagnose(AttrLoc, diag::attr_availability_swift_expected_option,
535+
AttrName);
536+
return nullptr;
537+
}
538+
518539
PlatformKind = PlatformKind::none;
519540
PlatformAgnostic = PlatformAgnosticAvailabilityKind::SwiftVersionSpecific;
520541
}
@@ -528,13 +549,30 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
528549
return nullptr;
529550
}
530551

552+
// Warn if any version is specified for non-specific platform '*'.
553+
if (Platform == "*" && SomeVersion) {
554+
auto diag = diagnose(AttrLoc,
555+
diag::attr_availability_nonspecific_platform_unexpected_version,
556+
AttrName);
557+
if (!Introduced.empty())
558+
diag.fixItRemove(SourceRange(Introduced.DelimiterLoc,
559+
Introduced.Range.End));
560+
if (!Deprecated.empty())
561+
diag.fixItRemove(SourceRange(Deprecated.DelimiterLoc,
562+
Deprecated.Range.End));
563+
if (!Obsoleted.empty())
564+
diag.fixItRemove(SourceRange(Obsoleted.DelimiterLoc,
565+
Obsoleted.Range.End));
566+
return nullptr;
567+
}
568+
531569
auto Attr = new (Context)
532570
AvailableAttr(AtLoc, SourceRange(AttrLoc, Tok.getLoc()),
533571
PlatformKind.getValue(),
534572
Message, Renamed,
535-
Introduced, IntroducedRange,
536-
Deprecated, DeprecatedRange,
537-
Obsoleted, ObsoletedRange,
573+
Introduced.Version, Introduced.Range,
574+
Deprecated.Version, Deprecated.Range,
575+
Obsoleted.Version, Obsoleted.Range,
538576
PlatformAgnostic,
539577
/*Implicit=*/false);
540578
return makeParserResult(Attr);

stdlib/public/Platform/tgmath.swift.gyb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ public func remquo(_ x: ${T}, _ y: ${T}) -> (${T}, Int) {
326326
% if T == 'Float80':
327327
#if (arch(i386) || arch(x86_64)) && !os(Windows)
328328
% end
329-
@available(*, deprecated: 4.2, message:
329+
@available(swift, deprecated: 4.2, message:
330330
"use ${T}(nan: ${T}.RawSignificand) instead.")
331331
@_transparent
332332
public func nan(_ tag: String) -> ${T} {

stdlib/public/SDK/CoreGraphics/CGFloat.swift.gyb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ public func remquo(_ x: CGFloat, _ y: CGFloat) -> (CGFloat, Int) {
575575
return (CGFloat(rem), quo)
576576
}
577577

578-
@available(*, deprecated: 4.2, message:
578+
@available(swift, deprecated: 4.2, message:
579579
"use CGFloat(nan: CGFloat.RawSignificand) instead.")
580580
@_transparent
581581
public func nan(_ tag: String) -> CGFloat {

test/Parse/diagnose_availability.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,39 @@ func availableOnMultiplePlatforms() {}
2626
// expected-error@-1 {{'deprecated' can't be combined with shorthand specification 'OSX 10.0'}}
2727
// expected-error@-2 {{expected declaration}}
2828
func twoShorthandsFollowedByDeprecated() {}
29+
30+
31+
// SR-8598: Missing/wrong warning message for '*' or 'swift' platform.
32+
33+
@available(*, deprecated: 4.2)
34+
// expected-warning@-1 {{unexpected version number in 'available' attribute for non-specific platform '*'}} {{25-30=}}
35+
func allPlatformsDeprecatedVersion() {}
36+
37+
@available(*, deprecated, obsoleted: 4.2)
38+
// expected-warning@-1 {{unexpected version number in 'available' attribute for non-specific platform '*'}} {{36-41=}}
39+
func allPlatformsDeprecatedAndObsoleted() {}
40+
41+
@available(*, introduced: 4.0, deprecated: 4.1, obsoleted: 4.2)
42+
// expected-warning@-1 {{unexpected version number in 'available' attribute for non-specific platform '*'}} {{25-30=}} {{42-47=}} {{58-63=}}
43+
func allPlatformsDeprecatedAndObsoleted2() {}
44+
45+
@available(swift, unavailable)
46+
// expected-warning@-1 {{'unavailable' cannot be used in 'available' attribute for platform 'swift'}}
47+
func swiftUnavailable() {}
48+
49+
@available(swift, unavailable, introduced: 4.2)
50+
// expected-warning@-1 {{'unavailable' cannot be used in 'available' attribute for platform 'swift'}}
51+
func swiftUnavailableIntroduced() {}
52+
53+
@available(swift, deprecated)
54+
// expected-warning@-1 {{expected version number with 'deprecated' in 'available' attribute for platform 'swift'}}
55+
func swiftDeprecated() {}
56+
57+
@available(swift, deprecated, obsoleted: 4.2)
58+
// expected-warning@-1 {{expected version number with 'deprecated' in 'available' attribute for platform 'swift'}}
59+
func swiftDeprecatedObsoleted() {}
60+
61+
@available(swift, message: "missing valid option")
62+
// expected-warning@-1 {{expected 'introduced', 'deprecated', or 'obsoleted' in 'available' attribute for platform 'swift'}}
63+
func swiftMessage() {}
64+

0 commit comments

Comments
 (0)