From b5dd2cb13c958e1a85bade1ead9ac5b3a8d7191c Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Tue, 29 May 2012 19:56:01 +0000 Subject: [PATCH] objective-c: fix a sema and IRGen crash when property getter result type is safe but does not match with property type resulting in spurious warning followed by crash in IRGen. // rdar://11515196 llvm-svn: 157641 --- clang/lib/CodeGen/CGObjC.cpp | 15 ++++---- clang/lib/CodeGen/CodeGenFunction.h | 1 + clang/lib/Sema/SemaObjCProperty.cpp | 6 ++-- .../getter-property-type-mismatch.m | 35 +++++++++++++++++++ clang/test/SemaObjC/property-typecheck-1.m | 12 +++---- 5 files changed, 54 insertions(+), 15 deletions(-) create mode 100644 clang/test/CodeGenObjC/getter-property-type-mismatch.m diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index a10822b75769..254f63c863b3 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -30,7 +30,7 @@ typedef llvm::PointerIntPair TryEmitResult; static TryEmitResult tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e); static RValue AdjustRelatedResultType(CodeGenFunction &CGF, - const Expr *E, + QualType ET, const ObjCMethodDecl *Method, RValue Result); @@ -202,20 +202,20 @@ llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) { /// \brief Adjust the type of the result of an Objective-C message send /// expression when the method has a related result type. static RValue AdjustRelatedResultType(CodeGenFunction &CGF, - const Expr *E, + QualType ExpT, const ObjCMethodDecl *Method, RValue Result) { if (!Method) return Result; if (!Method->hasRelatedResultType() || - CGF.getContext().hasSameType(E->getType(), Method->getResultType()) || + CGF.getContext().hasSameType(ExpT, Method->getResultType()) || !Result.isScalar()) return Result; // We have applied a related result type. Cast the rvalue appropriately. return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(), - CGF.ConvertType(E->getType()))); + CGF.ConvertType(ExpT))); } /// Decide whether to extend the lifetime of the receiver of a @@ -401,7 +401,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, Builder.CreateStore(newSelf, selfAddr); } - return AdjustRelatedResultType(*this, E, method, result); + return AdjustRelatedResultType(*this, E->getType(), method, result); } namespace { @@ -710,7 +710,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, assert(OMD && "Invalid call to generate getter (empty method)"); StartObjCMethod(OMD, IMP->getClassInterface(), OMD->getLocStart()); - generateObjCGetterBody(IMP, PID, AtomicHelperFn); + generateObjCGetterBody(IMP, PID, OMD, AtomicHelperFn); FinishFunction(); } @@ -772,6 +772,7 @@ static void emitCPPObjectAtomicGetterCall(CodeGenFunction &CGF, void CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, const ObjCPropertyImplDecl *propImpl, + const ObjCMethodDecl *GetterMethodDecl, llvm::Constant *AtomicHelperFn) { // If there's a non-trivial 'get' expression, we just have to emit that. if (!hasTrivialGetExpr(propImpl)) { @@ -905,6 +906,8 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, } value = Builder.CreateBitCast(value, ConvertType(propType)); + value = Builder.CreateBitCast(value, + ConvertType(GetterMethodDecl->getResultType())); } EmitReturnOfRValue(RValue::get(value), propType); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 91022de59e1e..de7e89e3911b 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1310,6 +1310,7 @@ public: const ObjCPropertyImplDecl *PID); void generateObjCGetterBody(const ObjCImplementationDecl *classImpl, const ObjCPropertyImplDecl *propImpl, + const ObjCMethodDecl *GetterMothodDecl, llvm::Constant *AtomicHelperFn); void GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 88de7d315e13..fb49e9f50cc7 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -1114,9 +1114,9 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, isa(GetterType)) compat = Context.canAssignObjCInterfaces( - PropertyIvarType->getAs(), - GetterType->getAs()); - else if (CheckAssignmentConstraints(Loc, PropertyIvarType, GetterType) + GetterType->getAs(), + PropertyIvarType->getAs()); + else if (CheckAssignmentConstraints(Loc, GetterType, PropertyIvarType) != Compatible) { Diag(Loc, diag::error_property_accessor_type) << property->getDeclName() << PropertyIvarType diff --git a/clang/test/CodeGenObjC/getter-property-type-mismatch.m b/clang/test/CodeGenObjC/getter-property-type-mismatch.m new file mode 100644 index 000000000000..c7e1c1a96a42 --- /dev/null +++ b/clang/test/CodeGenObjC/getter-property-type-mismatch.m @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s +// rdar://11515196 + +@interface NSArray @end + +@interface NSMutableArray : NSArray +- (void) addObject; +@end + +@interface BPXLAppDelegate + +- (NSArray *)arrayOfThings; + +@end + + +@interface BPXLAppDelegate () +@property (retain, nonatomic) NSMutableArray *arrayOfThings; +@end + +@implementation BPXLAppDelegate + +@synthesize arrayOfThings=_arrayOfThings; + +- (void)applicationDidFinishLaunching +{ + [self.arrayOfThings addObject]; +} + +@end + +// CHECK: define internal [[RET:%.*]]* @"\01-[BPXLAppDelegate arrayOfThings +// CHECK: [[THREE:%.*]] = bitcast [[OPQ:%.*]]* [[TWO:%.*]] to [[RET]]* +// CHECK: ret [[RET]]* [[THREE]] + diff --git a/clang/test/SemaObjC/property-typecheck-1.m b/clang/test/SemaObjC/property-typecheck-1.m index b28108ac85d1..58d0f215cd92 100644 --- a/clang/test/SemaObjC/property-typecheck-1.m +++ b/clang/test/SemaObjC/property-typecheck-1.m @@ -73,11 +73,11 @@ typedef void (F)(void); NSArray* first; } -@property (readonly) NSArray* pieces; -@property (readonly) NSMutableArray* first; // expected-warning {{type of property 'first' does not match type of accessor 'first'}} +@property (readonly) NSArray* pieces; // expected-warning {{type of property 'pieces' does not match type of accessor 'pieces'}} +@property (readonly) NSMutableArray* first; -- (NSMutableArray*) pieces; -- (NSArray*) first; // expected-note 2 {{declared here}} +- (NSMutableArray*) pieces; // expected-note 2 {{declared here}} +- (NSArray*) first; @end @interface Class2 { @@ -90,12 +90,12 @@ typedef void (F)(void); - (id) lastPiece { - return container.pieces; + return container.pieces; // expected-warning {{type of property 'pieces' does not match type of accessor 'pieces'}} } - (id)firstPeice { - return container.first; // expected-warning {{type of property 'first' does not match type of accessor 'first'}} + return container.first; } @end