From 4a031bdc8f08d77be8f0fd631b4f7ac97e25a0d7 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Fri, 29 Jun 2012 18:27:08 +0000 Subject: [PATCH] objective-c modern translator: Translation into objc_msgSend_stret entry point which requires nil check before calling objc_msgSend_stret. // rdar://11359268 - wip. llvm-svn: 159445 --- clang/lib/Rewrite/RewriteModernObjC.cpp | 155 +++++++++++++----- clang/test/Rewriter/objc-modern-StretAPI.mm | 42 +++++ .../objc-modern-container-subscript.mm | 3 +- 3 files changed, 159 insertions(+), 41 deletions(-) create mode 100644 clang/test/Rewriter/objc-modern-StretAPI.mm diff --git a/clang/lib/Rewrite/RewriteModernObjC.cpp b/clang/lib/Rewrite/RewriteModernObjC.cpp index 61afaca9a419..b0f4c0d084ec 100644 --- a/clang/lib/Rewrite/RewriteModernObjC.cpp +++ b/clang/lib/Rewrite/RewriteModernObjC.cpp @@ -367,6 +367,13 @@ namespace { Expr **args, unsigned nargs, SourceLocation StartLoc=SourceLocation(), SourceLocation EndLoc=SourceLocation()); + + Expr *SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, + QualType msgSendType, + QualType returnType, + SmallVectorImpl &ArgTypes, + SmallVectorImpl &MsgExprs, + ObjCMethodDecl *Method); Stmt *SynthMessageExpr(ObjCMessageExpr *Exp, SourceLocation StartLoc=SourceLocation(), @@ -3055,6 +3062,107 @@ QualType RewriteModernObjC::getConstantStringStructType() { return Context->getTagDeclType(ConstantStringDecl); } +/// getFunctionSourceLocation - returns start location of a function +/// definition. Complication arises when function has declared as +/// extern "C" or extern "C" {...} +static SourceLocation getFunctionSourceLocation (RewriteModernObjC &R, + FunctionDecl *FD) { + if (FD->isExternC() && !FD->isMain()) { + const DeclContext *DC = FD->getDeclContext(); + if (const LinkageSpecDecl *LSD = dyn_cast(DC)) + // if it is extern "C" {...}, return function decl's own location. + if (!LSD->getRBraceLoc().isValid()) + return LSD->getExternLoc(); + } + if (FD->getStorageClassAsWritten() != SC_None) + R.RewriteBlockLiteralFunctionDecl(FD); + return FD->getTypeSpecStartLoc(); +} + +/// SynthMsgSendStretCallExpr - This routine translates message expression +/// into a call to objc_msgSend_stret() entry point. Tricky part is that +/// nil check on receiver must be performed before calling objc_msgSend_stret. +/// MsgSendStretFlavor - function declaration objc_msgSend_stret(...) +/// msgSendType - function type of objc_msgSend_stret(...) +/// returnType - Result type of the method being synthesized. +/// ArgTypes - type of the arguments passed to objc_msgSend_stret, starting with receiver type. +/// MsgExprs - list of argument expressions being passed to objc_msgSend_stret, +/// starting with receiver. +/// Method - Method being rewritten. +Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, + QualType msgSendType, + QualType returnType, + SmallVectorImpl &ArgTypes, + SmallVectorImpl &MsgExprs, + ObjCMethodDecl *Method) { + // Now do the "normal" pointer to function cast. + QualType castType = getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), + Method ? Method->isVariadic() : false); + castType = Context->getPointerType(castType); + + // build type for containing the objc_msgSend_stret object. + static unsigned stretCount=0; + std::string name = "__Stret"; name += utostr(stretCount); + std::string str = "struct "; str += name; + str += " {\n\t"; + str += name; + str += "(id receiver, SEL sel"; + for (unsigned i = 2; i < ArgTypes.size(); i++) { + str += ", "; str += ArgTypes[i].getAsString(Context->getPrintingPolicy()); + str += " arg"; str += utostr(i); + } + // could be vararg. + for (unsigned i = ArgTypes.size(); i < MsgExprs.size(); i++) { + str += ", "; str += MsgExprs[i]->getType().getAsString(Context->getPrintingPolicy()); + str += " arg"; str += utostr(i); + } + + str += ") {\n"; + str += "\t if (receiver == 0)\n"; + str += "\t memset((void*)&s, 0, sizeof(s));\n"; + str += "\t else\n"; + str += "\t s = (("; str += castType.getAsString(Context->getPrintingPolicy()); + str += ")(void *)objc_msgSend_stret)(receiver, sel"; + for (unsigned i = 2; i < ArgTypes.size(); i++) { + str += ", arg"; str += utostr(i); + } + // could be vararg. + for (unsigned i = ArgTypes.size(); i < MsgExprs.size(); i++) { + str += ", arg"; str += utostr(i); + } + + str += ");\n"; + str += "\t}\n"; + str += "\t"; str += returnType.getAsString(Context->getPrintingPolicy()); + str += " s;\n"; + str += "};\n\n"; + SourceLocation FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef); + InsertText(FunLocStart, str); + ++stretCount; + + // AST for __Stretn(receiver, args).s; + IdentifierInfo *ID = &Context->Idents.get(name); + FunctionDecl *FD = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), ID, castType, 0, SC_Extern, + SC_None, false, false); + DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, castType, VK_RValue, + SourceLocation()); + CallExpr *STCE = new (Context) CallExpr(*Context, DRE, &MsgExprs[0], MsgExprs.size(), + castType, VK_LValue, SourceLocation()); + + FieldDecl *FieldD = FieldDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), + &Context->Idents.get("s"), + returnType, 0, + /*BitWidth=*/0, /*Mutable=*/true, + ICIS_NoInit); + MemberExpr *ME = new (Context) MemberExpr(STCE, false, FieldD, SourceLocation(), + FieldD->getType(), VK_LValue, + OK_Ordinary); + + return ME; +} + Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, SourceLocation StartLoc, SourceLocation EndLoc) { @@ -3443,29 +3551,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // expression which dictate which one to envoke depending on size of // method's return type. - // Create a reference to the objc_msgSend_stret() declaration. - DeclRefExpr *STDRE = new (Context) DeclRefExpr(MsgSendStretFlavor, - false, msgSendType, - VK_LValue, SourceLocation()); - // Need to cast objc_msgSend_stret to "void *" (see above comment). - cast = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->VoidTy), - CK_BitCast, STDRE); - // Now do the "normal" pointer to function cast. - castType = getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), - Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false); - castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, - cast); - - // Don't forget the parens to enforce the proper binding. - PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast); - - FT = msgSendType->getAs(); - CallExpr *STCE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], - MsgExprs.size(), - FT->getResultType(), VK_RValue, - SourceLocation()); + Expr *STCE = SynthMsgSendStretCallExpr(MsgSendStretFlavor, + msgSendType, returnType, + ArgTypes, MsgExprs, + Exp->getMethodDecl()); // Build sizeof(returnType) UnaryExprOrTypeTraitExpr *sizeofExpr = @@ -4152,23 +4241,6 @@ std::string RewriteModernObjC::SynthesizeBlockDescriptor(std::string DescTag, return S; } -/// getFunctionSourceLocation - returns start location of a function -/// definition. Complication arises when function has declared as -/// extern "C" or extern "C" {...} -static SourceLocation getFunctionSourceLocation (RewriteModernObjC &R, - FunctionDecl *FD) { - if (FD->isExternC() && !FD->isMain()) { - const DeclContext *DC = FD->getDeclContext(); - if (const LinkageSpecDecl *LSD = dyn_cast(DC)) - // if it is extern "C" {...}, return function decl's own location. - if (!LSD->getRBraceLoc().isValid()) - return LSD->getExternLoc(); - } - if (FD->getStorageClassAsWritten() != SC_None) - R.RewriteBlockLiteralFunctionDecl(FD); - return FD->getTypeSpecStartLoc(); -} - void RewriteModernObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, StringRef FunName) { bool RewriteSC = (GlobalVarDecl && @@ -5885,6 +5957,9 @@ void RewriteModernObjC::Initialize(ASTContext &context) { Preamble += "#define __weak\n"; } + // needed for use of memset. + Preamble += "\n#include \n"; + // Declarations required for modern objective-c array and dictionary literals. Preamble += "\n#include \n"; Preamble += "struct __NSContainer_literal {\n"; diff --git a/clang/test/Rewriter/objc-modern-StretAPI.mm b/clang/test/Rewriter/objc-modern-StretAPI.mm new file mode 100644 index 000000000000..d469dd7862a3 --- /dev/null +++ b/clang/test/Rewriter/objc-modern-StretAPI.mm @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// rdar://11359268 + +extern "C" void *sel_registerName(const char *); + +union U { + double d1; + char filler[32]; +}; + +struct S { + char filler[128]; +}; + +@interface I +- (struct S) Meth : (int) arg1 : (id) arg2; +- (struct S) Meth1; +- (union U) Meth2 : (double)d; +- (struct S) VAMeth : (int)anchor, ...; +@end + +I* PI(); + +extern "C" { + +struct S foo () { + struct S s = [PI() Meth : 1 : (id)0]; + + U u = [PI() Meth2 : 3.14]; + + S s1 = [PI() VAMeth : 12, 13.4, 1000, "hello"]; + + S s2 = [PI() VAMeth : 12]; + + S s3 = [PI() VAMeth : 0, "hello", "there"]; + + return [PI() Meth1]; +} + +} + diff --git a/clang/test/Rewriter/objc-modern-container-subscript.mm b/clang/test/Rewriter/objc-modern-container-subscript.mm index d6bb9c2eb31d..dadd6ee5a052 100644 --- a/clang/test/Rewriter/objc-modern-container-subscript.mm +++ b/clang/test/Rewriter/objc-modern-container-subscript.mm @@ -2,9 +2,10 @@ // RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp // rdar://11203853 +#include + void *sel_registerName(const char *); -typedef unsigned int size_t; @protocol P @end @interface NSMutableArray