]> granicus.if.org Git - clang/commitdiff
objc-arc: Check on a variety of unsafe assignment of retained
authorFariborz Jahanian <fjahanian@apple.com>
Fri, 24 Jun 2011 18:25:34 +0000 (18:25 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Fri, 24 Jun 2011 18:25:34 +0000 (18:25 +0000)
objects.  // rdar://9495837

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133806 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExpr.cpp
test/SemaObjC/arc-unsafe-assigns.m [new file with mode: 0644]
test/SemaObjC/arc.m

index bced5ee48a5e2ff95054d8b60d639d23d7bb1a1e..d514c1b19f002b64d1fef3bc85996781869202f1 100644 (file)
@@ -2603,6 +2603,9 @@ def warn_arc_non_pod_class_with_object_member : Warning<
 def warn_arc_retained_assign : Warning<
   "assigning retained object to %select{weak|unsafe_unretained}0 variable">,
   InGroup<ARCUnsafeRetainedAssign>;
+def warn_arc_retained_property_assign : Warning<
+  "assigning retained object to unsafe property">,
+  InGroup<ARCUnsafeRetainedAssign>;
 def warn_arc_trivial_member_function_with_object_member : Warning<
   "%0 cannot be shared between ARC and non-ARC "
   "code; add a non-trivial %select{copy constructor|copy assignment operator|"
index 7cb060dcdf8bb191ee8e1663533d1e524cb11a2d..1fa80fc63ee9a4665e5e950db4b23f31028b2f32 100644 (file)
@@ -5644,9 +5644,13 @@ public:
   void checkRetainCycles(ObjCMessageExpr *msg);
   void checkRetainCycles(Expr *receiver, Expr *argument);
 
-  /// checkWeakUnsafeAssigns - Check whether +1 expr is being assigned
-  /// to weak/__unsafe_unretained.
-  void checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS);
+  /// checkUnsafeAssigns - Check whether +1 expr is being assigned
+  /// to weak/__unsafe_unretained type.
+  bool checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS);
+
+  /// checkUnsafeExprAssigns - Check whether +1 expr is being assigned
+  /// to weak/__unsafe_unretained expression.
+  void checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, Expr *RHS);
 
   /// CheckMessageArgumentTypes - Check types in an Obj-C message send.
   /// \param Method - May be null.
index 6a09bf0e40c628251061066507a8b85b4057e826..35b6e9abc9c35d6721e0e32bf609ade3f463a433 100644 (file)
@@ -3720,15 +3720,50 @@ void Sema::checkRetainCycles(Expr *receiver, Expr *argument) {
     diagnoseRetainCycle(*this, capturer, owner);
 }
 
-void Sema::checkUnsafeAssigns(SourceLocation Loc,
+bool Sema::checkUnsafeAssigns(SourceLocation Loc,
                               QualType LHS, Expr *RHS) {
   Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
   if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
-    return;
-  if (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS))
-    if (cast->getCastKind() == CK_ObjCConsumeObject)
+    return false;
+  // strip off any implicit cast added to get to the one arc-specific
+  while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
+    if (cast->getCastKind() == CK_ObjCConsumeObject) {
       Diag(Loc, diag::warn_arc_retained_assign)
         << (LT == Qualifiers::OCL_ExplicitNone) 
         << RHS->getSourceRange();
+      return true;
+    }
+    RHS = cast->getSubExpr();
+  }
+  return false;
 }
 
+void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
+                              Expr *LHS, Expr *RHS) {
+  QualType LHSType = LHS->getType();
+  if (checkUnsafeAssigns(Loc, LHSType, RHS))
+    return;
+  Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime();
+  // FIXME. Check for other life times.
+  if (LT != Qualifiers::OCL_None)
+    return;
+  
+  if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
+    if (PRE->isImplicitProperty())
+      return;
+    const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
+    if (!PD)
+      return;
+    
+    unsigned Attributes = PD->getPropertyAttributes();
+    if (Attributes & ObjCPropertyDecl::OBJC_PR_assign)
+      while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
+        if (cast->getCastKind() == CK_ObjCConsumeObject) {
+          Diag(Loc, diag::warn_arc_retained_property_assign)
+          << RHS->getSourceRange();
+          return;
+        }
+        RHS = cast->getSubExpr();
+      }
+  }
+}
index 3fdfb63c10b9df625707386ede7139a15980a318..892b882df53c04faa4b2d6804aa9f5064008fa33 100644 (file)
@@ -6735,8 +6735,8 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS,
     if (ConvTy == Compatible) {
       if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong)
         checkRetainCycles(LHS, RHS.get());
-      else
-        checkUnsafeAssigns(Loc, LHSType, RHS.get());
+      else if (getLangOptions().ObjCAutoRefCount)
+        checkUnsafeExprAssigns(Loc, LHS, RHS.get());
     }
   } else {
     // Compound assignment "x += y"
diff --git a/test/SemaObjC/arc-unsafe-assigns.m b/test/SemaObjC/arc-unsafe-assigns.m
new file mode 100644 (file)
index 0000000..be8f902
--- /dev/null
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify %s
+// rdar://9495837
+
+@interface Foo {
+  __unsafe_unretained id unsafe_ivar;
+}
+
+@property (assign,nonatomic) id unsafe_prop;
+
+- (id)init;
++ (id)new;
++ (id)alloc;
+
+-(void)Meth;
+@end
+
+@implementation Foo
+@synthesize unsafe_prop;
+-(id)init { return self; }
++(id)new { return 0; }
++(id)alloc { return 0; }
+
+-(void)Meth {
+  self.unsafe_prop = [Foo new]; // expected-warning {{assigning retained object to unsafe property}}
+  self->unsafe_ivar = [Foo new]; // expected-warning {{assigning retained object to unsafe_unretained}}
+  self.unsafe_prop = [[Foo alloc] init]; // expected-warning {{assigning retained object to unsafe property}}
+  self->unsafe_ivar = [[Foo alloc] init]; // expected-warning {{assigning retained object to unsafe_unretained}}
+
+  __unsafe_unretained id unsafe_var;
+  unsafe_var = [Foo new]; // expected-warning {{assigning retained object to unsafe_unretained}}
+  unsafe_var = [[Foo alloc] init]; // expected-warning {{assigning retained object to unsafe_unretained}}
+}
+@end
+
+void bar(Foo *f) {
+  f.unsafe_prop = [Foo new]; // expected-warning {{assigning retained object to unsafe property}}
+
+  __unsafe_unretained id unsafe_var;
+  unsafe_var = [Foo new]; // expected-warning {{assigning retained object to unsafe_unretained}}
+  unsafe_var = [[Foo alloc] init]; // expected-warning {{assigning retained object to unsafe_unretained}}
+}
index 4877930ea0d614e882c3704edb439c42909df41c..3a548e084a59fc6cca131212171850af01526f77 100644 (file)
@@ -518,12 +518,12 @@ typedef struct Bark Bark;
 
 // rdar://9495837
 @interface Test30
-- (id) new;
++ (id) new;
 - (void)Meth;
 @end
 
 @implementation Test30
-- (id) new { return 0; }
++ (id) new { return 0; }
 - (void) Meth {
   __weak id x = [Test30 new]; // expected-warning {{assigning retained object to weak variable}}
   id __unsafe_unretained u = [Test30 new]; // expected-warning {{assigning retained object to unsafe_unretained variable}}