From 921c14322977253a60dcb171f45e468c95fe41f8 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Fri, 24 Jun 2011 18:25:34 +0000 Subject: [PATCH] objc-arc: Check on a variety of unsafe assignment of retained 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 | 3 ++ include/clang/Sema/Sema.h | 10 +++-- lib/Sema/SemaChecking.cpp | 43 ++++++++++++++++++++-- lib/Sema/SemaExpr.cpp | 4 +- test/SemaObjC/arc-unsafe-assigns.m | 41 +++++++++++++++++++++ test/SemaObjC/arc.m | 4 +- 6 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 test/SemaObjC/arc-unsafe-assigns.m diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index bced5ee48a..d514c1b19f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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; +def warn_arc_retained_property_assign : Warning< + "assigning retained object to unsafe property">, + InGroup; 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|" diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 7cb060dcdf..1fa80fc63e 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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. diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 6a09bf0e40..35b6e9abc9 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -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(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(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(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(RHS)) { + if (cast->getCastKind() == CK_ObjCConsumeObject) { + Diag(Loc, diag::warn_arc_retained_property_assign) + << RHS->getSourceRange(); + return; + } + RHS = cast->getSubExpr(); + } + } +} diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 3fdfb63c10..892b882df5 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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 index 0000000000..be8f90295e --- /dev/null +++ b/test/SemaObjC/arc-unsafe-assigns.m @@ -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}} +} diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m index 4877930ea0..3a548e084a 100644 --- a/test/SemaObjC/arc.m +++ b/test/SemaObjC/arc.m @@ -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}}