llvm-project/clang/test/SemaObjC/property-ambiguous-synthesis.m

49 lines
1.4 KiB
Mathematica
Raw Normal View History

// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://13075400
@protocol FooAsID
[ObjC] Pick a 'readwrite' property when synthesizing ambiguous property and check for incompatible attributes This commit changes the way ambiguous property synthesis (i.e. when synthesizing a property that's declared in multiple protocols) is performed. Previously, Clang synthesized the first property that was found. This lead to problems when the property was synthesized in a class that conformed to two protocols that declared that property and a second protocols had a 'readwrite' declaration - the setter was not synthesized so the class didn't really conform to the second protocol and user's code would crash at runtime when they would try to set the property. This commit ensures that a first readwrite property is selected. This is a semantic change that changes users code in this manner: ``` @protocol P @property(readonly) int p; @end @protocol P2 @property(readwrite) id p; @end @interface I <P2> @end @implementation I @syntesize p; // Users previously got a warning here, and Clang synthesized // readonly 'int p' here. Now Clang synthesizes readwrite 'id' p.. @end ``` To ensure that this change is safe, the warning about incompatible types is promoted to an error when this kind of readonly/readwrite ambiguity is detected in the @implementation. This will ensure that previous code that had this subtle bug and ignored the warning now will fail to compile with an error, and users should not get suprises at runtime once they resolve the error. The commit also extends the ambiguity checker, and now it can detect conflicts among the different property attributes. An error diagnostic is used for conflicting attributes, to ensure that the user won't get "suprises" at runtime. ProtocolPropertyMap is removed in favour of a a set + vector because the map's order of iteration is non-deterministic, so it couldn't be used to select the readwrite property. rdar://31579994 Differential Revision: https://reviews.llvm.org/D35268 llvm-svn: 307903
2017-07-13 19:06:22 +08:00
@property (assign) id foo; // expected-note 2 {{it could also be property of type 'id' declared here}} \\
// expected-warning {{property of type 'id' was selected for synthesis}}
@end
@protocol FooAsDouble
@property double foo; // expected-warning 2 {{property of type 'double' was selected for synthesis}} \
// expected-note {{it could also be property of type 'double' declared here}}
@end
@protocol FooAsShort
@property short foo; // expected-note {{it could also be property of type 'short' declared here}}
@end
@interface NSObject @end
@interface AnObject : NSObject<FooAsDouble,FooAsID>
@end
@interface Sub : AnObject
@end
@implementation Sub
@synthesize foo=_MyFooIvar; // expected-note {{property synthesized here}}
@end
@interface AnotherObject : NSObject<FooAsDouble, FooAsID,FooAsDouble, FooAsID, FooAsDouble,FooAsID>
@end
@implementation AnotherObject
@synthesize foo=_MyFooIvar; // expected-note {{property synthesized here}}
@end
@interface YetAnotherObject : NSObject<FooAsID,FooAsShort, FooAsDouble,FooAsID, FooAsShort>
@end
@implementation YetAnotherObject
@synthesize foo=_MyFooIvar; // expected-note {{property synthesized here}}
@end
double func(YetAnotherObject *object) {
return [object foo]; // expected-error {{returning 'id' from a function with incompatible result type 'double'}}
}