Skip to content

Commit 9d5baaa

Browse files
authored
Merge pull request swiftlang#36327 from slavapestov/fix-storage-availability
Fix availability checking for stored properties and enum cases with associated values
2 parents 6ac2515 + 511ada4 commit 9d5baaa

File tree

4 files changed

+102
-41
lines changed

4 files changed

+102
-41
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5184,6 +5184,10 @@ ERROR(availability_stored_property_no_potential,
51845184
none, "stored properties cannot be marked potentially unavailable with "
51855185
"'@available'", ())
51865186

5187+
ERROR(availability_enum_element_no_potential,
5188+
none, "enum cases with associated values cannot be marked potentially unavailable with "
5189+
"'@available'", ())
5190+
51875191
ERROR(availability_protocol_requires_version,
51885192
none, "protocol %0 requires %1 to be available in %2 %3 and newer",
51895193
(Identifier, DeclName, StringRef, llvm::VersionTuple))

lib/Sema/TypeCheckAttr.cpp

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,12 +1471,6 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
14711471

14721472
SourceLoc attrLoc = attr->getLocation();
14731473

1474-
Optional<Diag<>> MaybeNotAllowed =
1475-
TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable(D);
1476-
if (MaybeNotAllowed.hasValue()) {
1477-
diagnose(attrLoc, MaybeNotAllowed.getValue());
1478-
}
1479-
14801474
// Find the innermost enclosing declaration with an availability
14811475
// range annotation and ensure that this attribute's available version range
14821476
// is fully contained within that declaration's range. If there is no such
@@ -1494,16 +1488,27 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
14941488
EnclosingDecl = getEnclosingDeclForDecl(EnclosingDecl);
14951489
}
14961490

1497-
if (!EnclosingDecl)
1498-
return;
1499-
15001491
AvailabilityContext AttrRange{
15011492
VersionRange::allGTE(attr->Introduced.getValue())};
15021493

1503-
if (!AttrRange.isContainedIn(EnclosingAnnotatedRange.getValue())) {
1504-
diagnose(attr->getLocation(), diag::availability_decl_more_than_enclosing);
1505-
diagnose(EnclosingDecl->getLoc(),
1506-
diag::availability_decl_more_than_enclosing_enclosing_here);
1494+
if (EnclosingDecl) {
1495+
if (!AttrRange.isContainedIn(EnclosingAnnotatedRange.getValue())) {
1496+
diagnose(attr->getLocation(), diag::availability_decl_more_than_enclosing);
1497+
diagnose(EnclosingDecl->getLoc(),
1498+
diag::availability_decl_more_than_enclosing_enclosing_here);
1499+
}
1500+
}
1501+
1502+
Optional<Diag<>> MaybeNotAllowed =
1503+
TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable(D);
1504+
if (MaybeNotAllowed.hasValue()) {
1505+
AvailabilityContext DeploymentRange
1506+
= AvailabilityContext::forDeploymentTarget(Ctx);
1507+
if (EnclosingAnnotatedRange.hasValue())
1508+
DeploymentRange.intersectWith(*EnclosingAnnotatedRange);
1509+
1510+
if (!DeploymentRange.isContainedIn(AttrRange))
1511+
diagnose(attrLoc, MaybeNotAllowed.getValue());
15071512
}
15081513
}
15091514

@@ -3399,31 +3404,26 @@ Type TypeChecker::checkReferenceOwnershipAttr(VarDecl *var, Type type,
33993404

34003405
Optional<Diag<>>
34013406
TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable(const Decl *D) {
3402-
DeclContext *DC = D->getDeclContext();
3403-
// Do not permit potential availability of script-mode global variables;
3404-
// their initializer expression is not lazily evaluated, so this would
3405-
// not be safe.
3406-
if (isa<VarDecl>(D) && DC->isModuleScopeContext() &&
3407-
DC->getParentSourceFile()->isScriptMode()) {
3408-
return diag::availability_global_script_no_potential;
3409-
}
3410-
3411-
// For now, we don't allow stored properties to be potentially unavailable.
3412-
// We will want to support these eventually, but we haven't figured out how
3413-
// this will interact with Definite Initialization, deinitializers and
3414-
// resilience yet.
34153407
if (auto *VD = dyn_cast<VarDecl>(D)) {
3408+
if (!VD->hasStorage())
3409+
return None;
3410+
3411+
// Do not permit potential availability of script-mode global variables;
3412+
// their initializer expression is not lazily evaluated, so this would
3413+
// not be safe.
3414+
if (VD->isTopLevelGlobal())
3415+
return diag::availability_global_script_no_potential;
3416+
34163417
// Globals and statics are lazily initialized, so they are safe
3417-
// for potential unavailability. Note that if D is a global in script
3418-
// mode (which are not lazy) then we will already have returned
3419-
// a diagnosis above.
3420-
bool lazilyInitializedStored = VD->isStatic() ||
3421-
VD->getAttrs().hasAttribute<LazyAttr>() ||
3422-
DC->isModuleScopeContext();
3423-
3424-
if (VD->hasStorage() && !lazilyInitializedStored) {
3418+
// for potential unavailability.
3419+
if (!VD->isStatic() && !VD->getDeclContext()->isModuleScopeContext())
34253420
return diag::availability_stored_property_no_potential;
3426-
}
3421+
3422+
} else if (auto *EED = dyn_cast<EnumElementDecl>(D)) {
3423+
// An enum element with an associated value cannot be potentially
3424+
// unavailable.
3425+
if (EED->hasAssociatedValues())
3426+
return diag::availability_enum_element_no_potential;
34273427
}
34283428

34293429
return None;

test/Sema/availability_stored.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
// Code should type check with a new enough deployment target:
4+
// RUN: %target-swift-frontend -typecheck %s -target x86_64-apple-macos50
5+
6+
// REQUIRES: OS=macosx
7+
8+
@available(macOS 50, *)
9+
struct NewStruct {}
10+
11+
@available(macOS 50, *)
12+
struct GoodReferenceStruct {
13+
var x: NewStruct
14+
}
15+
16+
@available(macOS 50, *)
17+
struct GoodNestedReferenceStruct {
18+
struct Inner {
19+
var x: NewStruct
20+
}
21+
}
22+
23+
struct BadReferenceStruct1 {
24+
// expected-error@+1 {{stored properties cannot be marked potentially unavailable with '@available'}}
25+
@available(macOS 50, *)
26+
var x: NewStruct
27+
}
28+
29+
@available(macOS 40, *)
30+
struct BadReferenceStruct2 {
31+
// expected-error@+1 {{stored properties cannot be marked potentially unavailable with '@available'}}
32+
@available(macOS 50, *)
33+
var x: NewStruct
34+
}
35+
36+
// The same behavior should hold for enum elements with payloads.
37+
@available(macOS 50, *)
38+
enum GoodReferenceEnum {
39+
case x(NewStruct)
40+
}
41+
42+
@available(macOS 50, *)
43+
enum GoodNestedReferenceEnum {
44+
enum Inner {
45+
case x(NewStruct)
46+
}
47+
}
48+
49+
enum BadReferenceEnum1 {
50+
// expected-error@+1 {{enum cases with associated values cannot be marked potentially unavailable with '@available'}}
51+
@available(macOS 50, *)
52+
case x(NewStruct)
53+
}
54+
55+
@available(macOS 40, *)
56+
enum BadReferenceEnum2 {
57+
// expected-error@+1 {{enum cases with associated values cannot be marked potentially unavailable with '@available'}}
58+
@available(macOS 50, *)
59+
case x(NewStruct)
60+
}

test/Sema/availability_versions.swift

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,6 @@ class SubOfClassWithUnavailableInitializer : SuperWithWithUnavailableInitializer
309309
class ClassWithUnavailableProperties {
310310
// expected-note@-1 4{{add @available attribute to enclosing class}}
311311

312-
@available(OSX, introduced: 10.9) // expected-error {{stored properties cannot be marked potentially unavailable with '@available'}}
313312
var nonLazyAvailableOn10_9Stored: Int = 9
314313

315314
@available(OSX, introduced: 10.51) // expected-error {{stored properties cannot be marked potentially unavailable with '@available'}}
@@ -538,17 +537,17 @@ enum CompassPoint {
538537

539538
case WithAvailableByEnumPayload(p : EnumIntroducedOn10_51)
540539

540+
// expected-error@+1 {{enum cases with associated values cannot be marked potentially unavailable with '@available'}}
541541
@available(OSX, introduced: 10.52)
542542
case WithAvailableByEnumElementPayload(p : EnumIntroducedOn10_52)
543543

544+
// expected-error@+1 2{{enum cases with associated values cannot be marked potentially unavailable with '@available'}}
544545
@available(OSX, introduced: 10.52)
545546
case WithAvailableByEnumElementPayload1(p : EnumIntroducedOn10_52), WithAvailableByEnumElementPayload2(p : EnumIntroducedOn10_52)
546547

547548
case WithUnavailablePayload(p : EnumIntroducedOn10_52) // expected-error {{'EnumIntroducedOn10_52' is only available in macOS 10.52 or newer}}
548-
// expected-note@-1 {{add @available attribute to enclosing case}}
549549

550-
case WithUnavailablePayload1(p : EnumIntroducedOn10_52), WithUnavailablePayload2(p : EnumIntroducedOn10_52) // expected-error 2{{'EnumIntroducedOn10_52' is only available in macOS 10.52 or newer}}
551-
// expected-note@-1 2{{add @available attribute to enclosing case}}
550+
case WithUnavailablePayload1(p : EnumIntroducedOn10_52), WithUnavailablePayload2(p : EnumIntroducedOn10_52) // expected-error 2{{'EnumIntroducedOn10_52' is only available in macOS 10.52 or newer}}
552551
}
553552

554553
@available(OSX, introduced: 10.52)
@@ -1337,11 +1336,9 @@ enum EnumForFixit {
13371336
// expected-note@-1 2{{add @available attribute to enclosing enum}} {{1-1=@available(macOS 10.51, *)\n}}
13381337
case CaseWithUnavailablePayload(p: ClassAvailableOn10_51)
13391338
// expected-error@-1 {{'ClassAvailableOn10_51' is only available in macOS 10.51 or newer}}
1340-
// expected-note@-2 {{add @available attribute to enclosing case}} {{3-3=@available(macOS 10.51, *)\n }}
13411339

13421340
case CaseWithUnavailablePayload2(p: ClassAvailableOn10_51), WithoutPayload
13431341
// expected-error@-1 {{'ClassAvailableOn10_51' is only available in macOS 10.51 or newer}}
1344-
// expected-note@-2 {{add @available attribute to enclosing case}} {{3-3=@available(macOS 10.51, *)\n }}
13451342

13461343
}
13471344

0 commit comments

Comments
 (0)