From 937ec1d9575ec455bc2d4e1f159f64980b476196 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 19 Sep 2013 16:37:20 +0000 Subject: [PATCH] ObjectiveC: Allow NS_RETURNS_INNER_POINTER annotation of ObjectiveC properties to mean annotation of NS_RETURNS_INNER_POINTER on its synthesized getter. This also facilitates more migration to properties when methods are annotated with NS_RETURNS_INNER_POINTER. // rdar://14990439 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191009 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 5 ++- lib/Sema/SemaDeclAttr.cpp | 30 ++++++++------ lib/Sema/SemaObjCProperty.cpp | 4 ++ test/CodeGenObjC/arc-precise-lifetime.m | 47 +++++++++++++++++++++- test/SemaObjC/arc-property-lifetime.m | 5 ++- 5 files changed, 75 insertions(+), 16 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 152149e4bd..9a6e9d0ff0 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2027,7 +2027,8 @@ def err_attribute_wrong_decl_type : Error< "variables, functions and labels|fields and global variables|structs|" "variables, functions and tag types|thread-local variables|" "variables and fields|variables, data members and tag types|" - "types and namespaces|Objective-C interfaces}1">; + "types and namespaces|Objective-C interfaces|" + "methods and properties}1">; def warn_type_attribute_wrong_type : Warning< "'%0' only applies to %select{function|pointer|" "Objective-C object or block pointer}1 types; type here is %2">, @@ -2395,7 +2396,7 @@ def note_attribute_overloadable_prev_overload : Note< def err_attribute_overloadable_no_prototype : Error< "'overloadable' function %0 must have a prototype">; def warn_ns_attribute_wrong_return_type : Warning< - "%0 attribute only applies to %select{functions|methods}1 that " + "%0 attribute only applies to %select{functions|methods|properties}1 that " "return %select{an Objective-C object|a pointer|a non-retainable pointer}2">, InGroup; def warn_ns_attribute_wrong_parameter_type : Warning< diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 10ff4b8b94..d9e9972449 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -54,7 +54,8 @@ enum AttributeDeclKind { ExpectedVariableOrField, ExpectedVariableFieldOrTag, ExpectedTypeOrNamespace, - ExpectedObjectiveCInterface + ExpectedObjectiveCInterface, + ExpectedMethodOrProperty }; //===----------------------------------------------------------------------===// @@ -1476,7 +1477,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { break; } if (-1 != Err) { - S.Diag(AL.getLoc(), diag::err_ownership_type) << AL.getName() << Err + S.Diag(AL.getLoc(), diag::err_ownership_type) << AL.getName() << Err << Ex->getSourceRange(); return; } @@ -4145,29 +4146,34 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, const AttributeList &attr) { SourceLocation loc = attr.getLoc(); - + QualType resultType; + ObjCMethodDecl *method = dyn_cast(D); if (!method) { - S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << SourceRange(loc, loc) << attr.getName() << ExpectedMethod; - return; + ObjCPropertyDecl *property = dyn_cast(D); + if (!property) { + S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) + << SourceRange(loc, loc) << attr.getName() << ExpectedMethodOrProperty; + return; + } + resultType = property->getType(); } + else + // Check that the method returns a normal pointer. + resultType = method->getResultType(); - // Check that the method returns a normal pointer. - QualType resultType = method->getResultType(); - if (!resultType->isReferenceType() && (!resultType->isPointerType() || resultType->isObjCRetainableType())) { - S.Diag(method->getLocStart(), diag::warn_ns_attribute_wrong_return_type) + S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) << SourceRange(loc) - << attr.getName() << /*method*/ 1 << /*non-retainable pointer*/ 2; + << attr.getName() << (method ? /*method*/ 1 : /*property*/ 2) << /*non-retainable pointer*/ 2; // Drop the attribute. return; } - method->addAttr(::new (S.Context) + D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context, attr.getAttributeSpellingListIndex())); } diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 803bd7de88..cd5be5e35d 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -1943,6 +1943,10 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, if (property->hasAttr()) GetterMethod->addAttr( ::new (Context) NSReturnsNotRetainedAttr(Loc, Context)); + + if (property->hasAttr()) + GetterMethod->addAttr( + ::new (Context) ObjCReturnsInnerPointerAttr(Loc, Context)); if (getLangOpts().ObjCAutoRefCount) CheckARCMethodDecl(GetterMethod); diff --git a/test/CodeGenObjC/arc-precise-lifetime.m b/test/CodeGenObjC/arc-precise-lifetime.m index cb809a2b78..e15d5d4835 100644 --- a/test/CodeGenObjC/arc-precise-lifetime.m +++ b/test/CodeGenObjC/arc-precise-lifetime.m @@ -25,7 +25,8 @@ void test0() { // rdar://problem/9821110 @interface Test1 - (char*) interior __attribute__((objc_returns_inner_pointer)); -// Should we allow this on properties? +// Should we allow this on properties? Yes! see // rdar://14990439 +@property (nonatomic, readonly) char * PropertyReturnsInnerPointer __attribute__((objc_returns_inner_pointer)); @end extern Test1 *test1_helper(void); @@ -73,6 +74,50 @@ void test1b(void) { char *c = [ptr interior]; } +void test1c(void) { + // CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper() + // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* + // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) + // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* + // CHECK-NEXT: store [[TEST1]]* [[T3]] + // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]** + // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* + // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]]) + // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* + // CHECK-NEXT: [[T4:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_ + // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8* + // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast + // CHECK-NEXT: store i8* [[T6]], i8** + // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]** + // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* + // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release + // CHECK-NEXT: ret void + Test1 *ptr = test1_helper(); + char *pc = ptr.PropertyReturnsInnerPointer; +} + +void test1d(void) { + // CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper() + // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* + // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) + // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]* + // CHECK-NEXT: store [[TEST1]]* [[T3]] + // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]** + // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8* + // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retainAutorelease + // CHECK-NEXT: [[SIX:%.*]] = bitcast i8* [[T3]] to [[TEST1]]* + // CHECK-NEXT: [[SEVEN:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_ + // CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[SIX]] to i8* + // CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[EIGHT]], i8* [[SEVEN]]) + // CHECK-NEXT: store i8* [[CALL1]], i8** + // CHECK-NEXT: [[NINE:%.*]] = load [[TEST1]]** + // CHECK-NEXT: [[TEN:%.*]] = bitcast [[TEST1]]* [[NINE]] to i8* + // CHECK-NEXT: call void @objc_release(i8* [[TEN]]) + // CHECK-NEXT: ret void + __attribute__((objc_precise_lifetime)) Test1 *ptr = test1_helper(); + char *pc = ptr.PropertyReturnsInnerPointer; +} + @interface Test2 { @public id ivar; diff --git a/test/SemaObjC/arc-property-lifetime.m b/test/SemaObjC/arc-property-lifetime.m index 570c8d1af6..766a6141be 100644 --- a/test/SemaObjC/arc-property-lifetime.m +++ b/test/SemaObjC/arc-property-lifetime.m @@ -171,7 +171,10 @@ void foo(Baz *f) { // rdar://11253688 @interface Boom -@property (readonly) const void * innerPointer __attribute__((objc_returns_inner_pointer)); // expected-error {{'objc_returns_inner_pointer' attribute only applies to methods}} +{ + const void * innerPointerIvar __attribute__((objc_returns_inner_pointer)); // expected-error {{'objc_returns_inner_pointer' attribute only applies to methods and properties}} +} +@property (readonly) const void * innerPointer __attribute__((objc_returns_inner_pointer)); @end @interface Foo2 { -- 2.40.0