Forbid the block and lambda copy-capture of __autoreleasing variables
in ARC, under the usual reasoning limiting the use of __autoreleasing.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153725 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/docs/AutomaticReferenceCounting.html b/docs/AutomaticReferenceCounting.html
index ff65f3b..1416df5 100644
--- a/docs/AutomaticReferenceCounting.html
+++ b/docs/AutomaticReferenceCounting.html
@@ -1006,7 +1006,9 @@
<h1>Storage duration of <tt>__autoreleasing</tt> objects</h1>
<p>A program is ill-formed if it declares an <tt>__autoreleasing</tt>
-object of non-automatic storage duration.</p>
+object of non-automatic storage duration. A program is ill-formed
+if it captures an <tt>__autoreleasing</tt> object in a block or,
+unless by reference, in a C++11 lambda.</p>
<div class="rationale"><p>Rationale: autorelease pools are tied to the
current thread and scope by their nature. While it is possible to
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 9dd04b9..3078010 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3270,6 +3270,9 @@
def err_arc_autoreleasing_var : Error<
"%select{__block variables|global variables|fields|ivars}0 cannot have "
"__autoreleasing ownership">;
+def err_arc_autoreleasing_capture : Error<
+ "cannot capture __autoreleasing variable in a "
+ "%select{block|lambda by copy}0">;
def err_arc_thread_ownership : Error<
"thread-local variable has non-trivial ownership: type is %0">;
def err_arc_indirect_no_ownership : Error<
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 6b30643..88ef8cd 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -10087,6 +10087,17 @@
return true;
}
+ // Forbid the block-capture of autoreleasing variables.
+ if (CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
+ if (BuildAndDiagnose) {
+ Diag(Loc, diag::err_arc_autoreleasing_capture)
+ << /*block*/ 0;
+ Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return true;
+ }
+
if (HasBlocksAttr || CaptureType->isReferenceType()) {
// Block capture by reference does not change the capture or
// declaration reference types.
@@ -10179,6 +10190,16 @@
if (!RefType->getPointeeType()->isFunctionType())
CaptureType = RefType->getPointeeType();
}
+
+ // Forbid the lambda copy-capture of autoreleasing variables.
+ if (CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
+ if (BuildAndDiagnose) {
+ Diag(Loc, diag::err_arc_autoreleasing_capture) << /*lambda*/ 1;
+ Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return true;
+ }
}
// Capture this variable in the lambda.
diff --git a/test/SemaObjC/arc-invalid.m b/test/SemaObjC/arc-invalid.m
index b07460d..c736ed4 100644
--- a/test/SemaObjC/arc-invalid.m
+++ b/test/SemaObjC/arc-invalid.m
@@ -11,3 +11,8 @@
void test0(id p) {
takeBlock(^{ [p foo] + p; }); // expected-error {{invalid operands to binary expression}}
}
+
+void test1(void) {
+ __autoreleasing id p; // expected-note {{'p' declared here}}
+ takeBlock(^{ (void) p; }); // expected-error {{cannot capture __autoreleasing variable in a block}}
+}
diff --git a/test/SemaObjCXX/arc-0x.mm b/test/SemaObjCXX/arc-0x.mm
index be9f1dc..28eec51 100644
--- a/test/SemaObjCXX/arc-0x.mm
+++ b/test/SemaObjCXX/arc-0x.mm
@@ -30,3 +30,24 @@
} @catch (auto e) { // expected-error {{'auto' not allowed in exception declaration}}
}
}
+
+// rdar://problem/11068137
+void test1a() {
+ __autoreleasing id p; // expected-note 2 {{'p' declared here}}
+ (void) [&p] {};
+ (void) [p] {}; // expected-error {{cannot capture __autoreleasing variable in a lambda by copy}}
+ (void) [=] { (void) p; }; // expected-error {{cannot capture __autoreleasing variable in a lambda by copy}}
+}
+void test1b() {
+ __autoreleasing id v;
+ __autoreleasing id &p = v; // expected-note 2 {{'p' declared here}}
+ (void) [&p] {};
+ (void) [p] {}; // expected-error {{cannot capture __autoreleasing variable in a lambda by copy}}
+ (void) [=] { (void) p; }; // expected-error {{cannot capture __autoreleasing variable in a lambda by copy}}
+}
+void test1c() {
+ __autoreleasing id v; // expected-note {{'v' declared here}}
+ __autoreleasing id &p = v;
+ (void) ^{ (void) p; };
+ (void) ^{ (void) v; }; // expected-error {{cannot capture __autoreleasing variable in a block}}
+}