objc-arc: Check on a variety of unsafe assignment of retained

objects.  // rdar://9495837

llvm-svn: 133806
This commit is contained in:
Fariborz Jahanian 2011-06-24 18:25:34 +00:00
parent cb8fa3ec1d
commit 5f98da0ea2
6 changed files with 94 additions and 11 deletions

View 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|"

View 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.

View 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();
}
}
}

View 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"

View File

@ -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}}
}

View 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}}