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
/// 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;
/// \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.
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,
/// \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).
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; }
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:
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() {
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);
}
void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
+ VisitRedeclarable(ID);
VisitObjCContainerDecl(ID);
ID->setTypeForDecl(Reader.readType(F, Record, Idx).getTypePtrOrNull());
// 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);
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;
+ }
}
}
}
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;
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,
}
void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ VisitRedeclarable(D);
VisitObjCContainerDecl(D);
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);