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:
parent
5e558bcf26
commit
89654eef3a
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue