From: Daniel Dunbar Date: Sat, 30 Aug 2008 05:35:15 +0000 (+0000) Subject: Add Objective-C property setter support. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7f8ea5c5b3a6a4332a841eefdd86b0726722ea7b;p=clang Add Objective-C property setter support. - Change Obj-C runtime message API, drop the ObjCMessageExpr arg in favor of just result type and selector. Necessary so it can be reused in situations where we don't want to cons up an ObjCMessageExpr. - Update aggregate binary assignment to know about special property ref lvalues. - Add CodeGenFunction::EmitCallArg overload which takes an already emitted rvalue. Add CodeGenFunction::StoreComplexIntoAddr. Disabled logic in Sema for parsing Objective-C dot-syntax that accesses methods. This code does not search in the correct order and the AST node has no way of properly representing its results. Updated StmtDumper to print a bit more information about ObjCPropertyRefExprs. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55561 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index 0ccf201754..af19b61cd6 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -136,6 +136,7 @@ namespace { void VisitObjCMessageExpr(ObjCMessageExpr* Node); void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); + void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); }; } @@ -449,6 +450,18 @@ void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { fprintf(F, " "); fprintf(F, "%s", Node->getProtocol()->getName()); } + +void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { + DumpExpr(Node); + + if (ObjCMethodDecl *MD = dyn_cast(Node->getDecl())) { + fprintf(F, " MethodDecl=\"%s\"", MD->getSelector().getName().c_str()); + } else { + ObjCPropertyDecl *PD = dyn_cast(Node->getDecl()); + fprintf(F, " PropertyDecl=\"%s\"", PD->getName()); + } +} + //===----------------------------------------------------------------------===// // Stmt method implementations //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index c8aa26155e..e1893493b0 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -830,6 +830,24 @@ RValue CodeGenFunction::EmitCallExpr(llvm::Value *Callee, QualType FnType, return EmitCall(Callee, ResultType, Args); } +// FIXME: Merge the following two functions. +void CodeGenFunction::EmitCallArg(RValue RV, QualType Ty, + CallArgList &Args) { + llvm::Value *ArgValue; + + if (RV.isScalar()) { + ArgValue = RV.getScalarVal(); + } else if (RV.isComplex()) { + // Make a temporary alloca to pass the argument. + ArgValue = CreateTempAlloca(ConvertType(Ty)); + StoreComplexToAddr(RV.getComplexVal(), ArgValue, false); + } else { + ArgValue = RV.getAggregateAddr(); + } + + Args.push_back(std::make_pair(ArgValue, Ty)); +} + void CodeGenFunction::EmitCallArg(const Expr *E, CallArgList &Args) { QualType ArgTy = E->getType(); llvm::Value *ArgValue; diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index d335ea9c3f..11eb9fc115 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -264,14 +264,26 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { && "Invalid assignment"); LValue LHS = CGF.EmitLValue(E->getLHS()); - // Codegen the RHS so that it stores directly into the LHS. - CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), false /*FIXME: VOLATILE LHS*/); - - if (DestPtr == 0) - return; - - // If the result of the assignment is used, copy the RHS there also. - EmitAggregateCopy(DestPtr, LHS.getAddress(), E->getType()); + // We have to special case property setters, otherwise we must have + // a simple lvalue (no aggregates inside vectors, bitfields). + if (LHS.isPropertyRef()) { + // FIXME: Volatility? + llvm::Value *AggLoc = DestPtr; + if (!AggLoc) + AggLoc = CGF.CreateTempAlloca(CGF.ConvertType(E->getRHS()->getType())); + CGF.EmitAggExpr(E->getRHS(), AggLoc, false); + CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(), + RValue::getAggregate(AggLoc)); + } else { + // Codegen the RHS so that it stores directly into the LHS. + CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), false /*FIXME: VOLATILE LHS*/); + + if (DestPtr == 0) + return; + + // If the result of the assignment is used, copy the RHS there also. + EmitAggregateCopy(DestPtr, LHS.getAddress(), E->getType()); + } } void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) { diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 3e1f695c79..abd0ca8527 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -546,6 +546,13 @@ void CodeGenFunction::EmitComplexExprIntoAddr(const Expr *E, Emitter.EmitStoreOfComplex(Val, DestAddr, DestIsVolatile); } +/// StoreComplexToAddr - Store a complex number into the specified address. +void CodeGenFunction::StoreComplexToAddr(ComplexPairTy V, + llvm::Value *DestAddr, + bool DestIsVolatile) { + ComplexExprEmitter(*this).EmitStoreOfComplex(V, DestAddr, DestIsVolatile); +} + /// LoadComplexFromAddr - Load a complex number from the specified address. ComplexPairTy CodeGenFunction::LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile) { diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 2a808f8e05..79b50114b7 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -86,13 +86,15 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { if (isSuperMessage) { // super is only valid in an Objective-C method const ObjCMethodDecl *OMD = cast(CurFuncDecl); - return Runtime.GenerateMessageSendSuper(*this, E, + return Runtime.GenerateMessageSendSuper(*this, E->getType(), + E->getSelector(), OMD->getClassInterface(), Receiver, isClassMessage, Args); } - return Runtime.GenerateMessageSend(*this, E, Receiver, isClassMessage, Args); + return Runtime.GenerateMessageSend(*this, E->getType(), E->getSelector(), + Receiver, isClassMessage, Args); } /// StartObjCMethod - Begin emission of an ObjCMethod. This generates @@ -234,20 +236,28 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const ObjCPropertyRefExpr *E) { S = cast(E->getDecl())->getGetterName(); } - // FIXME: Improve location information. - SourceLocation Loc = E->getLocation(); - // PropertyRefExprs are always instance messages. - // FIXME: Is there any reason to try and pass the method here? - ObjCMessageExpr GetExpr(const_cast(E->getBase()), - S, E->getType(), 0, Loc, Loc, - 0, 0); - - return EmitObjCMessageExpr(&GetExpr); + return CGM.getObjCRuntime(). + GenerateMessageSend(*this, E->getType(), S, + EmitScalarExpr(E->getBase()), + false, CallArgList()); } void CodeGenFunction::EmitObjCPropertySet(const ObjCPropertyRefExpr *E, RValue Src) { - ErrorUnsupported(E, "Objective-C property setter call"); + Selector S; + if (const ObjCPropertyDecl *PD = dyn_cast(E->getDecl())) { + S = PD->getSetterName(); + } else { + // FIXME: How can we have a method decl here? + ErrorUnsupported(E, "Objective-C property setter call"); + return; + } + + CallArgList Args; + EmitCallArg(Src, E->getType(), Args); + CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S, + EmitScalarExpr(E->getBase()), + false, Args); } CGObjCRuntime::~CGObjCRuntime() {} diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index e5a5d05331..4565fbfeb0 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -96,13 +96,15 @@ public: virtual llvm::Constant *GenerateConstantString(const std::string &String); virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, - const ObjCMessageExpr *E, + QualType ResultType, + Selector Sel, llvm::Value *Receiver, bool IsClassMessage, const CallArgList &CallArgs); virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, - const ObjCMessageExpr *E, + QualType ResultType, + Selector Sel, const ObjCInterfaceDecl *Class, llvm::Value *Receiver, bool IsClassMessage, @@ -239,16 +241,17 @@ llvm::Constant *CGObjCGNU::GenerateConstantString(const std::string &Str) { ///should be called. CodeGen::RValue CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, - const ObjCMessageExpr *E, + QualType ResultType, + Selector Sel, const ObjCInterfaceDecl *Class, llvm::Value *Receiver, bool IsClassMessage, const CallArgList &CallArgs) { const ObjCInterfaceDecl *SuperClass = Class->getSuperClass(); - const llvm::Type *ReturnTy = CGM.getTypes().ConvertType(E->getType()); + const llvm::Type *ReturnTy = CGM.getTypes().ConvertType(ResultType); // TODO: This should be cached, not looked up every time. llvm::Value *ReceiverClass = GetClass(CGF.Builder, SuperClass); - llvm::Value *cmd = GetSelector(CGF.Builder, E->getSelector()); + llvm::Value *cmd = GetSelector(CGF.Builder, Sel); std::vector impArgTypes; impArgTypes.push_back(Receiver->getType()); impArgTypes.push_back(SelectorTy); @@ -282,18 +285,19 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, ActualArgs.push_back(std::make_pair(cmd, CGF.getContext().getObjCSelType())); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); - return CGF.EmitCall(imp, E->getType(), ActualArgs); + return CGF.EmitCall(imp, ResultType, ActualArgs); } /// Generate code for a message send expression. CodeGen::RValue CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, - const ObjCMessageExpr *E, + QualType ResultType, + Selector Sel, llvm::Value *Receiver, bool IsClassMessage, const CallArgList &CallArgs) { - const llvm::Type *ReturnTy = CGM.getTypes().ConvertType(E->getType()); - llvm::Value *cmd = GetSelector(CGF.Builder, E->getSelector()); + const llvm::Type *ReturnTy = CGM.getTypes().ConvertType(ResultType); + llvm::Value *cmd = GetSelector(CGF.Builder, Sel); // Look up the method implementation. std::vector impArgTypes; @@ -328,7 +332,7 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, ActualArgs.push_back(std::make_pair(cmd, CGF.getContext().getObjCSelType())); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); - return CGF.EmitCall(imp, E->getType(), ActualArgs); + return CGF.EmitCall(imp, ResultType, ActualArgs); } /// Generates a MethodList. Used in construction of a objc_class and diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 3b4309d894..ef4196e11f 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -219,7 +219,8 @@ private: const ObjCInterfaceDecl *ID); CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF, - const ObjCMessageExpr *E, + QualType ResultType, + Selector Sel, llvm::Value *Arg0, QualType Arg0Ty, bool IsSuper, @@ -337,14 +338,16 @@ public: virtual llvm::Constant *GenerateConstantString(const std::string &String); virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, - const ObjCMessageExpr *E, + QualType ResultType, + Selector Sel, llvm::Value *Receiver, bool IsClassMessage, const CallArgList &CallArgs); virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, - const ObjCMessageExpr *E, + QualType ResultType, + Selector Sel, const ObjCInterfaceDecl *Class, llvm::Value *Receiver, bool IsClassMessage, @@ -428,7 +431,8 @@ llvm::Constant *CGObjCMac::GenerateConstantString(const std::string &String) { /// which class's method should be called. CodeGen::RValue CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, - const ObjCMessageExpr *E, + QualType ResultType, + Selector Sel, const ObjCInterfaceDecl *Class, llvm::Value *Receiver, bool IsClassMessage, @@ -460,34 +464,35 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1)); - return EmitMessageSend(CGF, E, + return EmitMessageSend(CGF, ResultType, Sel, ObjCSuper, ObjCTypes.SuperPtrCTy, true, CallArgs); } /// Generate code for a message send expression. CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, - const ObjCMessageExpr *E, + QualType ResultType, + Selector Sel, llvm::Value *Receiver, bool IsClassMessage, const CallArgList &CallArgs) { llvm::Value *Arg0 = CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy, "tmp"); - return EmitMessageSend(CGF, E, + return EmitMessageSend(CGF, ResultType, Sel, Arg0, CGF.getContext().getObjCIdType(), false, CallArgs); } CodeGen::RValue CGObjCMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, - const ObjCMessageExpr *E, + QualType ResultType, + Selector Sel, llvm::Value *Arg0, QualType Arg0Ty, bool IsSuper, const CallArgList &CallArgs) { CallArgList ActualArgs; ActualArgs.push_back(std::make_pair(Arg0, Arg0Ty)); - ActualArgs.push_back(std::make_pair(EmitSelector(CGF.Builder, - E->getSelector()), + ActualArgs.push_back(std::make_pair(EmitSelector(CGF.Builder, Sel), CGF.getContext().getObjCSelType())); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); @@ -496,10 +501,9 @@ CodeGen::RValue CGObjCMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, // parameter and set the structure return flag. See // getMessageSendFn(). - const llvm::Type *ReturnTy = CGM.getTypes().ConvertType(E->getType()); + const llvm::Type *ReturnTy = CGM.getTypes().ConvertType(ResultType); return CGF.EmitCall(ObjCTypes.getMessageSendFn(IsSuper, ReturnTy), - E->getType(), - ActualArgs); + ResultType, ActualArgs); } llvm::Value *CGObjCMac::GenerateProtocolRef(llvm::IRBuilder<> &Builder, diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index 54591a331c..c0044e9a94 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -81,7 +81,8 @@ public: /// Generate an Objective-C message send operation. virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, - const ObjCMessageExpr *E, + QualType ResultType, + Selector Sel, llvm::Value *Receiver, bool IsClassMessage, const CallArgList &CallArgs) = 0; @@ -91,7 +92,8 @@ public: /// object. virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, - const ObjCMessageExpr *E, + QualType ResultType, + Selector Sel, const ObjCInterfaceDecl *Class, llvm::Value *Self, bool IsClassMessage, diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index e00c66552f..c8421e609a 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -299,8 +299,22 @@ public: // Scalar Expression Emission //===--------------------------------------------------------------------===// + /// CallArgList - Type for representing both the value and type of + /// arguments in a call. typedef llvm::SmallVector, 16> CallArgList; + + /// EmitCallArg - Emit the given expression and append the result + /// onto the given Args list. void EmitCallArg(const Expr *E, CallArgList &Args); + + /// EmitCallArg - Append the appropriate call argument for the given + /// rvalue and type onto the Args list. + void EmitCallArg(RValue RV, QualType Ty, CallArgList &Args); + + /// EmitCall - Generate a call of the given function, expecting the + /// given result type, and using the given argument list which + /// specifies both the LLVM arguments and the types they were + /// derived from. RValue EmitCall(llvm::Value *Callee, QualType ResultType, const CallArgList &Args); @@ -366,6 +380,10 @@ public: /// of complex type, storing into the specified Value*. void EmitComplexExprIntoAddr(const Expr *E, llvm::Value *DestAddr, bool DestIsVolatile); + + /// StoreComplexToAddr - Store a complex number into the specified address. + void StoreComplexToAddr(ComplexPairTy V, llvm::Value *DestAddr, + bool DestIsVolatile); /// LoadComplexFromAddr - Load a complex number from the specified address. ComplexPairTy LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 5169ce1311..ba13e7fe66 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -869,7 +869,11 @@ ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc, // FIXME: The logic for looking up nullary and unary selectors should be // shared with the code in ActOnInstanceMessage. - + + // FIXME: This logic is not correct, we should search for + // properties first. Additionally, the AST node doesn't currently + // have enough information to store the setter argument. +#if 0 // Before we look for explicit property declarations, we check for // nullary methods (which allow '.' notation). Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); @@ -886,6 +890,7 @@ ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc, return new ObjCPropertyRefExpr(MD, MD->getResultType(), MemberLoc, BaseExpr); } +#endif // FIXME: Need to deal with setter methods that take 1 argument. E.g.: // @interface NSBundle : NSObject {}