diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-12-15 18:03:09 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-12-15 18:03:09 +0000 |
commit | 53df7a1d34f21d8f2309311d1067d463e9064c60 (patch) | |
tree | c656cd7d7c1bd60325bd76cf1cae70defd8f970c | |
parent | 7ab8ef99e6b9064861b8d786a40560d74f96b421 (diff) |
Introduce the core infrastructure needed to model a complete
redeclaration chain for Objective-C classes, including:
- Using the first declaration as the canonical declaration.
- Using the definition as the primary DeclContext
- Making sure that all declarations have a pointer to the definition
data, and the definition knows that it is the definition.
- Serialization support for when a definition gets added to a
declaration that comes from an AST file.
However, note that we're not taking advantage of much of this code
yet, because we're still re-using ObjCInterfaceDecls.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146667 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclObjC.h | 43 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 9 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 10 | ||||
-rw-r--r-- | lib/Serialization/ASTCommon.h | 3 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 19 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 23 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterDecl.cpp | 1 |
7 files changed, 92 insertions, 16 deletions
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index db880eb2ea..c172a92cb7 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -540,7 +540,8 @@ public: /// Unlike C++, ObjC is a single-rooted class model. In Cocoa, classes /// typically inherit from NSObject (an exception is NSProxy). /// -class ObjCInterfaceDecl : public ObjCContainerDecl { +class ObjCInterfaceDecl : public ObjCContainerDecl + , public Redeclarable<ObjCInterfaceDecl> { /// TypeForDecl - This indicates the Type object that represents this /// TypeDecl. It is a cache maintained by ASTContext::getObjCInterfaceType mutable const Type *TypeForDecl; @@ -584,7 +585,10 @@ class ObjCInterfaceDecl : public ObjCContainerDecl { /// \brief Contains a pointer to the data associated with this class, /// which will be NULL if this class has not yet been defined. - DefinitionData *Definition; + /// + /// The boolean value indicates whether this particular declaration is + /// also the definition. + llvm::PointerIntPair<DefinitionData *, 1, bool> Definition; /// \brief The location of the last location in this declaration, e.g., /// the '>', '}', or identifier. @@ -598,13 +602,18 @@ class ObjCInterfaceDecl : public ObjCContainerDecl { bool InitiallyForwardDecl : 1; DefinitionData &data() const { - assert(Definition != 0 && "Declaration is not a definition!"); - return *Definition; + assert(Definition.getPointer() != 0 && "Declaration is not a definition!"); + return *Definition.getPointer(); } /// \brief Allocate the definition data for this class. void allocateDefinitionData(); + typedef Redeclarable<ObjCInterfaceDecl> redeclarable_base; + virtual ObjCInterfaceDecl *getNextRedeclaration() { + return RedeclLink.getNext(); + } + public: static ObjCInterfaceDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation atLoc, @@ -771,11 +780,15 @@ public: /// \brief Determine whether this declaration is a forward declaration of /// the class. - bool isForwardDecl() const { return Definition == 0; } + bool isForwardDecl() const { return !Definition.getInt(); } + /// \brief Determine whether this particular declaration of this class is + /// actually also a definition. + bool isThisDeclarationADefinition() const { return Definition.getInt(); } + /// \brief Determine whether this class has been defined. - bool hasDefinition() const { return Definition != 0; } - + bool hasDefinition() const { return Definition.getPointer() != 0; } + /// \brief Retrieve the definition of this class, or NULL if this class /// has been forward-declared (with @class) but not yet defined (with /// @interface). @@ -896,6 +909,22 @@ public: bool lookupCategory, bool RHSIsQualifiedID = false); + typedef redeclarable_base::redecl_iterator redecl_iterator; + redecl_iterator redecls_begin() const { + return redeclarable_base::redecls_begin(); + } + redecl_iterator redecls_end() const { + return redeclarable_base::redecls_end(); + } + + /// Retrieves the canonical declaration of this Objective-C class. + ObjCInterfaceDecl *getCanonicalDecl() { + return getFirstDeclaration(); + } + const ObjCInterfaceDecl *getCanonicalDecl() const { + return getFirstDeclaration(); + } + // Low-level accessor const Type *getTypeForDecl() const { return TypeForDecl; } void setTypeForDecl(const Type *TD) const { TypeForDecl = TD; } diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index b7941506b0..024f370c56 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -779,9 +779,16 @@ DeclContext *DeclContext::getPrimaryContext() { return this; case Decl::ObjCInterface: + if (ObjCInterfaceDecl *Def = cast<ObjCInterfaceDecl>(this)->getDefinition()) + return Def; + + return this; + case Decl::ObjCProtocol: + // FIXME: Update when protocols properly model forward declarations. + // For now, it's fine to fall through + case Decl::ObjCCategory: - // FIXME: Can Objective-C interfaces be forward-declared? return this; case Decl::ObjCImplementation: diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index decbd54c6d..1da0fab0ba 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -224,7 +224,15 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList( void ObjCInterfaceDecl::allocateDefinitionData() { assert(!hasDefinition() && "ObjC class already has a definition"); - Definition = new (getASTContext()) DefinitionData(); + Definition.setPointer(new (getASTContext()) DefinitionData()); + Definition.setInt(true); + + // Update all of the declarations with a pointer to the definition. + for (redecl_iterator RD = redecls_begin(), RDEnd = redecls_end(); + RD != RDEnd; ++RD) { + if (*RD != this) + RD->Definition.setPointer(Definition.getPointer()); + } } void ObjCInterfaceDecl::startDefinition() { diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h index 367f57f715..2e3d70b853 100644 --- a/lib/Serialization/ASTCommon.h +++ b/lib/Serialization/ASTCommon.h @@ -26,7 +26,8 @@ enum DeclUpdateKind { UPD_CXX_ADDED_IMPLICIT_MEMBER, UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, - UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER + UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER, + UPD_OBJC_SET_CLASS_DEFINITIONDATA }; TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT); diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index f7f93af9ce..6fc5764006 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -554,6 +554,7 @@ void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) { } void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { + VisitRedeclarable(ID); VisitObjCContainerDecl(ID); ID->setTypeForDecl(Reader.readType(F, Record, Idx).getTypePtrOrNull()); @@ -618,10 +619,9 @@ void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { // pending references were linked. Reader.PendingForwardRefs.erase(ID); #endif - } else if (Def) { - if (Def->Definition) { - ID->Definition = Def->Definition; + if (Def->Definition.getPointer()) { + ID->Definition.setPointer(Def->Definition.getPointer()); } else { // The definition is still initializing. Reader.PendingForwardRefs[Def].push_back(ID); @@ -2067,6 +2067,19 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile, cast<VarDecl>(D)->getMemberSpecializationInfo()->setPointOfInstantiation( Reader.ReadSourceLocation(ModuleFile, Record, Idx)); break; + + case UPD_OBJC_SET_CLASS_DEFINITIONDATA: { + ObjCInterfaceDecl *ID = cast<ObjCInterfaceDecl>(D); + ObjCInterfaceDecl *Def + = Reader.ReadDeclAs<ObjCInterfaceDecl>(ModuleFile, Record, Idx); + if (Def->Definition.getPointer()) { + ID->Definition.setPointer(Def->Definition.getPointer()); + } else { + // The definition is still initializing. + Reader.PendingForwardRefs[Def].push_back(ID); + } + break; + } } } } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 6cce0afc50..b3f76f7494 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -3439,6 +3439,7 @@ void ASTWriter::ResolveDeclUpdatesBlocks() { case UPD_CXX_ADDED_IMPLICIT_MEMBER: case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: + case UPD_OBJC_SET_CLASS_DEFINITIONDATA: URec[Idx] = GetDeclRef(reinterpret_cast<Decl *>(URec[Idx])); ++Idx; break; @@ -4379,10 +4380,26 @@ void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, void ASTWriter::CompletedObjCForwardRef(const ObjCContainerDecl *D) { assert(!WritingAST && "Already writing the AST!"); - if (!D->isFromASTFile()) - return; // Declaration not imported from PCH. + if (D->isFromASTFile()) + RewriteDecl(D); - RewriteDecl(D); + if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) { + for (ObjCInterfaceDecl::redecl_iterator I = ID->redecls_begin(), + E = ID->redecls_end(); + I != E; ++I) { + if (*I == ID) + continue; + + // We are interested when a PCH decl is modified. + if (I->isFromASTFile()) { + UpdateRecord &Record = DeclUpdates[*I]; + Record.push_back(UPD_OBJC_SET_CLASS_DEFINITIONDATA); + assert((*I)->hasDefinition()); + assert((*I)->getDefinition() == D); + Record.push_back(reinterpret_cast<uint64_t>(D)); // the DefinitionDecl + } + } + } } void ASTWriter::AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop, diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 9396958659..e641c101a1 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -447,6 +447,7 @@ void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) { } void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + VisitRedeclarable(D); VisitObjCContainerDecl(D); Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); |