ARC: make assignment to 'self' within class methods illegal. Fixes <rdar://problem/10416568>.

llvm-svn: 144572
This commit is contained in:
Ted Kremenek 2011-11-14 21:59:25 +00:00
parent 8e7fbcc3e4
commit 1fcdaa9c05
4 changed files with 30 additions and 14 deletions

View File

@ -1482,9 +1482,12 @@ implementation.</p></div>
<p>The <tt>self</tt> 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, <tt>self</tt> is implicitly <tt>const</tt> unless the method is
in the <a href="#family.semantics.init"><tt>init</tt> family</a>.</p>
during a message send to that object.</p>
<p>To make this safe, for Objective-C instance methods <tt>self</tt> is
implicitly <tt>const</tt> unless the method is in the <a
href="#family.semantics.init"><tt>init</tt> family</a>. Further, <tt>self</tt>
is <b>always</b> implicitly <tt>const</tt> within a class method.</p>
<div class="rationale"><p>Rationale: the cost of
retaining <tt>self</tt> in all methods was found to be prohibitive, as

View File

@ -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">;

View File

@ -580,17 +580,26 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
bool selfIsPseudoStrong = false;
bool selfIsConsumed = false;
if (isInstanceMethod() && Context.getLangOptions().ObjCAutoRefCount) {
selfIsConsumed = hasAttr<NSConsumesSelfAttr>();
if (Context.getLangOptions().ObjCAutoRefCount) {
if (isInstanceMethod()) {
selfIsConsumed = hasAttr<NSConsumesSelfAttr>();
// '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);
// '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) {
// 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;
}

View File

@ -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