Move the definition-specific data of ObjCInterfaceDecl into a
separately-allocated DefinitionData structure, which we manage the
same way as CXXRecordDecl::DefinitionData. This prepares the way for
making ObjCInterfaceDecls redeclarable, to more accurately model
forward declarations of Objective-C classes and eliminate the mutation
of ObjCInterfaceDecl that causes us serious trouble in the AST reader.

Note that ObjCInterfaceDecl's accessors are fairly robust against
being applied to forward declarations, because Clang (and Sema in
particular) doesn't perform RequireCompleteType/hasDefinition() checks
everywhere it has to. Each of these overly-robust cases is marked with
a FIXME, which we can tackle over time.




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146644 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index bdedf8a..f7f93af 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -556,43 +556,80 @@
 void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
   VisitObjCContainerDecl(ID);
   ID->setTypeForDecl(Reader.readType(F, Record, Idx).getTypePtrOrNull());
-  ID->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
   
-  // Read the directly referenced protocols and their SourceLocations.
-  unsigned NumProtocols = Record[Idx++];
-  SmallVector<ObjCProtocolDecl *, 16> Protocols;
-  Protocols.reserve(NumProtocols);
-  for (unsigned I = 0; I != NumProtocols; ++I)
-    Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
-  SmallVector<SourceLocation, 16> ProtoLocs;
-  ProtoLocs.reserve(NumProtocols);
-  for (unsigned I = 0; I != NumProtocols; ++I)
-    ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
-  ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(),
-                      Reader.getContext());
+  ObjCInterfaceDecl *Def = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
+  if (ID == Def) {
+    // Read the definition.
+    ID->allocateDefinitionData();
+    
+    ObjCInterfaceDecl::DefinitionData &Data = ID->data();
+    
+    // Read the superclass.
+    Data.SuperClass = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
+    Data.SuperClassLoc = ReadSourceLocation(Record, Idx);
+
+    // Read the directly referenced protocols and their SourceLocations.
+    unsigned NumProtocols = Record[Idx++];
+    SmallVector<ObjCProtocolDecl *, 16> Protocols;
+    Protocols.reserve(NumProtocols);
+    for (unsigned I = 0; I != NumProtocols; ++I)
+      Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+    SmallVector<SourceLocation, 16> ProtoLocs;
+    ProtoLocs.reserve(NumProtocols);
+    for (unsigned I = 0; I != NumProtocols; ++I)
+      ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
+    ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(),
+                        Reader.getContext());
   
-  // Read the transitive closure of protocols referenced by this class.
-  NumProtocols = Record[Idx++];
-  Protocols.clear();
-  Protocols.reserve(NumProtocols);
-  for (unsigned I = 0; I != NumProtocols; ++I)
-    Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
-  ID->AllReferencedProtocols.set(Protocols.data(), NumProtocols,
-                                 Reader.getContext());
+    // Read the transitive closure of protocols referenced by this class.
+    NumProtocols = Record[Idx++];
+    Protocols.clear();
+    Protocols.reserve(NumProtocols);
+    for (unsigned I = 0; I != NumProtocols; ++I)
+      Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+    ID->data().AllReferencedProtocols.set(Protocols.data(), NumProtocols,
+                                          Reader.getContext());
   
-  // Read the ivars.
-  unsigned NumIvars = Record[Idx++];
-  SmallVector<ObjCIvarDecl *, 16> IVars;
-  IVars.reserve(NumIvars);
-  for (unsigned I = 0; I != NumIvars; ++I)
-    IVars.push_back(ReadDeclAs<ObjCIvarDecl>(Record, Idx));
-  ID->setCategoryList(ReadDeclAs<ObjCCategoryDecl>(Record, Idx));
+    // Read the ivars.
+    unsigned NumIvars = Record[Idx++];
+    SmallVector<ObjCIvarDecl *, 16> IVars;
+    IVars.reserve(NumIvars);
+    for (unsigned I = 0; I != NumIvars; ++I)
+      IVars.push_back(ReadDeclAs<ObjCIvarDecl>(Record, Idx));
+    
+    // Read the categories.
+    ID->setCategoryList(ReadDeclAs<ObjCCategoryDecl>(Record, Idx));
   
-  // We will rebuild this list lazily.
-  ID->setIvarList(0);
+    // We will rebuild this list lazily.
+    ID->setIvarList(0);
+    
+    // If there are any pending forward references, make their definition data
+    // pointers point at the newly-allocated data.
+    ASTReader::PendingForwardRefsMap::iterator
+    FindI = Reader.PendingForwardRefs.find(ID);
+    if (FindI != Reader.PendingForwardRefs.end()) {
+      ASTReader::ForwardRefs &Refs = FindI->second;
+      for (ASTReader::ForwardRefs::iterator I = Refs.begin(), 
+                                            E = Refs.end(); 
+           I != E; ++I)
+        cast<ObjCInterfaceDecl>(*I)->Definition = ID->Definition;
+#ifndef NDEBUG
+      // We later check whether PendingForwardRefs is empty to make sure all
+      // pending references were linked.
+      Reader.PendingForwardRefs.erase(ID);
+#endif
+    
+    } else if (Def) {
+      if (Def->Definition) {
+        ID->Definition = Def->Definition;
+      } else {
+        // The definition is still initializing.
+        Reader.PendingForwardRefs[Def].push_back(ID);
+      }
+    }
+  }
+  
   ID->InitiallyForwardDecl = Record[Idx++];
-  ID->ForwardDecl = Record[Idx++];
-  ID->setSuperClassLoc(ReadSourceLocation(Record, Idx));
   ID->setLocEnd(ReadSourceLocation(Record, Idx));
 }
 
@@ -972,7 +1009,7 @@
       ASTReader::ForwardRefs &Refs = FindI->second;
       for (ASTReader::ForwardRefs::iterator
              I = Refs.begin(), E = Refs.end(); I != E; ++I)
-        (*I)->DefinitionData = D->DefinitionData;
+        cast<CXXRecordDecl>(*I)->DefinitionData = D->DefinitionData;
 #ifndef NDEBUG
       // We later check whether PendingForwardRefs is empty to make sure all
       // pending references were linked.
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 1448e59..9396958 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -449,36 +449,46 @@
 void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
   VisitObjCContainerDecl(D);
   Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
-  Writer.AddDeclRef(D->getSuperClass(), Record);
 
-  // Write out the protocols that are directly referenced by the @interface.
-  Record.push_back(D->ReferencedProtocols.size());
-  for (ObjCInterfaceDecl::protocol_iterator P = D->protocol_begin(),
-         PEnd = D->protocol_end();
-       P != PEnd; ++P)
-    Writer.AddDeclRef(*P, Record);
-  for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
-         PLEnd = D->protocol_loc_end();
-       PL != PLEnd; ++PL)
-    Writer.AddSourceLocation(*PL, Record);
-
-  // Write out the protocols that are transitively referenced.
-  Record.push_back(D->AllReferencedProtocols.size());
-  for (ObjCList<ObjCProtocolDecl>::iterator
-        P = D->AllReferencedProtocols.begin(),
-        PEnd = D->AllReferencedProtocols.end();
-       P != PEnd; ++P)
-    Writer.AddDeclRef(*P, Record);
+  ObjCInterfaceDecl *Def = D->getDefinition();
+  Writer.AddDeclRef(Def, Record);
   
-  // Write out the ivars.
-  Record.push_back(D->ivar_size());
-  for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(),
-                                     IEnd = D->ivar_end(); I != IEnd; ++I)
-    Writer.AddDeclRef(*I, Record);
-  Writer.AddDeclRef(D->getCategoryList(), Record);
+  if (D == Def) {
+    // Write the DefinitionData
+    ObjCInterfaceDecl::DefinitionData &Data = D->data();
+    
+    Writer.AddDeclRef(D->getSuperClass(), Record);
+    Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
+    
+    // Write out the protocols that are directly referenced by the @interface.
+    Record.push_back(Data.ReferencedProtocols.size());
+    for (ObjCInterfaceDecl::protocol_iterator P = D->protocol_begin(),
+                                           PEnd = D->protocol_end();
+         P != PEnd; ++P)
+      Writer.AddDeclRef(*P, Record);
+    for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
+         PLEnd = D->protocol_loc_end();
+         PL != PLEnd; ++PL)
+      Writer.AddSourceLocation(*PL, Record);
+    
+    // Write out the protocols that are transitively referenced.
+    Record.push_back(Data.AllReferencedProtocols.size());
+    for (ObjCList<ObjCProtocolDecl>::iterator
+              P = Data.AllReferencedProtocols.begin(),
+           PEnd = Data.AllReferencedProtocols.end();
+         P != PEnd; ++P)
+      Writer.AddDeclRef(*P, Record);
+    
+    // Write out the ivars.
+    Record.push_back(D->ivar_size());
+    for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(),
+                                       IEnd = D->ivar_end(); I != IEnd; ++I)
+      Writer.AddDeclRef(*I, Record);
+    
+    Writer.AddDeclRef(D->getCategoryList(), Record);
+  }  
+  
   Record.push_back(D->isInitiallyForwardDecl());
-  Record.push_back(D->isForwardDecl());
-  Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
   Writer.AddSourceLocation(D->getLocEnd(), Record);
   Code = serialization::DECL_OBJC_INTERFACE;
 }