Objective-C @synthesize support.

- Only supports simple assignment and atomic semantics are ignored.
 - Not quite usable yet because the methods do not actually get added
   to the class metadata.
 - Added ObjCPropertyDecl::getSetterKind (one of Assign, Copy, Retain).
 - Rearrange CodeGenFunction so synthesis can reuse function prolog /
   epilog code.

llvm-svn: 55365
This commit is contained in:
Daniel Dunbar 2008-08-26 08:29:31 +00:00
parent 5e558bcf26
commit 89654eef3a
7 changed files with 165 additions and 25 deletions

View File

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

View File

@ -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");
}
GenerateFunction(OMD->getBody());
/// 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;
}
// 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) {

View File

@ -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,

View File

@ -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

View File

@ -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);

View File

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

View File

@ -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);