aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaInit.cpp33
-rw-r--r--test/SemaObjC/arc.m13
-rw-r--r--test/SemaObjCXX/arc-overloading.mm60
3 files changed, 64 insertions, 42 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 9891500efa..16ba2a2910 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -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)
diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m
index 8d42d101dd..1202a2654e 100644
--- a/test/SemaObjC/arc.m
+++ b/test/SemaObjC/arc.m
@@ -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); }();
+}
diff --git a/test/SemaObjCXX/arc-overloading.mm b/test/SemaObjCXX/arc-overloading.mm
index 8141171eaf..2bce4bc894 100644
--- a/test/SemaObjCXX/arc-overloading.mm
+++ b/test/SemaObjCXX/arc-overloading.mm
@@ -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;
-
- int &ir1 = f3(sip);
- int &ir2 = f3(wip);
- int &ir3 = f3(aip);
- f3(uip); // expected-error{{no matching function for call to 'f3'}}
+ 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'}}
}
// 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;
-
- 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}}
+ 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}}
}
// 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