]> granicus.if.org Git - clang/commitdiff
ObjectiveC: Allow NS_RETURNS_INNER_POINTER annotation
authorFariborz Jahanian <fjahanian@apple.com>
Thu, 19 Sep 2013 16:37:20 +0000 (16:37 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Thu, 19 Sep 2013 16:37:20 +0000 (16:37 +0000)
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
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaObjCProperty.cpp
test/CodeGenObjC/arc-precise-lifetime.m
test/SemaObjC/arc-property-lifetime.m

index 152149e4bd24976308648400f9f07f3183850c4b..9a6e9d0ff06c2fd01af972f82cb3cbc5fe490e16 100644 (file)
@@ -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<IgnoredAttributes>;
 def warn_ns_attribute_wrong_parameter_type : Warning<
index 10ff4b8b942edc2a9956d8f81d8a265030424004..d9e997244979b01432cfa7eda45c6159442fd90b 100644 (file)
@@ -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\r
+      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<ObjCMethodDecl>(D);
 
   if (!method) {
-    S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
-      << SourceRange(loc, loc) << attr.getName() << ExpectedMethod;
-    return;
+    ObjCPropertyDecl *property = dyn_cast<ObjCPropertyDecl>(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()));
 }
index 803bd7de881fad50c5134b6ca7dd737ce3f0756c..cd5be5e35db75c6e16d529c9e578c73698195f50 100644 (file)
@@ -1943,6 +1943,10 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
     if (property->hasAttr<NSReturnsNotRetainedAttr>())
       GetterMethod->addAttr(
         ::new (Context) NSReturnsNotRetainedAttr(Loc, Context));
+    
+    if (property->hasAttr<ObjCReturnsInnerPointerAttr>())
+      GetterMethod->addAttr(
+        ::new (Context) ObjCReturnsInnerPointerAttr(Loc, Context));
 
     if (getLangOpts().ObjCAutoRefCount)
       CheckARCMethodDecl(GetterMethod);
index cb809a2b78146a9dba8de90f26baf0ce0d752b58..e15d5d4835ce31c08df405d76f7ba79c6eacd8a3 100644 (file)
@@ -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;
index 570c8d1af6042debfa9bf95053051d70358e78ef..766a6141be67a7dbb141ee2a79e6d4f499fd9983 100644 (file)
@@ -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 {