Merge pull request #15864 from jrose-apple/get-set-stop
Diagnose unavailable getters and setters
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 6b4f720..e2db36e 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -3622,38 +3622,45 @@
//------------------------------------------------------------------------------
ERROR(availability_decl_unavailable, none,
- "%0 is unavailable", (DeclName))
+ "%select{getter for |setter for |}0%1 is unavailable",
+ (unsigned, DeclName))
#define REPLACEMENT_DECL_KIND_SELECT "select{| instance method| property}"
ERROR(availability_decl_unavailable_rename, none,
- "%0 has been %select{renamed to|replaced by}1"
- "%" REPLACEMENT_DECL_KIND_SELECT "2 '%3'",
- (DeclName, bool, unsigned, StringRef))
+ "%select{getter for |setter for |}0%1 has been "
+ "%select{renamed to|replaced by}2%" REPLACEMENT_DECL_KIND_SELECT "3 "
+ "'%4'",
+ (unsigned, DeclName, bool, unsigned, StringRef))
ERROR(availability_decl_unavailable_rename_msg, none,
- "%0 has been %select{renamed to|replaced by}1"
- "%" REPLACEMENT_DECL_KIND_SELECT "2 '%3': %4",
- (DeclName, bool, unsigned, StringRef, StringRef))
+ "%select{getter for |setter for |}0%1 has been "
+ "%select{renamed to|replaced by}2%" REPLACEMENT_DECL_KIND_SELECT "3 "
+ "'%4': %5",
+ (unsigned, DeclName, bool, unsigned, StringRef, StringRef))
ERROR(availability_decl_unavailable_msg, none,
- "%0 is unavailable: %1", (DeclName, StringRef))
+ "%select{getter for |setter for |}0%1 is unavailable: %2",
+ (unsigned, DeclName, StringRef))
ERROR(availability_decl_unavailable_in_swift, none,
- "%0 is unavailable in Swift", (DeclName))
+ "%select{getter for |setter for |}0%1 is unavailable in Swift",
+ (unsigned, DeclName))
ERROR(availability_decl_unavailable_in_swift_msg, none,
- "%0 is unavailable in Swift: %1", (DeclName, StringRef))
+ "%select{getter for |setter for |}0%1 is unavailable in Swift: %2",
+ (unsigned, DeclName, StringRef))
NOTE(availability_marked_unavailable, none,
- "%0 has been explicitly marked unavailable here", (DeclName))
+ "%select{getter for |setter for |}0%1 has been explicitly marked "
+ "unavailable here", (unsigned, DeclName))
NOTE(availability_introduced_in_swift, none,
- "%0 was introduced in Swift %1",
- (DeclName, clang::VersionTuple))
+ "%select{getter for |setter for |}0%1 was introduced in Swift %2",
+ (unsigned, DeclName, clang::VersionTuple))
NOTE(availability_obsoleted, none,
- "%0 was obsoleted in %1 %2",
- (DeclName, StringRef, clang::VersionTuple))
+ "%select{getter for |setter for |}0%1 was obsoleted in %2 %3",
+ (unsigned, DeclName, StringRef, clang::VersionTuple))
WARNING(availability_deprecated, none,
"%select{getter for |setter for |}0%1 %select{is|%select{is|was}4}2 "
diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp
index e5253a8..07f653a 100644
--- a/lib/Sema/TypeCheckAvailability.cpp
+++ b/lib/Sema/TypeCheckAvailability.cpp
@@ -1534,6 +1534,9 @@
const ValueDecl *renamedDecl,
const AvailableAttr *attr,
const ApplyExpr *call) {
+ if (isa<AccessorDecl>(renamedDecl))
+ return;
+
ParsedDeclName parsed = swift::parseDeclName(attr->Rename);
if (!parsed)
return;
@@ -1906,6 +1909,26 @@
return ReplacementDeclKind::None;
}
+/// Returns a value that can be used to select between accessor kinds in
+/// diagnostics.
+///
+/// This is correlated with diag::availability_deprecated and others.
+static std::pair<unsigned, DeclName>
+getAccessorKindAndNameForDiagnostics(const ValueDecl *D) {
+ // This should always be one more than the last AccessorKind supported in
+ // the diagnostics. If you need to change it, change the assertion below as
+ // well.
+ static const unsigned NOT_ACCESSOR_INDEX = 2;
+
+ if (auto *accessor = dyn_cast<AccessorDecl>(D)) {
+ DeclName Name = accessor->getStorage()->getFullName();
+ assert(accessor->isGetterOrSetter());
+ return {static_cast<unsigned>(accessor->getAccessorKind()), Name};
+ }
+
+ return {NOT_ACCESSOR_INDEX, D->getFullName()};
+}
+
void TypeChecker::diagnoseIfDeprecated(SourceRange ReferenceRange,
const DeclContext *ReferenceDC,
const ValueDecl *DeprecatedDecl,
@@ -1933,26 +1956,19 @@
}
DeclName Name;
- Optional<unsigned> rawAccessorKind;
- if (auto *accessor = dyn_cast<AccessorDecl>(DeprecatedDecl)) {
- Name = accessor->getStorage()->getFullName();
- assert(accessor->isGetterOrSetter());
- rawAccessorKind = static_cast<unsigned>(accessor->getAccessorKind());
- } else {
- Name = DeprecatedDecl->getFullName();
- }
+ unsigned RawAccessorKind;
+ std::tie(RawAccessorKind, Name) =
+ getAccessorKindAndNameForDiagnostics(DeprecatedDecl);
StringRef Platform = Attr->prettyPlatformString();
clang::VersionTuple DeprecatedVersion;
if (Attr->Deprecated)
DeprecatedVersion = Attr->Deprecated.getValue();
- static const unsigned NOT_ACCESSOR_INDEX = 2;
if (Attr->Message.empty() && Attr->Rename.empty()) {
diagnose(ReferenceRange.Start, diag::availability_deprecated,
- rawAccessorKind.getValueOr(NOT_ACCESSOR_INDEX), Name,
- Attr->hasPlatform(), Platform, Attr->Deprecated.hasValue(),
- DeprecatedVersion)
+ RawAccessorKind, Name, Attr->hasPlatform(), Platform,
+ Attr->Deprecated.hasValue(), DeprecatedVersion)
.highlight(Attr->getRange());
return;
}
@@ -1965,22 +1981,21 @@
if (!Attr->Message.empty()) {
EncodedDiagnosticMessage EncodedMessage(Attr->Message);
diagnose(ReferenceRange.Start, diag::availability_deprecated_msg,
- rawAccessorKind.getValueOr(NOT_ACCESSOR_INDEX), Name,
- Attr->hasPlatform(), Platform, Attr->Deprecated.hasValue(),
- DeprecatedVersion, EncodedMessage.Message)
+ RawAccessorKind, Name, Attr->hasPlatform(), Platform,
+ Attr->Deprecated.hasValue(), DeprecatedVersion,
+ EncodedMessage.Message)
.highlight(Attr->getRange());
} else {
unsigned rawReplaceKind = static_cast<unsigned>(
replacementDeclKind.getValueOr(ReplacementDeclKind::None));
diagnose(ReferenceRange.Start, diag::availability_deprecated_rename,
- rawAccessorKind.getValueOr(NOT_ACCESSOR_INDEX), Name,
- Attr->hasPlatform(), Platform, Attr->Deprecated.hasValue(),
- DeprecatedVersion, replacementDeclKind.hasValue(), rawReplaceKind,
- newName)
+ RawAccessorKind, Name, Attr->hasPlatform(), Platform,
+ Attr->Deprecated.hasValue(), DeprecatedVersion,
+ replacementDeclKind.hasValue(), rawReplaceKind, newName)
.highlight(Attr->getRange());
}
- if (!Attr->Rename.empty() && !rawAccessorKind.hasValue()) {
+ if (!Attr->Rename.empty() && !isa<AccessorDecl>(DeprecatedDecl)) {
auto renameDiag = diagnose(ReferenceRange.Start,
diag::note_deprecated_rename,
newName);
@@ -1999,8 +2014,13 @@
else
diagnose(override, diag::override_unavailable_msg,
override->getBaseName(), attr->Message);
+
+ DeclName name;
+ unsigned rawAccessorKind;
+ std::tie(rawAccessorKind, name) =
+ getAccessorKindAndNameForDiagnostics(base);
diagnose(base, diag::availability_marked_unavailable,
- base->getFullName());
+ rawAccessorKind, name);
return;
}
@@ -2127,7 +2147,9 @@
}
SourceLoc Loc = R.Start;
- auto Name = D->getFullName();
+ DeclName Name;
+ unsigned RawAccessorKind;
+ std::tie(RawAccessorKind, Name) = getAccessorKindAndNameForDiagnostics(D);
switch (Attr->getPlatformAgnosticAvailability()) {
case PlatformAgnosticAvailabilityKind::Deprecated:
@@ -2150,14 +2172,14 @@
if (Attr->Message.empty()) {
auto diag = diagnose(Loc, diag::availability_decl_unavailable_rename,
- Name, replaceKind.hasValue(), rawReplaceKind,
- newName);
+ RawAccessorKind, Name, replaceKind.hasValue(),
+ rawReplaceKind, newName);
attachRenameFixIts(diag);
} else {
EncodedDiagnosticMessage EncodedMessage(Attr->Message);
auto diag = diagnose(Loc, diag::availability_decl_unavailable_rename_msg,
- Name, replaceKind.hasValue(), rawReplaceKind,
- newName, EncodedMessage.Message);
+ RawAccessorKind, Name, replaceKind.hasValue(),
+ rawReplaceKind, newName, EncodedMessage.Message);
attachRenameFixIts(diag);
}
} else if (isSubscriptReturningString(D, Context)) {
@@ -2171,12 +2193,13 @@
} else if (Attr->Message.empty()) {
diagnose(Loc, inSwift ? diag::availability_decl_unavailable_in_swift
: diag::availability_decl_unavailable,
- Name).highlight(R);
+ RawAccessorKind, Name)
+ .highlight(R);
} else {
EncodedDiagnosticMessage EncodedMessage(Attr->Message);
diagnose(Loc, inSwift ? diag::availability_decl_unavailable_in_swift_msg
: diag::availability_decl_unavailable_msg,
- Name, EncodedMessage.Message)
+ RawAccessorKind, Name, EncodedMessage.Message)
.highlight(R);
}
break;
@@ -2191,20 +2214,23 @@
case AvailableVersionComparison::Unavailable:
if (Attr->isLanguageVersionSpecific()
&& Attr->Introduced.hasValue())
- diagnose(D, diag::availability_introduced_in_swift, Name,
- *Attr->Introduced).highlight(Attr->getRange());
+ diagnose(D, diag::availability_introduced_in_swift,
+ RawAccessorKind, Name, *Attr->Introduced)
+ .highlight(Attr->getRange());
else
- diagnose(D, diag::availability_marked_unavailable, Name)
+ diagnose(D, diag::availability_marked_unavailable, RawAccessorKind, Name)
.highlight(Attr->getRange());
break;
case AvailableVersionComparison::Obsoleted:
// FIXME: Use of the platformString here is non-awesome for application
// extensions.
- diagnose(D, diag::availability_obsoleted, Name,
+ diagnose(D, diag::availability_obsoleted,
+ RawAccessorKind, Name,
(Attr->isLanguageVersionSpecific() ?
"Swift" : Attr->prettyPlatformString()),
- *Attr->Obsoleted).highlight(Attr->getRange());
+ *Attr->Obsoleted)
+ .highlight(Attr->getRange());
break;
}
return true;
@@ -2433,8 +2459,18 @@
return;
}
- // Make sure not to diagnose an accessor if we already complained about
- // the property/subscript.
+ // If the property/subscript is unconditionally unavailable, don't bother
+ // with any of the rest of this.
+ if (AvailableAttr::isUnavailable(D->getStorage()))
+ return;
+
+ if (TC.diagnoseExplicitUnavailability(D, ReferenceRange, ReferenceDC,
+ /*call*/nullptr)) {
+ return;
+ }
+
+ // Make sure not to diagnose an accessor's deprecation if we already
+ // complained about the property/subscript.
if (!TypeChecker::getDeprecated(D->getStorage()))
TC.diagnoseIfDeprecated(ReferenceRange, ReferenceDC, D, /*call*/nullptr);
@@ -2549,9 +2585,14 @@
}
if (!replacement.empty()) {
+ DeclName Name;
+ unsigned RawAccessorKind;
+ std::tie(RawAccessorKind, Name) = getAccessorKindAndNameForDiagnostics(D);
+
// If we emit a deprecation diagnostic, produce a fixit hint as well.
auto diag = TC.diagnose(R.Start, diag::availability_decl_unavailable_msg,
- D->getFullName(), "it has been removed in Swift 3");
+ RawAccessorKind, Name,
+ "it has been removed in Swift 3");
if (isa<PrefixUnaryExpr>(call)) {
// Prefix: remove the ++ or --.
diag.fixItRemove(call->getFn()->getSourceRange());
@@ -2594,9 +2635,13 @@
if (!args)
return false;
+ DeclName Name;
+ unsigned RawAccessorKind;
+ std::tie(RawAccessorKind, Name) = getAccessorKindAndNameForDiagnostics(D);
+
EncodedDiagnosticMessage EncodedMessage(Attr->Message);
auto diag = TC.diagnose(R.Start, diag::availability_decl_unavailable_msg,
- D->getFullName(), EncodedMessage.Message);
+ RawAccessorKind, Name, EncodedMessage.Message);
diag.highlight(R);
auto subject = args->getSubExpr();
diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp
index cdadb3b..5b8577d 100644
--- a/lib/Sema/TypeCheckPattern.cpp
+++ b/lib/Sema/TypeCheckPattern.cpp
@@ -1383,9 +1383,10 @@
EEP->getName().str() == "Some") {
SmallString<4> Rename;
camel_case::toLowercaseWord(EEP->getName().str(), Rename);
- diagnose(EEP->getLoc(), diag::availability_decl_unavailable_rename,
- EEP->getName(), /*replaced*/false,
- /*special kind*/0, Rename.str())
+ diagnose(EEP->getLoc(),
+ diag::availability_decl_unavailable_rename,
+ /*"getter" prefix*/2, EEP->getName(), /*replaced*/false,
+ /*special kind*/0, Rename.str())
.fixItReplace(EEP->getLoc(), Rename.str());
return true;
diff --git a/test/ClangImporter/Inputs/custom-modules/AvailabilityExtras.h b/test/ClangImporter/Inputs/custom-modules/AvailabilityExtras.h
index b151a3b..eb2a7f2 100644
--- a/test/ClangImporter/Inputs/custom-modules/AvailabilityExtras.h
+++ b/test/ClangImporter/Inputs/custom-modules/AvailabilityExtras.h
@@ -107,3 +107,18 @@
@property (class) int setterDeprecatedClass;
+ (void)setSetterDeprecatedClass:(int)setterDeprecated __attribute__((deprecated));
@end
+
+
+@interface UnavailableAccessors: NSObject
+@property NSInteger fullyUnavailable __attribute__((unavailable));
+
+@property NSInteger getterUnavailable;
+- (NSInteger)getterUnavailable __attribute__((unavailable));
+@property (class) NSInteger getterUnavailableClass;
++ (NSInteger)getterUnavailableClass __attribute__((unavailable));
+
+@property NSInteger setterUnavailable;
+- (void)setSetterUnavailable:(NSInteger)setterUnavailable __attribute__((unavailable));
+@property (class) NSInteger setterUnavailableClass;
++ (void)setSetterUnavailableClass:(NSInteger)setterUnavailable __attribute__((unavailable));
+@end
diff --git a/test/ClangImporter/availability.swift b/test/ClangImporter/availability.swift
index cc14dd5..9e744f4 100644
--- a/test/ClangImporter/availability.swift
+++ b/test/ClangImporter/availability.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify -I %S/Inputs/custom-modules %s
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify -I %S/Inputs/custom-modules %s -verify-ignore-unknown
// REQUIRES: objc_interop
@@ -25,6 +25,28 @@
NSDeallocateObject(x) // expected-error {{'NSDeallocateObject' is unavailable}}
}
+func test_unavailable_accessors(_ obj: UnavailableAccessors) {
+ _ = obj.fullyUnavailable // expected-error {{'fullyUnavailable' is unavailable}}
+ obj.fullyUnavailable = 0 // expected-error {{'fullyUnavailable' is unavailable}}
+ obj.fullyUnavailable += 1 // expected-error {{'fullyUnavailable' is unavailable}}
+
+ _ = obj.getterUnavailable // expected-error {{getter for 'getterUnavailable' is unavailable}}
+ obj.getterUnavailable = 0
+ obj.getterUnavailable += 1 // expected-error {{getter for 'getterUnavailable' is unavailable}}
+
+ _ = UnavailableAccessors.getterUnavailableClass // expected-error {{getter for 'getterUnavailableClass' is unavailable}}
+ UnavailableAccessors.getterUnavailableClass = 0
+ UnavailableAccessors.getterUnavailableClass += 1 // expected-error {{getter for 'getterUnavailableClass' is unavailable}}
+
+ _ = obj.setterUnavailable
+ obj.setterUnavailable = 0 // expected-error {{setter for 'setterUnavailable' is unavailable}}
+ obj.setterUnavailable += 1 // expected-error {{setter for 'setterUnavailable' is unavailable}}
+
+ _ = UnavailableAccessors.setterUnavailableClass
+ UnavailableAccessors.setterUnavailableClass = 0 // expected-error {{setter for 'setterUnavailableClass' is unavailable}}
+ UnavailableAccessors.setterUnavailableClass += 1 // expected-error {{setter for 'setterUnavailableClass' is unavailable}}
+}
+
func test_deprecated(_ s:UnsafeMutablePointer<CChar>, _ obj: AccessorDeprecations) {
_ = tmpnam(s) // expected-warning {{'tmpnam' is deprecated: Due to security concerns inherent in the design of tmpnam(3), it is highly recommended that you use mkstemp(3) instead.}}
diff --git a/test/attr/attr_availability.swift b/test/attr/attr_availability.swift
index 61168cf..2772276 100644
--- a/test/attr/attr_availability.swift
+++ b/test/attr/attr_availability.swift
@@ -871,6 +871,61 @@
deprecatedProperty = 0 // expected-warning {{'deprecatedProperty' is deprecated: bad variable}} {{none}}
deprecatedProperty += 1 // expected-warning {{'deprecatedProperty' is deprecated: bad variable}} {{none}}
+var unavailableGetter: Int {
+ @available(*, unavailable) get { return 0 } // expected-note * {{here}}
+ set {}
+}
+var unavailableGetterOnly: Int {
+ @available(*, unavailable) get { return 0 } // expected-note * {{here}}
+}
+var unavailableSetter: Int {
+ get { return 0 }
+ @available(*, unavailable) set {} // expected-note * {{here}}
+}
+var unavailableBoth: Int {
+ @available(*, unavailable) get { return 0 } // expected-note * {{here}}
+ @available(*, unavailable) set {} // expected-note * {{here}}
+}
+var unavailableMessage: Int {
+ @available(*, unavailable, message: "bad getter") get { return 0 } // expected-note * {{here}}
+ @available(*, unavailable, message: "bad setter") set {} // expected-note * {{here}}
+}
+var unavailableRename: Int {
+ @available(*, unavailable, renamed: "betterThing()") get { return 0 } // expected-note * {{here}}
+ @available(*, unavailable, renamed: "setBetterThing(_:)") set {} // expected-note * {{here}}
+}
+@available(*, unavailable, message: "bad variable")
+var unavailableProperty: Int { // expected-note * {{here}}
+ @available(*, unavailable, message: "bad getter") get { return 0 }
+ @available(*, unavailable, message: "bad setter") set {}
+}
+
+_ = unavailableGetter // expected-error {{getter for 'unavailableGetter' is unavailable}} {{none}}
+unavailableGetter = 0
+unavailableGetter += 1 // expected-error {{getter for 'unavailableGetter' is unavailable}} {{none}}
+
+_ = unavailableGetterOnly // expected-error {{getter for 'unavailableGetterOnly' is unavailable}} {{none}}
+
+_ = unavailableSetter
+unavailableSetter = 0 // expected-error {{setter for 'unavailableSetter' is unavailable}} {{none}}
+unavailableSetter += 1 // expected-error {{setter for 'unavailableSetter' is unavailable}} {{none}}
+
+_ = unavailableBoth // expected-error {{getter for 'unavailableBoth' is unavailable}} {{none}}
+unavailableBoth = 0 // expected-error {{setter for 'unavailableBoth' is unavailable}} {{none}}
+unavailableBoth += 1 // expected-error {{getter for 'unavailableBoth' is unavailable}} {{none}} expected-error {{setter for 'unavailableBoth' is unavailable}} {{none}}
+
+_ = unavailableMessage // expected-error {{getter for 'unavailableMessage' is unavailable: bad getter}} {{none}}
+unavailableMessage = 0 // expected-error {{setter for 'unavailableMessage' is unavailable: bad setter}} {{none}}
+unavailableMessage += 1 // expected-error {{getter for 'unavailableMessage' is unavailable: bad getter}} {{none}} expected-error {{setter for 'unavailableMessage' is unavailable: bad setter}} {{none}}
+
+_ = unavailableRename // expected-error {{getter for 'unavailableRename' has been renamed to 'betterThing()'}} {{none}}
+unavailableRename = 0 // expected-error {{setter for 'unavailableRename' has been renamed to 'setBetterThing(_:)'}} {{none}}
+unavailableRename += 1 // expected-error {{getter for 'unavailableRename' has been renamed to 'betterThing()'}} {{none}} expected-error {{setter for 'unavailableRename' has been renamed to 'setBetterThing(_:)'}} {{none}}
+
+_ = unavailableProperty // expected-error {{'unavailableProperty' is unavailable: bad variable}} {{none}}
+unavailableProperty = 0 // expected-error {{'unavailableProperty' is unavailable: bad variable}} {{none}}
+unavailableProperty += 1 // expected-error {{'unavailableProperty' is unavailable: bad variable}} {{none}}
+
struct DeprecatedAccessors {
var deprecatedMessage: Int {
@available(*, deprecated, message: "bad getter") get { return 0 }
@@ -925,3 +980,58 @@
other[alsoDeprecated: 0] += 1 // expected-warning {{'subscript(alsoDeprecated:)' is deprecated: bad subscript!}} {{none}}
}
}
+
+struct UnavailableAccessors {
+ var unavailableMessage: Int {
+ @available(*, unavailable, message: "bad getter") get { return 0 } // expected-note * {{here}}
+ @available(*, unavailable, message: "bad setter") set {} // expected-note * {{here}}
+ }
+
+ static var staticUnavailable: Int {
+ @available(*, unavailable, message: "bad getter") get { return 0 } // expected-note * {{here}}
+ @available(*, unavailable, message: "bad setter") set {} // expected-note * {{here}}
+ }
+
+ @available(*, unavailable, message: "bad property")
+ var unavailableProperty: Int { // expected-note * {{here}}
+ @available(*, unavailable, message: "bad getter") get { return 0 }
+ @available(*, unavailable, message: "bad setter") set {}
+ }
+
+ subscript(_: Int) -> Int {
+ @available(*, unavailable, message: "bad subscript getter") get { return 0 } // expected-note * {{here}}
+ @available(*, unavailable, message: "bad subscript setter") set {} // expected-note * {{here}}
+ }
+
+ @available(*, unavailable, message: "bad subscript!")
+ subscript(alsoUnavailable _: Int) -> Int { // expected-note * {{here}}
+ @available(*, unavailable, message: "bad subscript getter") get { return 0 }
+ @available(*, unavailable, message: "bad subscript setter") set {}
+ }
+
+ mutating func testAccessors(other: inout UnavailableAccessors) {
+ _ = unavailableMessage // expected-error {{getter for 'unavailableMessage' is unavailable: bad getter}} {{none}}
+ unavailableMessage = 0 // expected-error {{setter for 'unavailableMessage' is unavailable: bad setter}} {{none}}
+ unavailableMessage += 1 // expected-error {{getter for 'unavailableMessage' is unavailable: bad getter}} {{none}} expected-error {{setter for 'unavailableMessage' is unavailable: bad setter}} {{none}}
+
+ _ = other.unavailableMessage // expected-error {{getter for 'unavailableMessage' is unavailable: bad getter}} {{none}}
+ other.unavailableMessage = 0 // expected-error {{setter for 'unavailableMessage' is unavailable: bad setter}} {{none}}
+ other.unavailableMessage += 1 // expected-error {{getter for 'unavailableMessage' is unavailable: bad getter}} {{none}} expected-error {{setter for 'unavailableMessage' is unavailable: bad setter}} {{none}}
+
+ _ = other.unavailableProperty // expected-error {{'unavailableProperty' is unavailable: bad property}} {{none}}
+ other.unavailableProperty = 0 // expected-error {{'unavailableProperty' is unavailable: bad property}} {{none}}
+ other.unavailableProperty += 1 // expected-error {{'unavailableProperty' is unavailable: bad property}} {{none}}
+
+ _ = UnavailableAccessors.staticUnavailable // expected-error {{getter for 'staticUnavailable' is unavailable: bad getter}} {{none}}
+ UnavailableAccessors.staticUnavailable = 0 // expected-error {{setter for 'staticUnavailable' is unavailable: bad setter}} {{none}}
+ UnavailableAccessors.staticUnavailable += 1 // expected-error {{getter for 'staticUnavailable' is unavailable: bad getter}} {{none}} expected-error {{setter for 'staticUnavailable' is unavailable: bad setter}} {{none}}
+
+ _ = other[0] // expected-error {{getter for 'subscript' is unavailable: bad subscript getter}} {{none}}
+ other[0] = 0 // expected-error {{setter for 'subscript' is unavailable: bad subscript setter}} {{none}}
+ other[0] += 1 // expected-error {{getter for 'subscript' is unavailable: bad subscript getter}} {{none}} expected-error {{setter for 'subscript' is unavailable: bad subscript setter}} {{none}}
+
+ _ = other[alsoUnavailable: 0] // expected-error {{'subscript(alsoUnavailable:)' is unavailable: bad subscript!}} {{none}}
+ other[alsoUnavailable: 0] = 0 // expected-error {{'subscript(alsoUnavailable:)' is unavailable: bad subscript!}} {{none}}
+ other[alsoUnavailable: 0] += 1 // expected-error {{'subscript(alsoUnavailable:)' is unavailable: bad subscript!}} {{none}}
+ }
+}
diff --git a/test/attr/attr_availability_osx.swift b/test/attr/attr_availability_osx.swift
index 862476c..473bbdd 100644
--- a/test/attr/attr_availability_osx.swift
+++ b/test/attr/attr_availability_osx.swift
@@ -1,4 +1,12 @@
-// RUN: %swift -typecheck -verify -parse-stdlib -target x86_64-apple-macosx10.10 %s
+// RUN: %swift -typecheck -verify -parse-stdlib -module-name Swift -target x86_64-apple-macosx10.10 %s
+
+// Fake declarations of some standard library features for -parse-stdlib.
+precedencegroup AssignmentPrecedence {}
+enum Optional<T> {
+ case none
+ case some(T)
+}
+
@available(OSX, introduced: 10.5, deprecated: 10.8, obsoleted: 10.9,
message: "you don't want to do that anyway")
@@ -104,3 +112,32 @@
TestStruct().doFourthThing() // expected-error {{'doFourthThing()' is only available on OS X 10.12 or newer}} expected-note {{'if #available'}}
TestStruct().doDeprecatedThing() // expected-warning {{'doDeprecatedThing()' is deprecated}}
}
+
+extension TestStruct {
+ struct Data {
+ mutating func mutate() {}
+ }
+
+ var unavailableGetter: Data {
+ @available(macOS, unavailable, message: "bad getter")
+ get { return Data() } // expected-note 2 {{here}}
+ set {}
+ }
+
+ var unavailableSetter: Data {
+ get { return Data() }
+ @available(macOS, obsoleted: 10.5, message: "bad setter")
+ set {} // expected-note 2 {{setter for 'unavailableSetter' was obsoleted in OS X 10.5}}
+ }
+}
+
+func testAccessors() {
+ var t = TestStruct()
+ _ = t.unavailableGetter // expected-error {{getter for 'unavailableGetter' is unavailable}}
+ t.unavailableGetter = .init()
+ t.unavailableGetter.mutate() // expected-error {{getter for 'unavailableGetter' is unavailable}}
+
+ _ = t.unavailableSetter
+ t.unavailableSetter = .init() // expected-error {{setter for 'unavailableSetter' is unavailable: bad setter}}
+ t.unavailableSetter.mutate() // expected-error {{setter for 'unavailableSetter' is unavailable: bad setter}}
+}