From 422dd7b9f75e21132e832cbe4c65ca25bd90610f Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Fri, 8 Aug 2014 17:31:14 +0000 Subject: [PATCH] Objective-C ARC. Use of non-retain/autorelease API for building Objective-C array literals in ARC mode. rdar://17554063 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@215232 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 3 ++ lib/Sema/Sema.cpp | 1 + lib/Sema/SemaExprObjC.cpp | 41 ++++++++++++++++++--- test/CodeGenObjC/Inputs/literal-support.h | 1 + test/CodeGenObjC/arc-literals.m | 22 ++++++----- test/CodeGenObjCXX/Inputs/literal-support.h | 1 + test/CodeGenObjCXX/literals.mm | 13 +++++-- test/SemaObjC/arc.m | 7 ++-- test/SemaObjC/objc-literal-comparison.m | 1 + 9 files changed, 69 insertions(+), 21 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ed31a9f86e..f82974e274 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -685,6 +685,9 @@ public: /// \brief The declaration of the initWithObjects:forKeys:count: method. ObjCMethodDecl *InitDictionaryWithObjectsMethod; + /// \brief The declaration for + (id) alloc method used in [NSArray alloc] + ObjCMethodDecl *ArrayAllocObjectsMethod; + /// \brief The declaration for + (id) alloc method used in [NSDictionary alloc] ObjCMethodDecl *DictAllocObjectsMethod; diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 4ed5aa8a28..205081b656 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -98,6 +98,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, InitArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr), InitDictionaryWithObjectsMethod(nullptr), + ArrayAllocObjectsMethod(nullptr), DictAllocObjectsMethod(nullptr), GlobalNewDeleteDeclared(false), TUKind(TUKind), diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index e4625bc98c..786637c205 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -630,6 +630,7 @@ ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, } ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { + bool Arc = getLangOpts().ObjCAutoRefCount; // Look up the NSArray class, if we haven't done so already. if (!NSArrayDecl) { NamedDecl *IF = LookupSingleName(TUScope, @@ -649,18 +650,45 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { return ExprError(); } } - - // Find the arrayWithObjects:count: method, if we haven't done so already. QualType IdT = Context.getObjCIdType(); + if (Arc && !ArrayAllocObjectsMethod) { + // Find +[NSArray alloc] method. + IdentifierInfo *II = &Context.Idents.get("alloc"); + Selector AllocSel = Context.Selectors.getSelector(0, &II); + ArrayAllocObjectsMethod = NSArrayDecl->lookupClassMethod(AllocSel); + if (!ArrayAllocObjectsMethod && getLangOpts().DebuggerObjCLiteral) { + ArrayAllocObjectsMethod = ObjCMethodDecl::Create(Context, + SourceLocation(), SourceLocation(), AllocSel, + IdT, + nullptr /*TypeSourceInfo */, + Context.getTranslationUnitDecl(), + false /*Instance*/, false/*isVariadic*/, + /*isPropertyAccessor=*/false, + /*isImplicitlyDeclared=*/true, /*isDefined=*/false, + ObjCMethodDecl::Required, + false); + SmallVector Params; + ArrayAllocObjectsMethod->setMethodParams(Context, Params, None); + } + if (!ArrayAllocObjectsMethod) { + Diag(SR.getBegin(), diag::err_undeclared_alloc); + return ExprError(); + } + } + // Find the arrayWithObjects:count: method, if we haven't done so already. if (!ArrayWithObjectsMethod) { Selector - Sel = NSAPIObj->getNSArraySelector(NSAPI::NSArr_arrayWithObjectsCount); - ObjCMethodDecl *Method = NSArrayDecl->lookupClassMethod(Sel); + Sel = NSAPIObj->getNSArraySelector( + Arc? NSAPI::NSArr_initWithObjectsCount : NSAPI::NSArr_arrayWithObjectsCount); + ObjCMethodDecl *Method = + Arc? NSArrayDecl->lookupInstanceMethod(Sel) + : NSArrayDecl->lookupClassMethod(Sel); if (!Method && getLangOpts().DebuggerObjCLiteral) { TypeSourceInfo *ReturnTInfo = nullptr; Method = ObjCMethodDecl::Create( Context, SourceLocation(), SourceLocation(), Sel, IdT, ReturnTInfo, - Context.getTranslationUnitDecl(), false /*Instance*/, + Context.getTranslationUnitDecl(), + Arc /*Instance for Arc, Class for MRR*/, false /*isVariadic*/, /*isPropertyAccessor=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, @@ -740,7 +768,8 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { return MaybeBindToTemporary( ObjCArrayLiteral::Create(Context, Elements, Ty, - ArrayWithObjectsMethod, nullptr, SR)); + ArrayWithObjectsMethod, + ArrayAllocObjectsMethod, SR)); } ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, diff --git a/test/CodeGenObjC/Inputs/literal-support.h b/test/CodeGenObjC/Inputs/literal-support.h index 475c86af24..caa69c24ca 100644 --- a/test/CodeGenObjC/Inputs/literal-support.h +++ b/test/CodeGenObjC/Inputs/literal-support.h @@ -30,6 +30,7 @@ typedef unsigned char BOOL; @interface NSArray (NSArrayCreation) + (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt; +- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt; @end @interface NSDictionary : NSObject diff --git a/test/CodeGenObjC/arc-literals.m b/test/CodeGenObjC/arc-literals.m index 427c65aa05..29f2b45a80 100644 --- a/test/CodeGenObjC/arc-literals.m +++ b/test/CodeGenObjC/arc-literals.m @@ -8,7 +8,7 @@ // CHECK: c"numberWithUnsignedInt:\00" // CHECK: c"numberWithUnsignedLongLong:\00" // CHECK: c"numberWithChar:\00" -// CHECK: c"arrayWithObjects:count:\00" +// CHECK: c"initWithObjects:count:\00" // CHECK: c"initWithObjects:forKeys:count:\00" // CHECK: c"prop\00" @@ -53,10 +53,12 @@ void test_array(id a, id b) { // CHECK-NEXT: [[T0:%.*]] = load [[CLASS_T:%.*]]** @"\01L_OBJC_CLASSLIST // CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES // CHECK-NEXT: [[T1:%.*]] = bitcast [[CLASS_T]]* [[T0]] to i8* - // CHECK-NEXT: [[T2:%.*]] = bitcast [2 x i8*]* [[OBJECTS]] to i8** - // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast ({{.*@objc_msgSend.*}})(i8* [[T1]], i8* [[SEL]], i8** [[T2]], i64 2) - // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T3]]) - // CHECK: call void (...)* @clang.arc.use(i8* [[V0]], i8* [[V1]]) + + // CHECK-NEXT: [[ALLOC:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[T1]], i8* [[SEL]]) + // CHECK-NEXT: [[T9:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES + // CHECK-NEXT: [[T10:%.*]] = bitcast [2 x i8*]* [[OBJECTS]] to i8** + // CHECK-NEXT: [[ARRAYINIT:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i8**, i64)*)(i8* [[ALLOC]], i8* [[T9]], i8** [[T10]], i64 2) + // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[V0]], i8* [[V1]]) id arr = @[a, b]; // CHECK: call void @objc_release @@ -140,13 +142,15 @@ void test_property(B *b) { // Store to array. // CHECK-NEXT: store i8* [[V1]], i8** [[T0]] - // Invoke arrayWithObjects:count: + // Invoke initWithObjects:count: // CHECK-NEXT: [[T0:%.*]] = load [[CLASS_T]]** @"\01L_OBJC_CLASSLIST // CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES // CHECK-NEXT: [[T1:%.*]] = bitcast [[CLASS_T]]* [[T0]] to i8* - // CHECK-NEXT: [[T2:%.*]] = bitcast [1 x i8*]* [[OBJECTS]] to i8** - // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast ({{.*}} @objc_msgSend to {{.*}}(i8* [[T1]], i8* [[SEL]], i8** [[T2]], i64 1) - // CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue(i8* [[T3]]) + + // CHECK-NEXT: [[ALLOC:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[T1]], i8* [[SEL]]) + // CHECK-NEXT: [[T9:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES + // CHECK-NEXT: [[T10:%.*]] = bitcast [1 x i8*]* [[OBJECTS]] to i8** + // CHECK-NEXT: [[INIT:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i8**, i64)*)(i8* [[ALLOC]], i8* [[T9]], i8** [[T10]], i64 1) // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[V1]]) // CHECK-NEXT: bitcast // CHECK-NEXT: bitcast diff --git a/test/CodeGenObjCXX/Inputs/literal-support.h b/test/CodeGenObjCXX/Inputs/literal-support.h index fc80d88b13..174ec3a83c 100644 --- a/test/CodeGenObjCXX/Inputs/literal-support.h +++ b/test/CodeGenObjCXX/Inputs/literal-support.h @@ -30,6 +30,7 @@ typedef unsigned char BOOL; @interface NSArray (NSArrayCreation) + (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt; +- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt; @end @interface NSDictionary : NSObject diff --git a/test/CodeGenObjCXX/literals.mm b/test/CodeGenObjCXX/literals.mm index f21bba75f3..42ec4bee38 100644 --- a/test/CodeGenObjCXX/literals.mm +++ b/test/CodeGenObjCXX/literals.mm @@ -33,8 +33,15 @@ void test_array() { // CHECK: store i8* [[RET1]], i8** [[ELEMENT1]] // Build the array - // CHECK: {{invoke.*@objc_msgSend}} - // CHECK: call i8* @objc_retainAutoreleasedReturnValue + // CHECK: [[T4:%.*]] = load [[CLASS:%.*]]** @"\01L_OBJC_CLASSLIST_REFERENCES_$_" + // CHECK-NEXT: [[T5:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_ + // CHECK-NEXT: [[T6:%.*]] = bitcast [[CLASS]]* [[T4]] to i8* + // CHECK-NEXT: [[ALLOC:%.*]] = {{invoke.*@objc_msgSend}} + + // CHECK: [[T7:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_ + // CHECK-NEXT: [[T8:%.*]] = bitcast [2 x i8*]* [[OBJECTS]] to i8** + // CHECK-NEXT: [[INIT:%.*]] = {{invoke.*@objc_msgSend}} + id arr = @[ X(), Y() ]; // Destroy temporaries @@ -81,7 +88,7 @@ void test_array_instantiation() { // Build the array // CHECK: {{invoke.*@objc_msgSend}} - // CHECK: call i8* @objc_retainAutoreleasedReturnValue + id arr = @[ X(), Y() ]; // Destroy temporaries diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m index e60fd970f3..285c7371cc 100644 --- a/test/SemaObjC/arc.m +++ b/test/SemaObjC/arc.m @@ -21,8 +21,9 @@ id CFBridgingRelease(CFTypeRef); @interface NSNumber + (NSNumber *)numberWithInt:(int)value; @end -@interface NSArray +@interface NSArray : NSObject + (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; +- (id)initWithObjects:(const id [])objects count:(NSUInteger)cnt; @end void test0(void (*fn)(int), int val) { @@ -748,7 +749,7 @@ void rdar12569201(id key, id value) { // Declarations. __weak id x = @"foo"; // no-warning __weak id y = @{ key : value }; // expected-warning {{assigning retained object to weak variable; object will be released after assignment}} - __weak id z = @[ value ]; // expected-warning {{assigning array literal to a weak variable; object will be released after assignment}} + __weak id z = @[ value ]; // expected-warning {{assigning retained object to weak variable; object will be released after assignment}} __weak id b = ^() {}; // expected-warning {{assigning block literal to a weak variable; object will be released after assignment}} __weak id n = @42; // expected-warning {{assigning numeric literal to a weak variable; object will be released after assignment}} __weak id e = @(42); // expected-warning {{assigning numeric literal to a weak variable; object will be released after assignment}} @@ -756,7 +757,7 @@ void rdar12569201(id key, id value) { // Assignments. y = @{ key : value }; // expected-warning {{assigning retained object to weak variable; object will be released after assignment}} - z = @[ value ]; // expected-warning {{assigning array literal to a weak variable; object will be released after assignment}} + z = @[ value ]; // expected-warning {{assigning retained object to weak variable; object will be released after assignment}} b = ^() {}; // expected-warning {{assigning block literal to a weak variable; object will be released after assignment}} n = @42; // expected-warning {{assigning numeric literal to a weak variable; object will be released after assignment}} e = @(42); // expected-warning {{assigning numeric literal to a weak variable; object will be released after assignment}} diff --git a/test/SemaObjC/objc-literal-comparison.m b/test/SemaObjC/objc-literal-comparison.m index febce3a267..409d7134ef 100644 --- a/test/SemaObjC/objc-literal-comparison.m +++ b/test/SemaObjC/objc-literal-comparison.m @@ -29,6 +29,7 @@ typedef signed char BOOL; @interface NSArray : NSObject + (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt; +- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt; @end @interface NSDictionary : NSObject -- 2.40.0