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