<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><br><div><div>On Sep 19, 2013, at 9:46 AM, Aaron Ballman <<a href="mailto:aaron@aaronballman.com">aaron@aaronballman.com</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite">On Thu, Sep 19, 2013 at 12:37 PM, Fariborz Jahanian <<a href="mailto:fjahanian@apple.com">fjahanian@apple.com</a>> wrote:<br><blockquote type="cite">Author: fjahanian<br>Date: Thu Sep 19 11:37:20 2013<br>New Revision: 191009<br><br>URL: <a href="http://llvm.org/viewvc/llvm-project?rev=191009&view=rev">http://llvm.org/viewvc/llvm-project?rev=191009&view=rev</a><br>Log:<br>ObjectiveC: Allow NS_RETURNS_INNER_POINTER annotation<br>of ObjectiveC properties to mean annotation of<br>NS_RETURNS_INNER_POINTER on its synthesized getter.<br>This also facilitates more migration to properties when<br>methods are annotated with NS_RETURNS_INNER_POINTER.<br>// <a href="rdar://14990439">rdar://14990439</a><br><br>Modified:<br>    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>    cfe/trunk/lib/Sema/SemaDeclAttr.cpp<br>    cfe/trunk/lib/Sema/SemaObjCProperty.cpp<br>    cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m<br>    cfe/trunk/test/SemaObjC/arc-property-lifetime.m<br><br>Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=191009&r1=191008&r2=191009&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=191009&r1=191008&r2=191009&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Sep 19 11:37:20 2013<br>@@ -2027,7 +2027,8 @@ def err_attribute_wrong_decl_type : Erro<br>   "variables, functions and labels|fields and global variables|structs|"<br>   "variables, functions and tag types|thread-local variables|"<br>   "variables and fields|variables, data members and tag types|"<br>-  "types and namespaces|Objective-C interfaces}1">;<br>+  "types and namespaces|Objective-C interfaces|"<br>+  "methods and properties}1">;<br> def warn_type_attribute_wrong_type : Warning<<br>   "'%0' only applies to %select{function|pointer|"<br>   "Objective-C object or block pointer}1 types; type here is %2">,<br>@@ -2395,7 +2396,7 @@ def note_attribute_overloadable_prev_ove<br> def err_attribute_overloadable_no_prototype : Error<<br>   "'overloadable' function %0 must have a prototype">;<br> def warn_ns_attribute_wrong_return_type : Warning<<br>-  "%0 attribute only applies to %select{functions|methods}1 that "<br>+  "%0 attribute only applies to %select{functions|methods|properties}1 that "<br>   "return %select{an Objective-C object|a pointer|a non-retainable pointer}2">,<br>   InGroup<IgnoredAttributes>;<br> def warn_ns_attribute_wrong_parameter_type : Warning<<br><br>Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=191009&r1=191008&r2=191009&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=191009&r1=191008&r2=191009&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Sep 19 11:37:20 2013<br>@@ -54,7 +54,8 @@ enum AttributeDeclKind {<br>   ExpectedVariableOrField,<br>   ExpectedVariableFieldOrTag,<br>   ExpectedTypeOrNamespace,<br>-  ExpectedObjectiveCInterface<br>+  ExpectedObjectiveCInterface,<br>+  ExpectedMethodOrProperty<br> };<br><br> //===----------------------------------------------------------------------===//<br>@@ -1476,7 +1477,7 @@ static void handleOwnershipAttr(Sema &S,<br>         break;<br>     }<br>     if (-1 != Err) {<br>-      S.Diag(AL.getLoc(), diag::err_ownership_type) << AL.getName() << Err<br>+      S.Diag(AL.getLoc(), diag::err_ownership_type) << AL.getName() << Err<br>         << Ex->getSourceRange();<br>       return;<br>     }<br>@@ -4145,29 +4146,34 @@ static void handleNSReturnsRetainedAttr(<br> static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,<br>                                               const AttributeList &attr) {<br>   SourceLocation loc = attr.getLoc();<br>-<br>+  QualType resultType;<br>+<br>   ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D);<br><br>   if (!method) {<br>-    S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)<br>-      << SourceRange(loc, loc) << attr.getName() << ExpectedMethod;<br>-    return;<br>+    ObjCPropertyDecl *property = dyn_cast<ObjCPropertyDecl>(D);<br>+    if (!property) {<br>+      S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)<br>+        << SourceRange(loc, loc) << attr.getName() << ExpectedMethodOrProperty;<br>+      return;<br>+    }<br>+    resultType = property->getType();<br></blockquote><br>Please update the subjects in Attr.td for this attribute so it stays<br>in sync with what the semantics are checking for.<br><br><blockquote type="cite">   }<br>+  else<br>+    // Check that the method returns a normal pointer.<br>+    resultType = method->getResultType();<br><br>-  // Check that the method returns a normal pointer.<br>-  QualType resultType = method->getResultType();<br>-<br>   if (!resultType->isReferenceType() &&<br>       (!resultType->isPointerType() || resultType->isObjCRetainableType())) {<br>-    S.Diag(method->getLocStart(), diag::warn_ns_attribute_wrong_return_type)<br>+    S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type)<br>       << SourceRange(loc)<br>-      << attr.getName() << /*method*/ 1 << /*non-retainable pointer*/ 2;<br>+    << attr.getName() << (method ? /*method*/ 1 : /*property*/ 2) << /*non-retainable pointer*/ 2;<br></blockquote><br>A local enumeration would be better than comments, but meh.<br><br><blockquote type="cite"><br>     // Drop the attribute.<br>     return;<br>   }<br><br>-  method->addAttr(::new (S.Context)<br>+  D->addAttr(::new (S.Context)<br>                   ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context,<br>                                               attr.getAttributeSpellingListIndex()));<br> }<br><br>Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=191009&r1=191008&r2=191009&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=191009&r1=191008&r2=191009&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Thu Sep 19 11:37:20 2013<br>@@ -1943,6 +1943,10 @@ void Sema::ProcessPropertyDecl(ObjCPrope<br>     if (property->hasAttr<NSReturnsNotRetainedAttr>())<br>       GetterMethod->addAttr(<br>         ::new (Context) NSReturnsNotRetainedAttr(Loc, Context));<br>+<br>+    if (property->hasAttr<ObjCReturnsInnerPointerAttr>())<br>+      GetterMethod->addAttr(<br>+        ::new (Context) ObjCReturnsInnerPointerAttr(Loc, Context));<br><br>     if (getLangOpts().ObjCAutoRefCount)<br>       CheckARCMethodDecl(GetterMethod);<br><br>Modified: cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m?rev=191009&r1=191008&r2=191009&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m?rev=191009&r1=191008&r2=191009&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m (original)<br>+++ cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m Thu Sep 19 11:37:20 2013<br>@@ -25,7 +25,8 @@ void test0() {<br> // <a href="rdar://problem/9821110">rdar://problem/9821110</a><br> @interface Test1<br> - (char*) interior __attribute__((objc_returns_inner_pointer));<br>-// Should we allow this on properties?<br>+// Should we allow this on properties? Yes! see // <a href="rdar://14990439">rdar://14990439</a><br>+@property (nonatomic, readonly) char * PropertyReturnsInnerPointer __attribute__((objc_returns_inner_pointer));<br> @end<br> extern Test1 *test1_helper(void);<br><br>@@ -73,6 +74,50 @@ void test1b(void) {<br>   char *c = [ptr interior];<br> }<br><br>+void test1c(void) {<br>+  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()<br>+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*<br>+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])<br>+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*<br>+  // CHECK-NEXT: store [[TEST1]]* [[T3]]<br>+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**<br>+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*<br>+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])<br>+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*<br>+  // CHECK-NEXT: [[T4:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_<br>+  // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*<br>+  // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast<br>+  // CHECK-NEXT: store i8* [[T6]], i8**<br>+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**<br>+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*<br>+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release<br>+  // CHECK-NEXT: ret void<br>+  Test1 *ptr = test1_helper();<br>+  char *pc = ptr.PropertyReturnsInnerPointer;<br>+}<br>+<br>+void test1d(void) {<br>+  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()<br>+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*<br>+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])<br>+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*<br>+  // CHECK-NEXT: store [[TEST1]]* [[T3]]<br>+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**<br>+  // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*<br>+  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retainAutorelease<br>+  // CHECK-NEXT: [[SIX:%.*]] = bitcast i8* [[T3]] to [[TEST1]]*<br>+  // CHECK-NEXT: [[SEVEN:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_<br>+  // CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[SIX]] to i8*<br>+  // CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[EIGHT]], i8* [[SEVEN]])<br>+  // CHECK-NEXT: store i8* [[CALL1]], i8**<br>+  // CHECK-NEXT: [[NINE:%.*]] = load [[TEST1]]**<br>+  // CHECK-NEXT: [[TEN:%.*]] = bitcast [[TEST1]]* [[NINE]] to i8*<br>+  // CHECK-NEXT: call void @objc_release(i8* [[TEN]])<br>+  // CHECK-NEXT: ret void<br>+  __attribute__((objc_precise_lifetime)) Test1 *ptr = test1_helper();<br>+  char *pc = ptr.PropertyReturnsInnerPointer;<br>+}<br>+<br> @interface Test2 {<br> @public<br>   id ivar;<br><br>Modified: cfe/trunk/test/SemaObjC/arc-property-lifetime.m<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-property-lifetime.m?rev=191009&r1=191008&r2=191009&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-property-lifetime.m?rev=191009&r1=191008&r2=191009&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/SemaObjC/arc-property-lifetime.m (original)<br>+++ cfe/trunk/test/SemaObjC/arc-property-lifetime.m Thu Sep 19 11:37:20 2013<br>@@ -171,7 +171,10 @@ void foo(Baz *f) {<br><br> // <a href="rdar://11253688">rdar://11253688</a><br> @interface Boom<br>-@property (readonly) const void * innerPointer __attribute__((objc_returns_inner_pointer)); // expected-error {{'objc_returns_inner_pointer' attribute only applies to methods}}<br>+{<br>+  const void * innerPointerIvar __attribute__((objc_returns_inner_pointer)); // expected-error {{'objc_returns_inner_pointer' attribute only applies to methods and properties}}<br>+}<br>+@property (readonly) const void * innerPointer __attribute__((objc_returns_inner_pointer));<br> @end<br><br> @interface Foo2 {<br></blockquote><br>Missing test cases for the changes in SemaDeclAttr.cpp; please add.<br></blockquote><div><br></div>Sure. In r<span style="font-family: Menlo; font-size: 11px;">191016.</span></div><div><font face="Menlo"><span style="font-size: 11px;">- Fariborz</span></font></div><div><font face="Menlo"><span style="font-size: 11px;"><br></span></font><blockquote type="cite"><br>Thanks!<br><br>~Aaron<br></blockquote></div><br></body></html>