Skip to content

Commit d9cbdf5

Browse files
authored
Merge pull request #2976 from apple/eng/ganymede-avail
[clang][ObjC] Allow different availability annotation on a method
2 parents d74493d + efb102a commit d9cbdf5

File tree

5 files changed

+70
-9
lines changed

5 files changed

+70
-9
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3135,6 +3135,9 @@ class Sema final {
31353135
/// Merge availability attributes for an implementation of
31363136
/// a protocol requirement.
31373137
AMK_ProtocolImplementation,
3138+
/// Merge availability attributes for an implementation of
3139+
/// an optional protocol requirement.
3140+
AMK_OptionalProtocolImplementation
31383141
};
31393142

31403143
/// Describes the kind of priority given to an availability attribute.

clang/lib/Sema/SemaDecl.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2602,7 +2602,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
26022602
NewAttr = nullptr;
26032603
else if ((isa<DeprecatedAttr>(Attr) || isa<UnavailableAttr>(Attr)) &&
26042604
(AMK == Sema::AMK_Override ||
2605-
AMK == Sema::AMK_ProtocolImplementation))
2605+
AMK == Sema::AMK_ProtocolImplementation ||
2606+
AMK == Sema::AMK_OptionalProtocolImplementation))
26062607
NewAttr = nullptr;
26072608
else if (isa<SwiftPrivateAttr>(Attr) && AMK == Sema::AMK_Override)
26082609
NewAttr = nullptr;
@@ -2951,6 +2952,7 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
29512952
case AMK_Redeclaration:
29522953
case AMK_Override:
29532954
case AMK_ProtocolImplementation:
2955+
case AMK_OptionalProtocolImplementation:
29542956
LocalAMK = AMK;
29552957
break;
29562958
}
@@ -3852,10 +3854,11 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
38523854
ObjCMethodDecl *oldMethod) {
38533855
// Merge the attributes, including deprecated/unavailable
38543856
AvailabilityMergeKind MergeKind =
3855-
isa<ObjCProtocolDecl>(oldMethod->getDeclContext())
3856-
? AMK_ProtocolImplementation
3857-
: isa<ObjCImplDecl>(newMethod->getDeclContext()) ? AMK_Redeclaration
3858-
: AMK_Override;
3857+
isa<ObjCProtocolDecl>(oldMethod->getDeclContext())
3858+
? (oldMethod->isOptional() ? AMK_OptionalProtocolImplementation
3859+
: AMK_ProtocolImplementation)
3860+
: isa<ObjCImplDecl>(newMethod->getDeclContext()) ? AMK_Redeclaration
3861+
: AMK_Override;
38593862

38603863
mergeDeclAttributes(newMethod, oldMethod, MergeKind);
38613864

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2358,6 +2358,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(
23582358

23592359
case AMK_Override:
23602360
case AMK_ProtocolImplementation:
2361+
case AMK_OptionalProtocolImplementation:
23612362
OverrideOrImpl = true;
23622363
break;
23632364
}
@@ -2426,6 +2427,14 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(
24262427
diag::warn_mismatched_availability_override_unavail)
24272428
<< AvailabilityAttr::getPrettyPlatformName(Platform->getName())
24282429
<< (AMK == AMK_Override);
2430+
} else if (Which != 1 && AMK == AMK_OptionalProtocolImplementation) {
2431+
// Allow different 'introduced' / 'obsoleted' availability versions
2432+
// on a method that implements an optional protocol requirement. It
2433+
// makes less sense to allow this for 'deprecated' as the user can't
2434+
// see if the method is 'deprecated' as 'respondsToSelector' will
2435+
// still return true when the method is deprecated.
2436+
++i;
2437+
continue;
24292438
} else {
24302439
Diag(OldAA->getLocation(),
24312440
diag::warn_mismatched_availability_override)

clang/test/SemaObjC/attr-availability.m

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,7 @@ void use_myEnum() {
229229
// inherited be implementations of those protocol methods.
230230
@protocol AvailabilityP2
231231
@optional
232-
-(void)methodA __attribute__((availability(macosx,introduced=10.1,deprecated=10.2))); // expected-note 4{{'methodA' has been explicitly marked deprecated here}} \
233-
// expected-note 2{{protocol method is here}}
232+
-(void)methodA __attribute__((availability(macosx,introduced=10.1,deprecated=10.2))); // expected-note 4{{'methodA' has been explicitly marked deprecated here}}
234233
-(void)methodB __attribute__((unavailable)); // expected-note 4{{'methodB' has been explicitly marked unavailable here}}
235234
-(void)methodC;
236235
@end
@@ -279,7 +278,7 @@ void testImplementsAvailabilityP2b(ImplementsAvailabilityP2b *obj) {
279278

280279
__attribute__((objc_root_class))
281280
@interface ImplementsAvailabilityP2c <AvailabilityP2>
282-
-(void)methodA __attribute__((availability(macosx,introduced=10.2))); // expected-warning{{method introduced after the protocol method it implements on macOS (10.2 vs. 10.1)}}
281+
-(void)methodA __attribute__((availability(macosx,introduced=10.2)));
283282
-(void)methodB __attribute__((unavailable));
284283
@end
285284

@@ -288,7 +287,7 @@ @interface ImplementsAvailabilityP2d <AvailabilityP2>
288287
@end
289288

290289
@implementation ImplementsAvailabilityP2d
291-
-(void)methodA __attribute__((availability(macosx,introduced=10.2))) // expected-warning{{method introduced after the protocol method it implements on macOS (10.2 vs. 10.1)}}
290+
-(void)methodA __attribute__((availability(macosx,introduced=10.2)))
292291
{
293292
}
294293
-(void)methodB __attribute__((unavailable)) {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// RUN: %clang_cc1 -triple arm64-apple-ios11 -fsyntax-only -verify %s
2+
3+
@protocol P
4+
5+
@property (nonatomic) int reqProp __attribute__((availability(ios, introduced=12.0))); // expected-note 2 {{is here}}
6+
7+
8+
9+
@optional
10+
@property (nonatomic) int myProp __attribute__((availability(ios, introduced=12.0))); // expected-note {{has been marked as being introduced in}}
11+
12+
@optional
13+
@property (nonatomic, readonly) int depProp __attribute__((availability(ios, introduced=8.0, deprecated=12.0))); // expected-note {{protocol method is here}}
14+
15+
@optional
16+
@property (nonatomic) int obsProp __attribute__((availability(ios, introduced=8.0, obsoleted=12.0)));
17+
18+
@optional
19+
- (void) unavaibleInClass __attribute__((availability(ios, introduced=12.0))); // expected-note {{method is here}}
20+
21+
@end
22+
23+
@interface X <P>
24+
25+
@property (nonatomic) int myProp __attribute__((availability(ios, introduced=13.0))); // expected-note 2 {{has been marked as being introduced in}}
26+
27+
@property (nonatomic) int reqProp __attribute__((availability(ios, introduced=13.0))); // expected-warning 2 {{method introduced after the protocol method it implements on iOS}}
28+
29+
@property (nonatomic, readonly) int depProp __attribute__((availability(ios, introduced=8.0, deprecated=10.0))); // expected-warning {{method deprecated before the protocol method it implements on iOS (12.0 vs. 10.0)}} expected-note {{been explicitly marked deprecated here}}
30+
31+
@property (nonatomic) int obsProp __attribute__((availability(ios, introduced=8.0, obsoleted=10.0))); // expected-note {{been explicitly marked unavailable here}}
32+
33+
- (void) unavaibleInClass __attribute__((availability(ios, unavailable))); // expected-warning {{method cannot be unavailable on iOS when the protocol method it implements is available}}
34+
35+
@end
36+
37+
38+
void test(X *x) {
39+
int i = x.myProp; // expected-warning {{'myProp' is only available on iOS 13.0 or newer}} expected-note {{enclose}}
40+
x.myProp = i; // expected-warning {{'setMyProp:' is only available on iOS 13.0 or newer}} expected-note {{enclose}}
41+
int i2 = x.depProp; // expected-warning {{'depProp' is deprecated: first deprecated in iOS 10.0}}
42+
int i3 = x.obsProp; // expected-error {{'obsProp' is unavailable: obsoleted in iOS 10.0}}
43+
}
44+
45+
void testProto(id<P> x) {
46+
int i = x.myProp; // expected-warning {{'myProp' is only available on iOS 12.0 or newer}} expected-note {{enclose}}
47+
}

0 commit comments

Comments
 (0)