diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index c5ae646c4e39b..556fe66810be4 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1328,6 +1328,20 @@ ERROR(attr_availability_expected_equal,none, ERROR(attr_availability_expected_version,none, "expected version number in '%0' attribute", (StringRef)) +WARNING(attr_availability_swift_expected_option,none, + "expected 'introduced', 'deprecated', or 'obsoleted' in '%0' attribute " + "for platform 'swift'", (StringRef)) +WARNING(attr_availability_swift_expected_deprecated_version,none, + "expected version number with 'deprecated' in '%0' attribute for " + "platform 'swift'", (StringRef)) +WARNING(attr_availability_swift_infeasible_option,none, + "'%0' cannot be used in '%1' attribute for platform 'swift'", + (StringRef, StringRef)) + +WARNING(attr_availability_nonspecific_platform_unexpected_version,none, + "unexpected version number in '%0' attribute for non-specific platform " + "'*'", (StringRef)) + // autoclosure ERROR(attr_autoclosure_expected_r_paren,PointsToFirstBadToken, "expected ')' in @autoclosure", ()) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index fa75d5437235e..ff9001a9f34ee 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -315,11 +315,19 @@ ParserResult Parser::parseExtendedAvailabilitySpecList( return true; }; + struct VersionArg { + llvm::VersionTuple Version; + SourceRange Range; + SourceLoc DelimiterLoc; + bool empty() const { + return Version.empty(); + } + }; + StringRef Platform = Tok.getText(); StringRef Message, Renamed; - llvm::VersionTuple Introduced, Deprecated, Obsoleted; - SourceRange IntroducedRange, DeprecatedRange, ObsoletedRange; + VersionArg Introduced, Deprecated, Obsoleted; auto PlatformAgnostic = PlatformAgnosticAvailabilityKind::None; SyntaxParsingContext AvailabilitySpecContext( @@ -443,7 +451,9 @@ ParserResult Parser::parseExtendedAvailabilitySpecList( case IsIntroduced: case IsObsoleted: { // Items with version arguments. + SourceLoc DelimiterLoc; if (findAttrValueDelimiter()) { + DelimiterLoc = Tok.getLoc(); consumeToken(); } else { diagnose(Tok, diag::attr_availability_expected_equal, AttrName, @@ -454,24 +464,19 @@ ParserResult Parser::parseExtendedAvailabilitySpecList( break; } - auto &VersionArg = + auto &VerArg = (ArgumentKind == IsIntroduced) ? Introduced : (ArgumentKind == IsDeprecated) ? Deprecated : Obsoleted; - auto &VersionRange = (ArgumentKind == IsIntroduced) - ? IntroducedRange - : (ArgumentKind == IsDeprecated) - ? DeprecatedRange - : ObsoletedRange; - if (parseVersionTuple( - VersionArg, VersionRange, + VerArg.Version, VerArg.Range, Diagnostic(diag::attr_availability_expected_version, AttrName))) { AnyArgumentInvalid = true; if (peekToken().isAny(tok::r_paren, tok::comma)) consumeToken(); } + VerArg.DelimiterLoc = DelimiterLoc; SyntaxContext->createNodeInPlace(SyntaxKind::AvailabilityLabeledArgument); @@ -511,10 +516,26 @@ ParserResult Parser::parseExtendedAvailabilitySpecList( bool SomeVersion = (!Introduced.empty() || !Deprecated.empty() || !Obsoleted.empty()); - if (!PlatformKind.hasValue() && - Platform == "swift" && - SomeVersion && - PlatformAgnostic == PlatformAgnosticAvailabilityKind::None) { + if (!PlatformKind.hasValue() && Platform == "swift") { + if (PlatformAgnostic == PlatformAgnosticAvailabilityKind::Deprecated) { + diagnose(AttrLoc, + diag::attr_availability_swift_expected_deprecated_version, + AttrName); + return nullptr; + } + if (PlatformAgnostic == PlatformAgnosticAvailabilityKind::Unavailable) { + diagnose(AttrLoc, diag::attr_availability_swift_infeasible_option, + "unavailable", AttrName); + return nullptr; + } + assert(PlatformAgnostic == PlatformAgnosticAvailabilityKind::None); + + if (!SomeVersion) { + diagnose(AttrLoc, diag::attr_availability_swift_expected_option, + AttrName); + return nullptr; + } + PlatformKind = PlatformKind::none; PlatformAgnostic = PlatformAgnosticAvailabilityKind::SwiftVersionSpecific; } @@ -528,13 +549,30 @@ ParserResult Parser::parseExtendedAvailabilitySpecList( return nullptr; } + // Warn if any version is specified for non-specific platform '*'. + if (Platform == "*" && SomeVersion) { + auto diag = diagnose(AttrLoc, + diag::attr_availability_nonspecific_platform_unexpected_version, + AttrName); + if (!Introduced.empty()) + diag.fixItRemove(SourceRange(Introduced.DelimiterLoc, + Introduced.Range.End)); + if (!Deprecated.empty()) + diag.fixItRemove(SourceRange(Deprecated.DelimiterLoc, + Deprecated.Range.End)); + if (!Obsoleted.empty()) + diag.fixItRemove(SourceRange(Obsoleted.DelimiterLoc, + Obsoleted.Range.End)); + return nullptr; + } + auto Attr = new (Context) AvailableAttr(AtLoc, SourceRange(AttrLoc, Tok.getLoc()), PlatformKind.getValue(), Message, Renamed, - Introduced, IntroducedRange, - Deprecated, DeprecatedRange, - Obsoleted, ObsoletedRange, + Introduced.Version, Introduced.Range, + Deprecated.Version, Deprecated.Range, + Obsoleted.Version, Obsoleted.Range, PlatformAgnostic, /*Implicit=*/false); return makeParserResult(Attr); diff --git a/stdlib/public/Platform/tgmath.swift.gyb b/stdlib/public/Platform/tgmath.swift.gyb index 9d9484f584f5d..59095ba3facd6 100644 --- a/stdlib/public/Platform/tgmath.swift.gyb +++ b/stdlib/public/Platform/tgmath.swift.gyb @@ -326,7 +326,7 @@ public func remquo(_ x: ${T}, _ y: ${T}) -> (${T}, Int) { % if T == 'Float80': #if (arch(i386) || arch(x86_64)) && !os(Windows) % end -@available(*, deprecated: 4.2, message: +@available(swift, deprecated: 4.2, message: "use ${T}(nan: ${T}.RawSignificand) instead.") @_transparent public func nan(_ tag: String) -> ${T} { diff --git a/stdlib/public/SDK/CoreGraphics/CGFloat.swift.gyb b/stdlib/public/SDK/CoreGraphics/CGFloat.swift.gyb index 2dedc1213fd8f..978c56dfc9e60 100644 --- a/stdlib/public/SDK/CoreGraphics/CGFloat.swift.gyb +++ b/stdlib/public/SDK/CoreGraphics/CGFloat.swift.gyb @@ -575,7 +575,7 @@ public func remquo(_ x: CGFloat, _ y: CGFloat) -> (CGFloat, Int) { return (CGFloat(rem), quo) } -@available(*, deprecated: 4.2, message: +@available(swift, deprecated: 4.2, message: "use CGFloat(nan: CGFloat.RawSignificand) instead.") @_transparent public func nan(_ tag: String) -> CGFloat { diff --git a/test/Parse/diagnose_availability.swift b/test/Parse/diagnose_availability.swift index 506bce9f46e22..1b35b9af90fa5 100644 --- a/test/Parse/diagnose_availability.swift +++ b/test/Parse/diagnose_availability.swift @@ -26,3 +26,39 @@ func availableOnMultiplePlatforms() {} // expected-error@-1 {{'deprecated' can't be combined with shorthand specification 'OSX 10.0'}} // expected-error@-2 {{expected declaration}} func twoShorthandsFollowedByDeprecated() {} + + +// SR-8598: Missing/wrong warning message for '*' or 'swift' platform. + +@available(*, deprecated: 4.2) +// expected-warning@-1 {{unexpected version number in 'available' attribute for non-specific platform '*'}} {{25-30=}} +func allPlatformsDeprecatedVersion() {} + +@available(*, deprecated, obsoleted: 4.2) +// expected-warning@-1 {{unexpected version number in 'available' attribute for non-specific platform '*'}} {{36-41=}} +func allPlatformsDeprecatedAndObsoleted() {} + +@available(*, introduced: 4.0, deprecated: 4.1, obsoleted: 4.2) +// expected-warning@-1 {{unexpected version number in 'available' attribute for non-specific platform '*'}} {{25-30=}} {{42-47=}} {{58-63=}} +func allPlatformsDeprecatedAndObsoleted2() {} + +@available(swift, unavailable) +// expected-warning@-1 {{'unavailable' cannot be used in 'available' attribute for platform 'swift'}} +func swiftUnavailable() {} + +@available(swift, unavailable, introduced: 4.2) +// expected-warning@-1 {{'unavailable' cannot be used in 'available' attribute for platform 'swift'}} +func swiftUnavailableIntroduced() {} + +@available(swift, deprecated) +// expected-warning@-1 {{expected version number with 'deprecated' in 'available' attribute for platform 'swift'}} +func swiftDeprecated() {} + +@available(swift, deprecated, obsoleted: 4.2) +// expected-warning@-1 {{expected version number with 'deprecated' in 'available' attribute for platform 'swift'}} +func swiftDeprecatedObsoleted() {} + +@available(swift, message: "missing valid option") +// expected-warning@-1 {{expected 'introduced', 'deprecated', or 'obsoleted' in 'available' attribute for platform 'swift'}} +func swiftMessage() {} +