diff options
-rw-r--r-- | clang/include/clang/AST/DeclObjC.h | 21 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGObjC.cpp | 90 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGObjCMac.cpp | 4 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 20 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 14 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 40 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.h | 1 |
7 files changed, 165 insertions, 25 deletions
diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index d985ce39626..df958471241 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -1172,7 +1172,8 @@ public: OBJC_PR_nonatomic = 0x40, OBJC_PR_setter = 0x80 }; - + + enum SetterKind { Assign, Retain, Copy }; enum PropertyControl { None, Required, Optional }; private: QualType DeclType; @@ -1206,10 +1207,24 @@ public: PropertyAttributes |= PRVal; } + // Helper methods for accessing attributes. + + /// isReadOnly - Return true iff the property has a setter. bool isReadOnly() const { return (PropertyAttributes & OBJC_PR_readonly); } - + + /// getSetterKind - Return the method used for doing assignment in + /// the property setter. This is only valid if the property has been + /// defined to have a setter. + SetterKind getSetterKind() const { + if (PropertyAttributes & OBJC_PR_retain) + return Retain; + if (PropertyAttributes & OBJC_PR_copy) + return Copy; + return Assign; + } + Selector getGetterName() const { return GetterName; } void setGetterName(Selector Sel) { GetterName = Sel; } @@ -1278,7 +1293,7 @@ public: return PropertyIvarDecl ? Synthesize : Dynamic; } - ObjCIvarDecl *getPropertyIvarDecl() { + ObjCIvarDecl *getPropertyIvarDecl() const { return PropertyIvarDecl; } diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index ddd7c8119be..93567a4f8f5 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -88,9 +88,12 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { return Runtime.GenerateMessageSend(*this, E, Receiver, isClassMessage); } -/// Generate an Objective-C method. An Objective-C method is a C function with -/// its pointer, name, and types registered in the class struture. -void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) { +/// StartObjCMethod - Begin emission of an ObjCMethod. This generates +/// the LLVM function and sets the other context used by +/// CodeGenFunction. + +// FIXME: This should really be merged with GenerateCode. +void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD) { CurFn = CGM.getObjCRuntime().GenerateMethod(OMD); llvm::BasicBlock *EntryBB = llvm::BasicBlock::Create("entry", CurFn); @@ -127,8 +130,87 @@ void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) { EmitParmDecl(*OMD->getParamDecl(i), AI); } assert(AI == CurFn->arg_end() && "Argument mismatch"); +} + +/// Generate an Objective-C method. An Objective-C method is a C function with +/// its pointer, name, and types registered in the class struture. +void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) { + StartObjCMethod(OMD); + EmitStmt(OMD->getBody()); + + const CompoundStmt *S = dyn_cast<CompoundStmt>(OMD->getBody()); + if (S) { + FinishFunction(S->getRBracLoc()); + } else { + FinishFunction(); + } +} + +// FIXME: I wasn't sure about the synthesis approach. If we end up +// generating an AST for the whole body we can just fall back to +// having a GenerateFunction which takes the body Stmt. + +/// GenerateObjCGetter - Generate an Objective-C property getter +/// function. The given Decl must be either an ObjCCategoryImplDecl +/// or an ObjCImplementationDecl. +void CodeGenFunction::GenerateObjCGetter(const ObjCPropertyImplDecl *PID) { + const ObjCPropertyDecl *PD = PID->getPropertyDecl(); + ObjCMethodDecl *OMD = PD->getGetterMethodDecl(); + assert(OMD && "Invalid call to generate getter (empty method)"); + // FIXME: This is rather murky, we create this here since they will + // not have been created by Sema for us. + OMD->createImplicitParams(getContext()); + StartObjCMethod(OMD); + + // FIXME: What about nonatomic? + SourceLocation Loc = PD->getLocation(); + ValueDecl *Self = OMD->getSelfDecl(); + ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl(); + DeclRefExpr Base(Self, Self->getType(), Loc); + ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base, + true, true); + ReturnStmt Return(Loc, &IvarRef); + EmitStmt(&Return); + + FinishFunction(); +} + +/// GenerateObjCSetter - Generate an Objective-C property setter +/// function. The given Decl must be either an ObjCCategoryImplDecl +/// or an ObjCImplementationDecl. +void CodeGenFunction::GenerateObjCSetter(const ObjCPropertyImplDecl *PID) { + const ObjCPropertyDecl *PD = PID->getPropertyDecl(); + ObjCMethodDecl *OMD = PD->getSetterMethodDecl(); + assert(OMD && "Invalid call to generate setter (empty method)"); + // FIXME: This is rather murky, we create this here since they will + // not have been created by Sema for us. + OMD->createImplicitParams(getContext()); + StartObjCMethod(OMD); + + switch (PD->getSetterKind()) { + case ObjCPropertyDecl::Assign: break; + case ObjCPropertyDecl::Copy: + CGM.ErrorUnsupported(PID, "Obj-C setter with 'copy'"); + break; + case ObjCPropertyDecl::Retain: + CGM.ErrorUnsupported(PID, "Obj-C setter with 'retain'"); + break; + } - GenerateFunction(OMD->getBody()); + // FIXME: What about nonatomic? + SourceLocation Loc = PD->getLocation(); + ValueDecl *Self = OMD->getSelfDecl(); + ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl(); + DeclRefExpr Base(Self, Self->getType(), Loc); + ParmVarDecl *ArgDecl = OMD->getParamDecl(0); + DeclRefExpr Arg(ArgDecl, ArgDecl->getType(), Loc); + ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base, + true, true); + BinaryOperator Assign(&IvarRef, &Arg, BinaryOperator::Assign, + Ivar->getType(), Loc); + EmitStmt(&Assign); + + FinishFunction(); } llvm::Value *CodeGenFunction::LoadObjCSelf(void) { diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 42237097863..50d3abee0ba 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -233,9 +233,7 @@ private: const llvm::Type *InterfaceTy); /// EmitMethodList - Emit the method list for the given - /// implementation. If ForClass is true the list of class methods - /// will be emitted, otherwise the list of instance methods will be - /// generated. The return value has type MethodListPtrTy. + /// implementation. The return value has type MethodListPtrTy. llvm::Constant *EmitMethodList(const std::string &Name, const char *Section, llvm::SmallVector<ObjCMethodDecl*, 32>::const_iterator begin, diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 11fde873028..909486a6d1a 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -62,19 +62,15 @@ bool CodeGenFunction::hasAggregateLLVMType(QualType T) { !T->isVoidType() && !T->isVectorType() && !T->isFunctionType(); } -void CodeGenFunction::GenerateFunction(const Stmt *Body) { - // Emit the function body. - EmitStmt(Body); - +void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { // Finish emission of indirect switches. EmitIndirectSwitches(); // Emit debug descriptor for function end. CGDebugInfo *DI = CGM.getDebugInfo(); if (DI) { - const CompoundStmt* s = dyn_cast<CompoundStmt>(Body); - if (s && s->getRBracLoc().isValid()) { - DI->setLocation(s->getRBracLoc()); + if (EndLoc.isValid()) { + DI->setLocation(EndLoc); } DI->EmitRegionEnd(CurFn, Builder); } @@ -156,7 +152,15 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD, EmitParmDecl(*CurParam, V); } } - GenerateFunction(FD->getBody()); + + EmitStmt(FD->getBody()); + + const CompoundStmt *S = dyn_cast<CompoundStmt>(FD->getBody()); + if (S) { + FinishFunction(S->getRBracLoc()); + } else { + FinishFunction(); + } } /// isDummyBlock - Return true if BB is an empty basic block diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 2ba6b8ddcce..4eed9a7173f 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -39,6 +39,7 @@ namespace clang { class FunctionTypeProto; class LabelStmt; class ObjCMethodDecl; + class ObjCPropertyImplDecl; class TargetInfo; class VarDecl; @@ -112,9 +113,20 @@ public: ASTContext &getContext() const; void GenerateObjCMethod(const ObjCMethodDecl *OMD); + + void StartObjCMethod(const ObjCMethodDecl *MD); + + /// GenerateObjCGetter - Synthesize an Objective-C property getter + /// function. + void GenerateObjCGetter(const ObjCPropertyImplDecl *PID); + + /// GenerateObjCSetter - Synthesize an Objective-C property setter + /// function for the given property. + void GenerateObjCSetter(const ObjCPropertyImplDecl *PID); + void GenerateCode(const FunctionDecl *FD, llvm::Function *Fn); - void GenerateFunction(const Stmt *Body); + void FinishFunction(SourceLocation EndLoc=SourceLocation()); const llvm::Type *ConvertType(QualType T); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 51428c07ac8..57d5377bc37 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -836,6 +836,32 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &str) return GetAddrOfConstantString(str + "\0"); } +/// EmitObjCPropertyImplementations - Emit information for synthesized +/// properties for an implementation. +void CodeGenModule::EmitObjCPropertyImplementations(const + ObjCImplementationDecl *D) { + for (ObjCImplementationDecl::propimpl_iterator i = D->propimpl_begin(), + e = D->propimpl_end(); i != e; ++i) { + ObjCPropertyImplDecl *PID = *i; + + // Dynamic is just for type-checking. + if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { + ObjCPropertyDecl *PD = PID->getPropertyDecl(); + + // Determine which methods need to be implemented, some may have + // been overridden. Note that ::isSynthesized is not the method + // we want, that just indicates if the decl came from a + // property. What we want to know is if the method is defined in + // this implementation. + if (!D->getInstanceMethod(PD->getGetterName())) + CodeGenFunction(*this).GenerateObjCGetter(PID); + if (!PD->isReadOnly() && + !D->getInstanceMethod(PD->getSetterName())) + CodeGenFunction(*this).GenerateObjCSetter(PID); + } + } +} + /// EmitTopLevelDecl - Emit code for a single top level declaration. void CodeGenModule::EmitTopLevelDecl(Decl *D) { // If an error has occurred, stop code generation, but continue @@ -868,13 +894,18 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { break; case Decl::ObjCCategoryImpl: + // Categories have properties but don't support synthesize so we + // can ignore them here. + Runtime->GenerateCategory(cast<ObjCCategoryImplDecl>(D)); break; - case Decl::ObjCImplementation: - Runtime->GenerateClass(cast<ObjCImplementationDecl>(D)); + case Decl::ObjCImplementation: { + ObjCImplementationDecl *OMD = cast<ObjCImplementationDecl>(D); + EmitObjCPropertyImplementations(OMD); + Runtime->GenerateClass(OMD); break; - + } case Decl::ObjCMethod: { ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(D); // If this is not a prototype, emit the body. @@ -882,9 +913,6 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { CodeGenFunction(*this).GenerateObjCMethod(OMD); break; } - case Decl::ObjCPropertyImpl: - assert(0 && "FIXME: ObjCPropertyImpl unsupported"); - break; case Decl::ObjCCompatibleAlias: assert(0 && "FIXME: ObjCCompatibleAlias unsupported"); break; diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 7501fd461e6..b339ae9d674 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -217,6 +217,7 @@ private: llvm::GlobalValue *EmitForwardFunctionDefinition(const FunctionDecl *D); void EmitGlobalFunctionDefinition(const FunctionDecl *D); void EmitGlobalVarDefinition(const VarDecl *D); + void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); // FIXME: Hardcoding priority here is gross. void AddGlobalCtor(llvm::Function * Ctor, int Priority=65535); |