Skip to content

Commit 76828ef

Browse files
committed
Sema: Reject version specs in @available attributes for custom domains.
1 parent 233d884 commit 76828ef

9 files changed

+62
-31
lines changed

include/swift/AST/Attr.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3319,7 +3319,7 @@ class SemanticAvailableAttr final {
33193319
return attr->getRawIntroduced();
33203320
}
33213321

3322-
/// The source range of the `introduced:` component.
3322+
/// The source range of the `introduced:` version component.
33233323
SourceRange getIntroducedSourceRange() const { return attr->IntroducedRange; }
33243324

33253325
/// Returns the effective range in which the declaration with this attribute
@@ -3331,11 +3331,17 @@ class SemanticAvailableAttr final {
33313331
return attr->getRawDeprecated();
33323332
}
33333333

3334+
/// The source range of the `deprecated:` version component.
3335+
SourceRange getDeprecatedSourceRange() const { return attr->DeprecatedRange; }
3336+
33343337
/// The version tuple written in source for the `obsoleted:` component.
33353338
std::optional<llvm::VersionTuple> getObsoleted() const {
33363339
return attr->getRawObsoleted();
33373340
}
33383341

3342+
/// The source range of the `obsoleted:` version component.
3343+
SourceRange getObsoletedSourceRange() const { return attr->ObsoletedRange; }
3344+
33393345
/// Returns the `message:` field of the attribute, or an empty string.
33403346
StringRef getMessage() const { return attr->Message; }
33413347

include/swift/AST/AvailabilityDomain.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ class AvailabilityDomain final {
190190
return PlatformKind::none;
191191
}
192192

193+
/// Returns true if availability for this domain can be specified in terms of
194+
/// version ranges.
195+
bool isVersioned() const;
196+
193197
/// Returns true if this domain is considered active in the current
194198
/// compilation context.
195199
bool isActive(const ASTContext &ctx) const;

include/swift/AST/DiagnosticsParse.def

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,10 +1579,6 @@ ERROR(attr_availability_expected_equal,none,
15791579
ERROR(attr_availability_expected_version,none,
15801580
"expected version number in '%0' attribute", (StringRef))
15811581

1582-
WARNING(attr_availability_nonspecific_platform_unexpected_version,none,
1583-
"unexpected version number in '%0' attribute for non-specific platform "
1584-
"'*'", (StringRef))
1585-
15861582
WARNING(attr_availability_wildcard_ignored,none,
15871583
"* as platform name has no effect in '%0' attribute", (StringRef))
15881584

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6735,6 +6735,9 @@ ERROR(attr_availability_requires_custom_availability, none,
67356735
"specifying '%0' in '%1' attribute requires "
67366736
"-enable-experimental-feature CustomAvailability",
67376737
(StringRef, const DeclAttribute))
6738+
WARNING(attr_availability_unexpected_version,none,
6739+
"unexpected version number in '%0' attribute for '%1'",
6740+
(const DeclAttribute, StringRef))
67386741

67396742
ERROR(availability_decl_unavailable, none,
67406743
"%0 is unavailable%select{ in %2|}1%select{|: %3}3",

lib/AST/AvailabilityDomain.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,21 @@ AvailabilityDomain::builtinDomainForString(StringRef string,
4040
return std::nullopt;
4141
}
4242

43+
bool AvailabilityDomain::isVersioned() const {
44+
switch (getKind()) {
45+
case Kind::Universal:
46+
case Kind::Embedded:
47+
return false;
48+
case Kind::SwiftLanguage:
49+
case Kind::PackageDescription:
50+
case Kind::Platform:
51+
return true;
52+
case Kind::Custom:
53+
// FIXME: [availability] Support versioned custom availability domains
54+
return false;
55+
}
56+
}
57+
4358
bool AvailabilityDomain::isActive(const ASTContext &ctx) const {
4459
switch (getKind()) {
4560
case Kind::Universal:

lib/Parse/ParseDecl.cpp

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -546,26 +546,6 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
546546
if (AnyArgumentInvalid)
547547
return nullptr;
548548

549-
// Warn if any version is specified with the universal domain ('*').
550-
bool SomeVersion = (!Introduced.empty() ||
551-
!Deprecated.empty() ||
552-
!Obsoleted.empty());
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-
569549
auto Attr = new (Context) AvailableAttr(
570550
AtLoc, SourceRange(AttrLoc, Tok.getLoc()), Platform, PlatformLoc,
571551
AttrKind, Message, Renamed, Introduced.Version, Introduced.Range,

lib/Sema/TypeCheckAttr.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8390,6 +8390,26 @@ SemanticAvailableAttrRequest::evaluate(swift::Evaluator &evaluator,
83908390
}
83918391

83928392
auto domainName = domain->getNameForAttributePrinting();
8393+
auto semanticAttr = SemanticAvailableAttr(attr);
8394+
8395+
bool hasVersionSpec =
8396+
(introducedVersion || deprecatedVersion || obsoletedVersion);
8397+
8398+
if (!domain->isVersioned() && hasVersionSpec) {
8399+
SourceRange versionSourceRange;
8400+
if (introducedVersion)
8401+
versionSourceRange = semanticAttr.getIntroducedSourceRange();
8402+
else if (deprecatedVersion)
8403+
versionSourceRange = semanticAttr.getDeprecatedSourceRange();
8404+
else if (obsoletedVersion)
8405+
versionSourceRange = semanticAttr.getObsoletedSourceRange();
8406+
8407+
diags
8408+
.diagnose(attrLoc, diag::attr_availability_unexpected_version, attr,
8409+
domainName)
8410+
.highlight(versionSourceRange);
8411+
return std::nullopt;
8412+
}
83938413

83948414
if (domain->isSwiftLanguage() || domain->isPackageDescription()) {
83958415
switch (attr->getKind()) {
@@ -8413,8 +8433,6 @@ SemanticAvailableAttrRequest::evaluate(swift::Evaluator &evaluator,
84138433
break;
84148434
}
84158435

8416-
bool hasVersionSpec =
8417-
(introducedVersion || deprecatedVersion || obsoletedVersion);
84188436
if (!hasVersionSpec) {
84198437
diags.diagnose(attrLoc, diag::attr_availability_expected_version_spec,
84208438
attrName, domainName);
@@ -8438,7 +8456,7 @@ SemanticAvailableAttrRequest::evaluate(swift::Evaluator &evaluator,
84388456
mutableAttr->setRawObsoleted(canonicalizeVersion(*obsoletedVersion));
84398457
}
84408458

8441-
return SemanticAvailableAttr(attr);
8459+
return semanticAttr;
84428460
}
84438461

84448462
template <typename ATTR>

test/Parse/diagnose_availability.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ func twoShorthandsFollowedByDeprecated() {}
3333
// Missing/wrong warning message for '*' or 'swift' platform.
3434

3535
@available(*, deprecated: 4.2)
36-
// expected-warning@-1 {{unexpected version number in 'available' attribute for non-specific platform '*'}} {{25-30=}}
36+
// expected-warning@-1 {{unexpected version number in '@available' attribute for '*'}}
3737
func allPlatformsDeprecatedVersion() {}
3838

3939
@available(*, deprecated, obsoleted: 4.2)
40-
// expected-warning@-1 {{unexpected version number in 'available' attribute for non-specific platform '*'}} {{36-41=}}
40+
// expected-warning@-1 {{unexpected version number in '@available' attribute for '*'}}
4141
func allPlatformsDeprecatedAndObsoleted() {}
4242

4343
@available(*, introduced: 4.0, deprecated: 4.1, obsoleted: 4.2)
44-
// expected-warning@-1 {{unexpected version number in 'available' attribute for non-specific platform '*'}} {{25-30=}} {{42-47=}} {{58-63=}}
44+
// expected-warning@-1 {{unexpected version number in '@available' attribute for '*'}}
4545
func allPlatformsDeprecatedAndObsoleted2() {}
4646

4747
@available(swift, unavailable)

test/attr/attr_availability_custom_domains.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@
1111
@available(EnabledDomain)
1212
func availableInEnabledDomain() { }
1313

14+
@available(EnabledDomain, introduced: 1.0) // expected-warning {{unexpected version number in '@available' attribute for 'EnabledDomain'}}
15+
func introducedInEnabledDomain() { }
16+
17+
@available(EnabledDomain, deprecated: 1.0) // expected-warning {{unexpected version number in '@available' attribute for 'EnabledDomain'}}
18+
func deprecatedInEnabledDomain() { }
19+
20+
@available(EnabledDomain, obsoleted: 1.0) // expected-warning {{unexpected version number in '@available' attribute for 'EnabledDomain'}}
21+
func obsoletedInEnabledDomain() { }
22+
1423
@available(DisabledDomain, unavailable)
1524
func unavailableInDisabledDomain() { } // expected-note {{'unavailableInDisabledDomain()' has been explicitly marked unavailable here}}
1625

0 commit comments

Comments
 (0)