From b846381fc3099b2340ba8c74d16178203a60d9a0 Mon Sep 17 00:00:00 2001 From: John McCall Date: Thu, 4 Apr 2013 01:38:37 +0000 Subject: [PATCH] Be sure to check ARC conventions on the implicit method declarations of a property just in case the property's getter happens to be +1. We won't synthesize a getter for such a property, but we will allow the user to define a +1 method for it. rdar://13115896 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178731 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 1 + lib/Sema/SemaDeclObjC.cpp | 20 +++++++-------- lib/Sema/SemaObjCProperty.cpp | 8 ++++++ test/CodeGenObjC/arc-property.m | 45 +++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index d17557260e..5b93e513ea 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -6361,6 +6361,7 @@ public: ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty, bool IsInstance); + bool CheckARCMethodDecl(ObjCMethodDecl *method); bool inferObjCARCLifetime(ValueDecl *decl); ExprResult diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 5d16f3eae6..96a432a108 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -193,7 +193,7 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, /// \brief Check a method declaration for compatibility with the Objective-C /// ARC conventions. -static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { +bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) { ObjCMethodFamily family = method->getMethodFamily(); switch (family) { case OMF_None: @@ -207,17 +207,17 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { return false; case OMF_dealloc: - if (!S.Context.hasSameType(method->getResultType(), S.Context.VoidTy)) { + if (!Context.hasSameType(method->getResultType(), Context.VoidTy)) { SourceRange ResultTypeRange; if (const TypeSourceInfo *ResultTypeInfo = method->getResultTypeSourceInfo()) ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange(); if (ResultTypeRange.isInvalid()) - S.Diag(method->getLocation(), diag::error_dealloc_bad_result_type) + Diag(method->getLocation(), diag::error_dealloc_bad_result_type) << method->getResultType() << FixItHint::CreateInsertion(method->getSelectorLoc(0), "(void)"); else - S.Diag(method->getLocation(), diag::error_dealloc_bad_result_type) + Diag(method->getLocation(), diag::error_dealloc_bad_result_type) << method->getResultType() << FixItHint::CreateReplacement(ResultTypeRange, "void"); return true; @@ -226,11 +226,11 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { case OMF_init: // If the method doesn't obey the init rules, don't bother annotating it. - if (S.checkInitMethod(method, QualType())) + if (checkInitMethod(method, QualType())) return true; - method->addAttr(new (S.Context) NSConsumesSelfAttr(SourceLocation(), - S.Context)); + method->addAttr(new (Context) NSConsumesSelfAttr(SourceLocation(), + Context)); // Don't add a second copy of this attribute, but otherwise don't // let it be suppressed. @@ -249,8 +249,8 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { break; } - method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(), - S.Context)); + method->addAttr(new (Context) NSReturnsRetainedAttr(SourceLocation(), + Context)); return false; } @@ -3032,7 +3032,7 @@ Decl *Sema::ActOnMethodDeclaration( bool ARCError = false; if (getLangOpts().ObjCAutoRefCount) - ARCError = CheckARCMethodDecl(*this, ObjCMethod); + ARCError = CheckARCMethodDecl(ObjCMethod); // Infer the related result type when possible. if (!ARCError && RTC == Sema::RTC_Compatible && diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 824a249084..68fb07f8fe 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -1936,6 +1936,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, if (property->hasAttr()) GetterMethod->addAttr( ::new (Context) NSReturnsNotRetainedAttr(Loc, Context)); + + if (getLangOpts().ObjCAutoRefCount) + CheckARCMethodDecl(GetterMethod); } else // A user declared getter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation @@ -1984,6 +1987,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, // and the real context should be the same. if (lexicalDC) SetterMethod->setLexicalDeclContext(lexicalDC); + + // It's possible for the user to have set a very odd custom + // setter selector that causes it to have a method family. + if (getLangOpts().ObjCAutoRefCount) + CheckARCMethodDecl(SetterMethod); } else // A user declared setter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation diff --git a/test/CodeGenObjC/arc-property.m b/test/CodeGenObjC/arc-property.m index 0e01fb7eda..dde02d7dd7 100644 --- a/test/CodeGenObjC/arc-property.m +++ b/test/CodeGenObjC/arc-property.m @@ -86,4 +86,49 @@ static Class theGlobalClass; // CHECK-NEXT: call void @objc_storeStrong(i8** [[T3]], i8* null) [[NUW]] // CHECK-NEXT: ret void +// rdar://13115896 +@interface Test3 +@property id copyMachine; +@end + +void test3(Test3 *t) { + id x = t.copyMachine; + x = [t copyMachine]; +} +// CHECK: define void @test3([[TEST3:%.*]]* +// Prologue. +// CHECK: [[T:%.*]] = alloca [[TEST3]]*, +// CHECK-NEXT: [[X:%.*]] = alloca i8*, +// Property access. +// CHECK: [[T0:%.*]] = load [[TEST3]]** [[T]], +// CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES +// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8* +// CHECK-NEXT: [[T2:%.*]] = call i8* bitcast ({{.*}} @objc_msgSend to {{.*}})(i8* [[T1]], i8* [[SEL]]) +// CHECK-NEXT: store i8* [[T2]], i8** [[X]], +// Message send. +// CHECK-NEXT: [[T0:%.*]] = load [[TEST3]]** [[T]], +// CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES +// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8* +// CHECK-NEXT: [[T2:%.*]] = call i8* bitcast ({{.*}} @objc_msgSend to {{.*}})(i8* [[T1]], i8* [[SEL]]) +// CHECK-NEXT: [[T3:%.*]] = load i8** [[X]], +// CHECK-NEXT: store i8* [[T2]], i8** [[X]], +// CHECK-NEXT: call void @objc_release(i8* [[T3]]) +// Epilogue. +// CHECK-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null) +// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST3]]** [[T]] to i8** +// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null) +// CHECK-NEXT: ret void + +@implementation Test3 +- (id) copyMachine { + extern id test3_helper(void); + return test3_helper(); +} +// CHECK: define internal i8* @"\01-[Test3 copyMachine]"( +// CHECK: [[T0:%.*]] = call i8* @test3_helper() +// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) +// CHECK-NEXT: ret i8* [[T1]] +- (void) setCopyMachine: (id) x {} +@end + // CHECK: attributes [[NUW]] = { nounwind } -- 2.40.0