ARC writeback isn't supposed to apply to local indirect pointers,

only to pointers to locals.  But it should work inside blocks, too.

llvm-svn: 133969
This commit is contained in:
John McCall
2011-06-27 23:59:58 +00:00
parent 5f3ab2248c
commit 63f844494d
3 changed files with 62 additions and 40 deletions

View File

@@ -3195,24 +3195,24 @@ static void TryUserDefinedConversion(Sema &S,
enum InvalidICRKind { IIK_okay, IIK_nonlocal, IIK_nonscalar };
/// Determines whether this expression is an acceptable ICR source.
static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e) {
static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
bool isAddressOf) {
// Skip parens.
e = e->IgnoreParens();
// Skip address-of nodes.
if (UnaryOperator *op = dyn_cast<UnaryOperator>(e)) {
if (op->getOpcode() == UO_AddrOf)
return isInvalidICRSource(C, op->getSubExpr());
return isInvalidICRSource(C, op->getSubExpr(), /*addressof*/ true);
// Skip certain casts.
} else if (CastExpr *cast = dyn_cast<CastExpr>(e)) {
switch (cast->getCastKind()) {
} else if (CastExpr *ce = dyn_cast<CastExpr>(e)) {
switch (ce->getCastKind()) {
case CK_Dependent:
case CK_BitCast:
case CK_LValueBitCast:
case CK_LValueToRValue:
case CK_NoOp:
return isInvalidICRSource(C, cast->getSubExpr());
return isInvalidICRSource(C, ce->getSubExpr(), isAddressOf);
case CK_ArrayToPointerDecay:
return IIK_nonscalar;
@@ -3225,16 +3225,25 @@ static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e) {
}
// If we have a declaration reference, it had better be a local variable.
} else if (DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(e)) {
if (VarDecl *var = dyn_cast<VarDecl>(declRef->getDecl()))
return (var->hasLocalStorage() ? IIK_okay : IIK_nonlocal);
} else if (isa<DeclRefExpr>(e) || isa<BlockDeclRefExpr>(e)) {
if (!isAddressOf) return IIK_nonlocal;
VarDecl *var;
if (isa<DeclRefExpr>(e)) {
var = dyn_cast<VarDecl>(cast<DeclRefExpr>(e)->getDecl());
if (!var) return IIK_nonlocal;
} else {
var = cast<BlockDeclRefExpr>(e)->getDecl();
}
return (var->hasLocalStorage() ? IIK_okay : IIK_nonlocal);
// If we have a conditional operator, check both sides.
} else if (ConditionalOperator *cond = dyn_cast<ConditionalOperator>(e)) {
if (InvalidICRKind iik = isInvalidICRSource(C, cond->getLHS()))
if (InvalidICRKind iik = isInvalidICRSource(C, cond->getLHS(), isAddressOf))
return iik;
return isInvalidICRSource(C, cond->getRHS());
return isInvalidICRSource(C, cond->getRHS(), isAddressOf);
// These are never scalar.
} else if (isa<ArraySubscriptExpr>(e)) {
@@ -3254,7 +3263,7 @@ static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e) {
static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) {
assert(src->isRValue());
InvalidICRKind iik = isInvalidICRSource(S.Context, src);
InvalidICRKind iik = isInvalidICRSource(S.Context, src, false);
if (iik == IIK_okay) return;
S.Diag(src->getExprLoc(), diag::err_arc_nonlocal_writeback)

View File

@@ -592,3 +592,16 @@ int Test33(id someid) {
@synthesize newName2;
@end
void test35(void) {
extern void test36_helper(id*);
id x;
__strong id *xp = 0;
test36_helper(&x);
test36_helper(xp); // expected-error {{passing address of non-local object to __autoreleasing parameter for write-back}}
// rdar://problem/9665710
__block id y;
test36_helper(&y);
^{ test36_helper(&y); }();
}

View File

@@ -58,15 +58,15 @@ void test_f2() {
int &f3(id __autoreleasing *); // expected-note{{candidate function not viable: 1st argument ('__unsafe_unretained id *') has __unsafe_unretained ownership, but parameter has __autoreleasing ownership}}
void test_f3() {
id __strong *sip;
id __weak *wip;
id __autoreleasing *aip;
id __unsafe_unretained *uip;
id __strong sip;
id __weak wip;
id __autoreleasing aip;
id __unsafe_unretained uip;
int &ir1 = f3(sip);
int &ir2 = f3(wip);
int &ir3 = f3(aip);
f3(uip); // expected-error{{no matching function for call to 'f3'}}
int &ir1 = f3(&sip);
int &ir2 = f3(&wip);
int &ir3 = f3(&aip);
f3(&uip); // expected-error{{no matching function for call to 'f3'}}
}
// Writeback conversion vs. no conversion
@@ -74,15 +74,15 @@ int &f4(id __autoreleasing *);
float &f4(id __strong *);
void test_f4() {
id __strong *sip;
id __weak *wip;
id __autoreleasing *aip;
extern __weak id *weak_global_ptr;
id __strong sip;
id __weak wip;
id __autoreleasing aip;
extern __weak id weak_global_ptr;
float &fr1 = f4(sip);
int &ir1 = f4(wip);
int &ir2 = f4(aip);
int &ir3 = f4(weak_global_ptr); // expected-error{{passing address of non-local object to __autoreleasing parameter for write-back}}
float &fr1 = f4(&sip);
int &ir1 = f4(&wip);
int &ir2 = f4(&aip);
int &ir3 = f4(&weak_global_ptr); // expected-error{{passing address of non-local object to __autoreleasing parameter for write-back}}
}
// Writeback conversion vs. other conversion.
@@ -90,13 +90,13 @@ int &f5(id __autoreleasing *);
float &f5(id const __unsafe_unretained *);
void test_f5() {
id __strong *sip;
id __weak *wip;
id __autoreleasing *aip;
id __strong sip;
id __weak wip;
id __autoreleasing aip;
int &ir1 = f5(wip);
float &fr1 = f5(sip);
int &ir2 = f5(aip);
int &ir1 = f5(&wip);
float &fr1 = f5(&sip);
int &ir2 = f5(&aip);
}
@interface A
@@ -106,13 +106,13 @@ int &f6(id __autoreleasing *);
float &f6(id const __unsafe_unretained *);
void test_f6() {
A* __strong *sip;
A* __weak *wip;
A* __autoreleasing *aip;
A* __strong sip;
A* __weak wip;
A* __autoreleasing aip;
int &ir1 = f6(wip);
float &fr1 = f6(sip);
int &ir2 = f6(aip);
int &ir1 = f6(&wip);
float &fr1 = f6(&sip);
int &ir2 = f6(&aip);
}
// Reference binding