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
This commit is contained in:
Fariborz Jahanian 2012-06-29 18:27:08 +00:00
parent 025d518e3e
commit 4a031bdc8f
3 changed files with 159 additions and 41 deletions

View File

@ -368,6 +368,13 @@ namespace {
SourceLocation StartLoc=SourceLocation(),
SourceLocation EndLoc=SourceLocation());
Expr *SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor,
QualType msgSendType,
QualType returnType,
SmallVectorImpl<QualType> &ArgTypes,
SmallVectorImpl<Expr*> &MsgExprs,
ObjCMethodDecl *Method);
Stmt *SynthMessageExpr(ObjCMessageExpr *Exp,
SourceLocation StartLoc=SourceLocation(),
SourceLocation EndLoc=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<LinkageSpecDecl>(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<QualType> &ArgTypes,
SmallVectorImpl<Expr*> &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<FunctionType>();
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<LinkageSpecDecl>(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 <string.h>\n";
// Declarations required for modern objective-c array and dictionary literals.
Preamble += "\n#include <stdarg.h>\n";
Preamble += "struct __NSContainer_literal {\n";

View File

@ -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];
}
}

View File

@ -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 <string.h>
void *sel_registerName(const char *);
typedef unsigned int size_t;
@protocol P @end
@interface NSMutableArray