aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r--lib/Sema/SemaDeclAttr.cpp30
1 files changed, 30 insertions, 0 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 61b7b3ee05..ad9b6ddba9 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -2767,6 +2767,33 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
};
}
+static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
+ const AttributeList &attr) {
+ SourceLocation loc = attr.getLoc();
+
+ ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D);
+
+ if (!isa<ObjCMethodDecl>(method)) {
+ S.Diag(method->getLocStart(), diag::err_attribute_wrong_decl_type)
+ << SourceRange(loc, loc) << attr.getName() << 13 /* methods */;
+ return;
+ }
+
+ // Check that the method returns a normal pointer.
+ QualType resultType = method->getResultType();
+ if (!resultType->isPointerType() || resultType->isObjCRetainableType()) {
+ S.Diag(method->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
+ << SourceRange(loc)
+ << attr.getName() << /*method*/ 1 << /*non-retainable pointer*/ 2;
+
+ // Drop the attribute.
+ return;
+ }
+
+ method->addAttr(
+ ::new (S.Context) ObjCReturnsInnerPointerAttr(loc, S.Context));
+}
+
static void handleObjCOwnershipAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (hasDeclarator(D)) return;
@@ -2969,6 +2996,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_objc_precise_lifetime:
handleObjCPreciseLifetimeAttr(S, D, Attr); break;
+ case AttributeList::AT_objc_returns_inner_pointer:
+ handleObjCReturnsInnerPointerAttr(S, D, Attr); break;
+
// Checker-specific.
case AttributeList::AT_cf_consumed:
case AttributeList::AT_ns_consumed: handleNSConsumedAttr (S, D, Attr); break;