From 25491a22afc4312d651ad6bfd936304536f7595f Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Wed, 5 May 2010 21:52:17 +0000 Subject: [PATCH] This patch deals with Sema Part of Setter/Getter synthesis of properties which are of C++ objects. Code Gen to follow (Radar 7468090). llvm-svn: 103123 --- clang/include/clang/AST/DeclObjC.h | 24 +++++++++++- clang/include/clang/Parse/Action.h | 3 +- clang/lib/CodeGen/CGObjC.cpp | 6 --- clang/lib/Frontend/PCHReaderDecl.cpp | 1 + clang/lib/Frontend/PCHWriterDecl.cpp | 1 + clang/lib/Parse/ParseObjc.cpp | 10 ++--- clang/lib/Sema/Sema.h | 9 +++-- clang/lib/Sema/SemaDeclObjC.cpp | 14 +++---- clang/lib/Sema/SemaObjCProperty.cpp | 57 ++++++++++++++++++++++++++-- 9 files changed, 98 insertions(+), 27 deletions(-) diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index e34ec9ffcdf0..97d165696aad 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -1421,13 +1421,21 @@ private: /// Null for @dynamic. Required for @synthesize. ObjCIvarDecl *PropertyIvarDecl; + + /// Null for @dynamic. Non-null if property must be copy-constructed in getter + Expr *GetterCXXConstructor; + + /// Null for @dynamic. Non-null if property has assignment operator to call + /// in Setter synthesis. + Expr *SetterCXXAssignment; ObjCPropertyImplDecl(DeclContext *DC, SourceLocation atLoc, SourceLocation L, ObjCPropertyDecl *property, Kind PK, ObjCIvarDecl *ivarDecl) : Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc), - PropertyDecl(property), PropertyIvarDecl(ivarDecl) { + PropertyDecl(property), PropertyIvarDecl(ivarDecl), + GetterCXXConstructor(0), SetterCXXAssignment(0) { assert (PK == Dynamic || PropertyIvarDecl); } @@ -1457,7 +1465,21 @@ public: return PropertyIvarDecl; } void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { PropertyIvarDecl = Ivar; } + + Expr *getGetterCXXConstructor() const { + return GetterCXXConstructor; + } + void setGetterCXXConstructor(Expr *getterCXXConstructor) { + GetterCXXConstructor = getterCXXConstructor; + } + Expr *getSetterCXXAssignment() const { + return SetterCXXAssignment; + } + void setSetterCXXAssignment(Expr *setterCXXAssignment) { + SetterCXXAssignment = setterCXXAssignment; + } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCPropertyImplDecl *D) { return true; } static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; } diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 3d68d80ef9f0..98c9538d5ef9 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -2303,6 +2303,7 @@ public: } // ActOnPropertyImplDecl - called for every property implementation virtual DeclPtrTy ActOnPropertyImplDecl( + Scope *S, SourceLocation AtLoc, // location of the @synthesize/@dynamic SourceLocation PropertyNameLoc, // location for the property name bool ImplKind, // true for @synthesize, false for @@ -2346,7 +2347,7 @@ public: // protocols, categories), the parser passes all methods/properties. // For class implementations, these values default to 0. For implementations, // methods are processed incrementally (by ActOnMethodDeclaration above). - virtual void ActOnAtEnd(SourceRange AtEnd, + virtual void ActOnAtEnd(Scope *S, SourceRange AtEnd, DeclPtrTy classDecl, DeclPtrTy *allMethods = 0, unsigned allNum = 0, diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 8426f7105be4..cd369c6f114f 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -157,9 +157,6 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic); 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(), IMP->getClassInterface()); StartObjCMethod(OMD, IMP->getClassInterface()); // Determine if we should use an objc_getProperty call for @@ -274,9 +271,6 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, 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(), IMP->getClassInterface()); StartObjCMethod(OMD, IMP->getClassInterface()); bool IsCopy = PD->getSetterKind() == ObjCPropertyDecl::Copy; diff --git a/clang/lib/Frontend/PCHReaderDecl.cpp b/clang/lib/Frontend/PCHReaderDecl.cpp index 14dd2e927c41..6700dd3af45d 100644 --- a/clang/lib/Frontend/PCHReaderDecl.cpp +++ b/clang/lib/Frontend/PCHReaderDecl.cpp @@ -394,6 +394,7 @@ void PCHDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { cast_or_null(Reader.GetDecl(Record[Idx++]))); D->setPropertyIvarDecl( cast_or_null(Reader.GetDecl(Record[Idx++]))); + // FIXME. read GetterCXXConstructor and SetterCXXAssignment } void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) { diff --git a/clang/lib/Frontend/PCHWriterDecl.cpp b/clang/lib/Frontend/PCHWriterDecl.cpp index 7b7806239604..d3618df64ece 100644 --- a/clang/lib/Frontend/PCHWriterDecl.cpp +++ b/clang/lib/Frontend/PCHWriterDecl.cpp @@ -370,6 +370,7 @@ void PCHDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { Writer.AddSourceLocation(D->getLocStart(), Record); Writer.AddDeclRef(D->getPropertyDecl(), Record); Writer.AddDeclRef(D->getPropertyIvarDecl(), Record); + // FIXME. write GetterCXXConstructor and SetterCXXAssignment. Code = pch::DECL_OBJC_PROPERTY_IMPL; } diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 7b1ecf6437dc..9acb4fef80f2 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -446,7 +446,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, // Insert collected methods declarations into the @interface object. // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit. - Actions.ActOnAtEnd(AtEnd, interfaceDecl, + Actions.ActOnAtEnd(CurScope, AtEnd, interfaceDecl, allMethods.data(), allMethods.size(), allProperties.data(), allProperties.size(), allTUVariables.data(), allTUVariables.size()); @@ -1277,7 +1277,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { DeclPtrTy Result = ObjCImpDecl; ConsumeToken(); // the "end" identifier if (ObjCImpDecl) { - Actions.ActOnAtEnd(atEnd, ObjCImpDecl); + Actions.ActOnAtEnd(CurScope, atEnd, ObjCImpDecl); ObjCImpDecl = DeclPtrTy(); PendingObjCImpDecl.pop_back(); } @@ -1292,7 +1292,7 @@ Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() { if (PendingObjCImpDecl.empty()) return Actions.ConvertDeclToDeclGroup(DeclPtrTy()); DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val(); - Actions.ActOnAtEnd(SourceRange(), ImpDecl); + Actions.ActOnAtEnd(CurScope, SourceRange(), ImpDecl); return Actions.ConvertDeclToDeclGroup(ImpDecl); } @@ -1371,7 +1371,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { propertyIvar = Tok.getIdentifierInfo(); ConsumeToken(); // consume ivar-name } - Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, true, ObjCImpDecl, + Actions.ActOnPropertyImplDecl(CurScope, atLoc, propertyLoc, true, ObjCImpDecl, propertyId, propertyIvar); if (Tok.isNot(tok::comma)) break; @@ -1411,7 +1411,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { IdentifierInfo *propertyId = Tok.getIdentifierInfo(); SourceLocation propertyLoc = ConsumeToken(); // consume property name - Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, false, ObjCImpDecl, + Actions.ActOnPropertyImplDecl(CurScope, atLoc, propertyLoc, false, ObjCImpDecl, propertyId, 0); if (Tok.isNot(tok::comma)) diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index f146c8578721..45ea09e4f278 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1528,13 +1528,13 @@ public: /// ImplMethodsVsClassMethods - This is main routine to warn if any method /// remains unimplemented in the class or category @implementation. - void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, + void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool IncompleteImpl = false); /// DiagnoseUnimplementedProperties - This routine warns on those properties /// which must be implemented by this implementation. - void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, + void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const llvm::DenseSet& InsMap); @@ -3858,7 +3858,7 @@ public: void MatchOneProtocolPropertiesInClass(Decl *CDecl, ObjCProtocolDecl *PDecl); - virtual void ActOnAtEnd(SourceRange AtEnd, + virtual void ActOnAtEnd(Scope *S, SourceRange AtEnd, DeclPtrTy classDecl, DeclPtrTy *allMethods = 0, unsigned allNum = 0, DeclPtrTy *allProperties = 0, unsigned pNum = 0, @@ -3871,7 +3871,8 @@ public: bool *OverridingProperty, tok::ObjCKeywordKind MethodImplKind); - virtual DeclPtrTy ActOnPropertyImplDecl(SourceLocation AtLoc, + virtual DeclPtrTy ActOnPropertyImplDecl(Scope *S, + SourceLocation AtLoc, SourceLocation PropertyLoc, bool ImplKind,DeclPtrTy ClassImplDecl, IdentifierInfo *PropertyId, diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index d446cc13da26..b7d737984c74 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -925,7 +925,7 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet &InsMap, } } -void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, +void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool IncompleteImpl) { llvm::DenseSet InsMap; @@ -939,7 +939,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, // an implementation or 2) there is a @synthesize/@dynamic implementation // of the property in the @implementation. if (isa(CDecl)) - DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap); + DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); llvm::DenseSet ClsMap; for (ObjCImplementationDecl::classmeth_iterator @@ -968,7 +968,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, for (ObjCCategoryDecl *Categories = I->getCategoryList(); Categories; Categories = Categories->getNextClassCategory()) { if (Categories->IsClassExtension()) { - ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl); + ImplMethodsVsClassMethods(S, IMPDecl, Categories, IncompleteImpl); break; } } @@ -990,7 +990,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I) InsMap.insert((*I)->getSelector()); } - DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap); + DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); } } else assert(false && "invalid ObjCContainerDecl type."); @@ -1326,7 +1326,7 @@ void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, // Note: For class/category implemenations, allMethods/allProperties is // always null. -void Sema::ActOnAtEnd(SourceRange AtEnd, +void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, DeclPtrTy classDecl, DeclPtrTy *allMethods, unsigned allNum, DeclPtrTy *allProperties, unsigned pNum, @@ -1433,7 +1433,7 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, if (ObjCImplementationDecl *IC=dyn_cast(ClassDecl)) { IC->setAtEndRange(AtEnd); if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) { - ImplMethodsVsClassMethods(IC, IDecl); + ImplMethodsVsClassMethods(S, IC, IDecl); AtomicPropertySetterGetterRules(IC, IDecl); if (LangOpts.ObjCNonFragileABI2) while (IDecl->getSuperClass()) { @@ -1452,7 +1452,7 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, for (ObjCCategoryDecl *Categories = IDecl->getCategoryList(); Categories; Categories = Categories->getNextClassCategory()) { if (Categories->getIdentifier() == CatImplClass->getIdentifier()) { - ImplMethodsVsClassMethods(CatImplClass, Categories); + ImplMethodsVsClassMethods(S, CatImplClass, Categories); break; } } diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index b73739fc5551..f64ee970a959 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -13,6 +13,8 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" +#include "clang/AST/ExprObjC.h" using namespace clang; @@ -275,7 +277,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, /// builds the AST node for a property implementation declaration; declared /// as @synthesize or @dynamic. /// -Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, +Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, + SourceLocation AtLoc, SourceLocation PropertyLoc, bool Synthesize, DeclPtrTy ClassCatImpDecl, @@ -427,6 +430,54 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, ObjCPropertyImplDecl::Synthesize : ObjCPropertyImplDecl::Dynamic), Ivar); + if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) { + getterMethod->createImplicitParams(Context, IDecl); + if (getLangOptions().CPlusPlus && Synthesize) { + // For Objective-C++, need to synthesize the AST for the IVAR object to be + // returned by the getter as it must conform to C++'s copy-return rules. + // FIXME. Eventually we want to do this for Objective-C as well. + ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl(); + DeclRefExpr *SelfExpr = + new (Context) DeclRefExpr(SelfDecl,SelfDecl->getType(), + SourceLocation()); + Expr *IvarRefExpr = + new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc, + SelfExpr, true, true); + OwningExprResult Res = + PerformCopyInitialization(InitializedEntity::InitializeResult( + SourceLocation(), + getterMethod->getResultType()), + SourceLocation(), + Owned(IvarRefExpr)); + if (!Res.isInvalid()) { + Expr *ResExpr = Res.takeAs(); + if (ResExpr) + ResExpr = MaybeCreateCXXExprWithTemporaries(ResExpr); + PIDecl->setGetterCXXConstructor(ResExpr); + } + } + } + if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) { + setterMethod->createImplicitParams(Context, IDecl); + if (getLangOptions().CPlusPlus && Synthesize) { + // FIXME. Eventually we want to do this for Objective-C as well. + ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl(); + DeclRefExpr *SelfExpr = + new (Context) DeclRefExpr(SelfDecl,SelfDecl->getType(), + SourceLocation()); + Expr *lhs = + new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc, + SelfExpr, true, true); + ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); + ParmVarDecl *Param = (*P); + Expr *rhs = new (Context) DeclRefExpr(Param,Param->getType(), + SourceLocation()); + OwningExprResult Res = BuildBinOp(S, SourceLocation(), + BinaryOperator::Assign, lhs, rhs); + PIDecl->setSetterCXXAssignment(Res.takeAs()); + } + } + if (IC) { if (Synthesize) if (ObjCPropertyImplDecl *PPIDecl = @@ -818,7 +869,7 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, } -void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, +void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const llvm::DenseSet& InsMap) { llvm::DenseMap PropMap; @@ -841,7 +892,7 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, PropImplMap.count(Prop)) continue; if (LangOpts.ObjCNonFragileABI2 && !isa(IMPDecl)) { - ActOnPropertyImplDecl(IMPDecl->getLocation(), + ActOnPropertyImplDecl(S, IMPDecl->getLocation(), IMPDecl->getLocation(), true, DeclPtrTy::make(IMPDecl), Prop->getIdentifier(),