From: Ted Kremenek
Date: Mon, 14 Nov 2011 21:59:25 +0000 (+0000)
Subject: ARC: make assignment to 'self' within class methods illegal. Fixes .
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144572 91177308-0d34-0410-b5e6-96231b3b80d8
---
diff --git a/docs/AutomaticReferenceCounting.html b/docs/AutomaticReferenceCounting.html
index ab7debf20c..0265bbdd38 100644
--- a/docs/AutomaticReferenceCounting.html
+++ b/docs/AutomaticReferenceCounting.html
@@ -1482,9 +1482,12 @@ implementation.
The self parameter variable of an Objective-C method is
never actually retained by the implementation. It is undefined
behavior, or at least dangerous, to cause an object to be deallocated
-during a message send to that object. To make this
-safe, self is implicitly const unless the method is
-in the init family.
+during a message send to that object.
+
+To make this safe, for Objective-C instance methods self is
+implicitly const unless the method is in the init family. Further, self
+is always implicitly const within a class method.
Rationale: the cost of
retaining self in all methods was found to be prohibitive, as
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index ad175e465f..312ea82458 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3078,8 +3078,10 @@ def note_arc_gained_method_convention : Note<
"declaration in interface is not in the '%select{alloc|copy|init|new}0' "
"family because %select{its result type is not an object pointer|"
"its result type is unrelated to its receiver type}1">;
-def err_typecheck_arr_assign_self : Error<
+def err_typecheck_arc_assign_self : Error<
"cannot assign to 'self' outside of a method in the init family">;
+def err_typecheck_arc_assign_self_class_method : Error<
+ "cannot assign to 'self' in a class method">;
def err_typecheck_arr_assign_enumeration : Error<
"fast enumeration variables can't be modified in ARC by default; "
"declare the variable __strong to allow this">;
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 35ee7c6ccd..766b673bde 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -580,17 +580,26 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
bool selfIsPseudoStrong = false;
bool selfIsConsumed = false;
- if (isInstanceMethod() && Context.getLangOptions().ObjCAutoRefCount) {
- selfIsConsumed = hasAttr();
-
- // 'self' is always __strong. It's actually pseudo-strong except
- // in init methods (or methods labeled ns_consumes_self), though.
- Qualifiers qs;
- qs.setObjCLifetime(Qualifiers::OCL_Strong);
- selfTy = Context.getQualifiedType(selfTy, qs);
-
- // In addition, 'self' is const unless this is an init method.
- if (getMethodFamily() != OMF_init && !selfIsConsumed) {
+
+ if (Context.getLangOptions().ObjCAutoRefCount) {
+ if (isInstanceMethod()) {
+ selfIsConsumed = hasAttr();
+
+ // 'self' is always __strong. It's actually pseudo-strong except
+ // in init methods (or methods labeled ns_consumes_self), though.
+ Qualifiers qs;
+ qs.setObjCLifetime(Qualifiers::OCL_Strong);
+ selfTy = Context.getQualifiedType(selfTy, qs);
+
+ // In addition, 'self' is const unless this is an init method.
+ if (getMethodFamily() != OMF_init && !selfIsConsumed) {
+ selfTy = selfTy.withConst();
+ selfIsPseudoStrong = true;
+ }
+ }
+ else {
+ assert(isClassMethod());
+ // 'self' is always const in class methods.
selfTy = selfTy.withConst();
selfIsPseudoStrong = true;
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d22a431d06..4f2f8c4eaf 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -7063,7 +7063,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
// - self
ObjCMethodDecl *method = S.getCurMethodDecl();
if (method && var == method->getSelfDecl())
- Diag = diag::err_typecheck_arr_assign_self;
+ Diag = method->isClassMethod()
+ ? diag::err_typecheck_arc_assign_self_class_method
+ : diag::err_typecheck_arc_assign_self;
// - fast enumeration variables
else