]> granicus.if.org Git - clang/commitdiff
Add Objective-C property setter support.
authorDaniel Dunbar <daniel@zuster.org>
Sat, 30 Aug 2008 05:35:15 +0000 (05:35 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Sat, 30 Aug 2008 05:35:15 +0000 (05:35 +0000)
 - 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

lib/AST/StmtDumper.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprComplex.cpp
lib/CodeGen/CGObjC.cpp
lib/CodeGen/CGObjCGNU.cpp
lib/CodeGen/CGObjCMac.cpp
lib/CodeGen/CGObjCRuntime.h
lib/CodeGen/CodeGenFunction.h
lib/Sema/SemaExpr.cpp

index 0ccf20175422dc3475548cf3ad83ba6416fd632e..af19b61cd643008e7830c035cdbc71e94bfc49b8 100644 (file)
@@ -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<ObjCMethodDecl>(Node->getDecl())) {
+    fprintf(F, " MethodDecl=\"%s\"", MD->getSelector().getName().c_str());
+  } else {
+    ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(Node->getDecl());
+    fprintf(F, " PropertyDecl=\"%s\"", PD->getName());
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Stmt method implementations
 //===----------------------------------------------------------------------===//
index c8aa26155e2967ded1e7557b7aa0e1d92a127cae..e1893493b0695368f99e4d9bf4028e284269b73c 100644 (file)
@@ -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;
index d335ea9c3fb384f2d79759d0874d8c2a845bf3ce..11eb9fc1157592586392c792c5457ba5b1b29e13 100644 (file)
@@ -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) {
index 3e1f695c79e92c3a7b33475391e23d11dc9f68d2..abd0ca8527e0a93565b07da3ece854f73a3c7d8c 100644 (file)
@@ -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) {
index 2a808f8e0598f55ad497d60ba4cb3a0a8fb772c5..79b50114b771407ae9505a3586b3c52e80829c3f 100644 (file)
@@ -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<ObjCMethodDecl>(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<ObjCPropertyDecl>(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<Expr*>(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<ObjCPropertyDecl>(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() {}
index e5a5d053314082ccf7853e1791d9352e945d5983..4565fbfeb0efb67e1c0c7a33d6171a803ab3e88e 100644 (file)
@@ -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<const llvm::Type*> 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<const llvm::Type*> 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 
index 3b4309d8941b6c75789253aeac1a415ee08bea77..ef4196e11fcdc655abff2114d61dd073ccdb80a5 100644 (file)
@@ -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, 
index 54591a331c6a6328e3d56fb26a7a9be1c1aabbe5..c0044e9a94d1a02b2517c11e879e281a2016594d 100644 (file)
@@ -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,
index e00c66552f638011450270f67f14be8b05069458..c8421e609a565437c5e6bb84c6090328b9a16364 100644 (file)
@@ -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<std::pair<llvm::Value*, QualType>, 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);
 
index 5169ce13111d462120969da67a14bf59c69f7f3c..ba13e7fe66c45aa6532b69f71dd4f6f6667e74ff 100644 (file)
@@ -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 {}