[cfe-commits] r110989 - in /cfe/trunk: include/clang/AST/DeclBase.h include/clang/Frontend/PCHBitCodes.h include/clang/Frontend/PCHReader.h include/clang/Frontend/PCHWriter.h lib/Frontend/PCHReader.cpp lib/Frontend/PCHReaderDecl.cpp lib/Frontend/PCHWriter.cpp lib/Frontend/PCHWriterDecl.cpp lib/Sema/SemaDeclObjC.cpp test/PCH/chain-predecl.h test/PCH/chain-predecl.m

Sebastian Redl sebastian.redl at getdesigned.at
Thu Aug 12 17:28:03 PDT 2010


Author: cornedbee
Date: Thu Aug 12 19:28:03 2010
New Revision: 110989

URL: http://llvm.org/viewvc/llvm-project?rev=110989&view=rev
Log:
Instead of modifying the ObjC AST to not modify existing declarations, teach chained PCH to overwrite declarations from earlier PCH files in dependent ones. Tell Sema to note when it changes AST nodes so that they have to be reserialized. Finally, the ObjCProtocolDecls created in forward decls, like the ObjCInterfaceDecls in @class forward decls, are not lexically part of the decl context; only the definition is.

Added:
    cfe/trunk/test/PCH/chain-predecl.h
    cfe/trunk/test/PCH/chain-predecl.m
Modified:
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/include/clang/Frontend/PCHBitCodes.h
    cfe/trunk/include/clang/Frontend/PCHReader.h
    cfe/trunk/include/clang/Frontend/PCHWriter.h
    cfe/trunk/lib/Frontend/PCHReader.cpp
    cfe/trunk/lib/Frontend/PCHReaderDecl.cpp
    cfe/trunk/lib/Frontend/PCHWriter.cpp
    cfe/trunk/lib/Frontend/PCHWriterDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=110989&r1=110988&r2=110989&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Thu Aug 12 19:28:03 2010
@@ -222,11 +222,14 @@
   // NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
   unsigned Access : 2;
   friend class CXXClassMemberWrapper;
-  
-  // PCHLevel - the "level" of precompiled header/AST file from which this
-  // declaration was built.
-  unsigned PCHLevel : 3;
-  
+
+  /// PCHLevel - the "level" of precompiled header/AST file from which this
+  /// declaration was built.
+  unsigned PCHLevel : 2;
+
+  /// PCHChanged - if this declaration has changed since being deserialized
+  bool PCHChanged : 1;
+
   /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
   unsigned IdentifierNamespace : 15;
 
@@ -243,7 +246,7 @@
     : NextDeclInContext(0), DeclCtx(DC),
       Loc(L), DeclKind(DK), InvalidDecl(0),
       HasAttrs(false), Implicit(false), Used(false),
-      Access(AS_none), PCHLevel(0),
+      Access(AS_none), PCHLevel(0), PCHChanged(false),
       IdentifierNamespace(getIdentifierNamespaceForKind(DK)) {
     if (Decl::CollectingStats()) add(DK);
   }
@@ -251,7 +254,7 @@
   Decl(Kind DK, EmptyShell Empty)
     : NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),
       HasAttrs(false), Implicit(false), Used(false),
-      Access(AS_none), PCHLevel(0),
+      Access(AS_none), PCHLevel(0), PCHChanged(false),
       IdentifierNamespace(getIdentifierNamespaceForKind(DK)) {
     if (Decl::CollectingStats()) add(DK);
   }
@@ -358,7 +361,7 @@
   unsigned getPCHLevel() const { return PCHLevel; }
 
   /// \brief The maximum PCH level that any declaration may have.
-  static const unsigned MaxPCHLevel = 7;
+  static const unsigned MaxPCHLevel = 3;
 
   /// \brief Set the PCH level of this declaration.
   void setPCHLevel(unsigned Level) { 
@@ -366,6 +369,17 @@
     PCHLevel = Level;
   }
 
+  /// \brief Query whether this declaration was changed in a significant way
+  /// since being loaded from a PCH file.
+  ///
+  /// In an epic violation of layering, what is "significant" is entirely
+  /// up to the PCH system, but implemented in AST and Sema.
+  bool isChangedSinceDeserialization() const { return PCHChanged; }
+
+  /// \brief Mark this declaration as having changed since deserialization, or
+  /// reset the flag.
+  void setChangedSinceDeserialization(bool Changed) { PCHChanged = Changed; }
+
   unsigned getIdentifierNamespace() const {
     return IdentifierNamespace;
   }

Modified: cfe/trunk/include/clang/Frontend/PCHBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHBitCodes.h?rev=110989&r1=110988&r2=110989&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHBitCodes.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHBitCodes.h Thu Aug 12 19:28:03 2010
@@ -256,7 +256,14 @@
       WEAK_UNDECLARED_IDENTIFIERS = 31,
 
       /// \brief Record code for pending implicit instantiations.
-      PENDING_IMPLICIT_INSTANTIATIONS = 32
+      PENDING_IMPLICIT_INSTANTIATIONS = 32,
+
+      /// \brief Record code for a decl replacement block.
+      ///
+      /// If a declaration is modified after having been deserialized, and then
+      /// written to a dependent PCH file, its ID and offset must be added to
+      /// the replacement block.
+      DECL_REPLACEMENTS = 33
     };
 
     /// \brief Record types used within a source manager block.

Modified: cfe/trunk/include/clang/Frontend/PCHReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHReader.h?rev=110989&r1=110988&r2=110989&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHReader.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHReader.h Thu Aug 12 19:28:03 2010
@@ -321,6 +321,11 @@
   /// = I + 1 has already been loaded.
   std::vector<Decl *> DeclsLoaded;
 
+  typedef llvm::DenseMap<pch::DeclID, std::pair<PerFileData *, uint64_t> >
+      DeclReplacementMap;
+  /// \brief Declarations that have been replaced in a later file in the chain.
+  DeclReplacementMap ReplacedDecls;
+
   /// \brief Information about the contents of a DeclContext.
   struct DeclContextInfo {
     llvm::BitstreamCursor *Stream;
@@ -577,7 +582,7 @@
   RecordLocation TypeCursorForIndex(unsigned Index);
   void LoadedDecl(unsigned Index, Decl *D);
   Decl *ReadDeclRecord(unsigned Index, pch::DeclID ID);
-  RecordLocation DeclCursorForIndex(unsigned Index);
+  RecordLocation DeclCursorForIndex(unsigned Index, pch::DeclID ID);
 
   void PassInterestingDeclsToConsumer();
 

Modified: cfe/trunk/include/clang/Frontend/PCHWriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHWriter.h?rev=110989&r1=110988&r2=110989&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHWriter.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHWriter.h Thu Aug 12 19:28:03 2010
@@ -227,10 +227,18 @@
   /// to this set, so that we can write out lexical content updates for it.
   llvm::SmallPtrSet<const NamespaceDecl *, 16> UpdatedNamespaces;
 
+  /// \brief Decls that have been replaced in the current dependent PCH.
+  ///
+  /// When a decl changes fundamentally after being deserialized (this shouldn't
+  /// happen, but the ObjC AST nodes are designed this way), it will be
+  /// serialized again. In this case, it is registered here, so that the reader
+  /// knows to read the updated version.
+  llvm::SmallVector<std::pair<pch::DeclID, uint64_t>, 16> ReplacedDecls;
+
   /// \brief Statements that we've encountered while serializing a
   /// declaration or type.
   llvm::SmallVector<Stmt *, 16> StmtsToEmit;
-  
+
   /// \brief Statements collection to use for PCHWriter::AddStmt().
   /// It will point to StmtsToEmit unless it is overriden. 
   llvm::SmallVector<Stmt *, 16> *CollectedStmts;
@@ -274,6 +282,7 @@
   void WriteReferencedSelectorsPool(Sema &SemaRef);
   void WriteIdentifierTable(Preprocessor &PP);
   void WriteAttributeRecord(const Attr *Attr);
+  void WriteDeclUpdateBlock();
 
   unsigned ParmVarDeclAbbrev;
   unsigned DeclContextLexicalAbbrev;

Modified: cfe/trunk/lib/Frontend/PCHReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReader.cpp?rev=110989&r1=110988&r2=110989&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHReader.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReader.cpp Thu Aug 12 19:28:03 2010
@@ -1774,6 +1774,17 @@
       F.NumPreallocatedPreprocessingEntities = Record[0];
       F.LocalNumMacroDefinitions = Record[1];
       break;
+
+    case pch::DECL_REPLACEMENTS: {
+      if (Record.size() % 2 != 0) {
+        Error("invalid DECL_REPLACEMENTS block in PCH file");
+        return Failure;
+      }
+      for (unsigned I = 0, N = Record.size(); I != N; I += 2)
+        ReplacedDecls[static_cast<pch::DeclID>(Record[I])] =
+            std::make_pair(&F, Record[I+1]);
+      break;
+    }
     }
     First = false;
   }

Modified: cfe/trunk/lib/Frontend/PCHReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReaderDecl.cpp?rev=110989&r1=110988&r2=110989&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHReaderDecl.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReaderDecl.cpp Thu Aug 12 19:28:03 2010
@@ -1307,7 +1307,13 @@
 }
 
 /// \brief Get the correct cursor and offset for loading a type.
-PCHReader::RecordLocation PCHReader::DeclCursorForIndex(unsigned Index) {
+PCHReader::RecordLocation
+PCHReader::DeclCursorForIndex(unsigned Index, pch::DeclID ID) {
+  // See if there's an override.
+  DeclReplacementMap::iterator It = ReplacedDecls.find(ID);
+  if (It != ReplacedDecls.end())
+    return RecordLocation(&It->second.first->DeclsCursor, It->second.second);
+
   PerFileData *F = 0;
   for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
     F = Chain[N - I - 1];
@@ -1321,7 +1327,7 @@
 
 /// \brief Read the declaration at the given offset from the PCH file.
 Decl *PCHReader::ReadDeclRecord(unsigned Index, pch::DeclID ID) {
-  RecordLocation Loc = DeclCursorForIndex(Index);
+  RecordLocation Loc = DeclCursorForIndex(Index, ID);
   llvm::BitstreamCursor &DeclsCursor = *Loc.first;
   // Keep track of where we are in the stream, then jump back there
   // after reading this declaration.

Modified: cfe/trunk/lib/Frontend/PCHWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriter.cpp?rev=110989&r1=110988&r2=110989&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriter.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriter.cpp Thu Aug 12 19:28:03 2010
@@ -2414,6 +2414,8 @@
        I != E; ++I) {
     if ((*I)->getPCHLevel() == 0)
       NewGlobalDecls.push_back(GetDeclRef(*I));
+    else if ((*I)->isChangedSinceDeserialization())
+      (void)GetDeclRef(*I); // Make sure it's written, but don't record it.
   }
   // We also need to write a lexical updates block for the TU.
   llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev();
@@ -2596,10 +2598,24 @@
   Record.push_back(NumMacros);
   Record.push_back(NumLexicalDeclContexts);
   Record.push_back(NumVisibleDeclContexts);
+  WriteDeclUpdateBlock();
   Stream.EmitRecord(pch::STATISTICS, Record);
   Stream.ExitBlock();
 }
 
+void PCHWriter::WriteDeclUpdateBlock() {
+  if (ReplacedDecls.empty())
+    return;
+
+  RecordData Record;
+  for (llvm::SmallVector<std::pair<pch::DeclID, uint64_t>, 16>::iterator
+           I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) {
+    Record.push_back(I->first);
+    Record.push_back(I->second);
+  }
+  Stream.EmitRecord(pch::DECL_REPLACEMENTS, Record);
+}
+
 void PCHWriter::AddSourceLocation(SourceLocation Loc, RecordData &Record) {
   Record.push_back(Loc.getRawEncoding());
 }
@@ -2817,6 +2833,12 @@
     // enqueue it in the list of declarations to emit.
     ID = NextDeclID++;
     DeclTypesToEmit.push(const_cast<Decl *>(D));
+  } else if (ID < FirstDeclID && D->isChangedSinceDeserialization()) {
+    // We don't add it to the replacement collection here, because we don't
+    // have the offset yet.
+    DeclTypesToEmit.push(const_cast<Decl *>(D));
+    // Reset the flag, so that we don't add this decl multiple times.
+    const_cast<Decl *>(D)->setChangedSinceDeserialization(false);
   }
 
   return ID;

Modified: cfe/trunk/lib/Frontend/PCHWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriterDecl.cpp?rev=110989&r1=110988&r2=110989&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriterDecl.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriterDecl.cpp Thu Aug 12 19:28:03 2010
@@ -1126,18 +1126,24 @@
   }
 
   // Determine the ID for this declaration
-  pch::DeclID &ID = DeclIDs[D];
-  if (ID == 0)
-    ID = NextDeclID++;
-
-  unsigned Index = ID - FirstDeclID;
-
-  // Record the offset for this declaration
-  if (DeclOffsets.size() == Index)
-    DeclOffsets.push_back(Stream.GetCurrentBitNo());
-  else if (DeclOffsets.size() < Index) {
-    DeclOffsets.resize(Index+1);
-    DeclOffsets[Index] = Stream.GetCurrentBitNo();
+  pch::DeclID &IDR = DeclIDs[D];
+  if (IDR == 0)
+    IDR = NextDeclID++;
+  pch::DeclID ID = IDR;
+
+  if (ID < FirstDeclID) {
+    // We're replacing a decl in a previous file.
+    ReplacedDecls.push_back(std::make_pair(ID, Stream.GetCurrentBitNo()));
+  } else {
+    unsigned Index = ID - FirstDeclID;
+
+    // Record the offset for this declaration
+    if (DeclOffsets.size() == Index)
+      DeclOffsets.push_back(Stream.GetCurrentBitNo());
+    else if (DeclOffsets.size() < Index) {
+      DeclOffsets.resize(Index+1);
+      DeclOffsets[Index] = Stream.GetCurrentBitNo();
+    }
   }
 
   // Build and emit a record for this declaration
@@ -1164,5 +1170,5 @@
   //
   // FIXME: This should be renamed, the predicate is much more complicated.
   if (isRequiredDecl(D, Context))
-    ExternalDefinitions.push_back(Index + 1);
+    ExternalDefinitions.push_back(ID);
 }

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=110989&r1=110988&r2=110989&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Thu Aug 12 19:28:03 2010
@@ -89,6 +89,9 @@
       IDecl->setLocation(AtInterfaceLoc);
       IDecl->setForwardDecl(false);
       IDecl->setClassLoc(ClassLoc);
+      // If the forward decl was in a PCH, we need to write it again in a
+      // chained PCH.
+      IDecl->setChangedSinceDeserialization(true);
       
       // Since this ObjCInterfaceDecl was created by a forward declaration,
       // we now add it to the DeclContext since it wasn't added before
@@ -176,7 +179,7 @@
     IDecl->setLocEnd(ClassLoc);
   }
 
-  /// Check then save referenced protocols.
+  // Check then save referenced protocols.
   if (NumProtoRefs) {
     IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
                            ProtoLocs, Context);
@@ -284,6 +287,9 @@
     // Make sure the cached decl gets a valid start location.
     PDecl->setLocation(AtProtoInterfaceLoc);
     PDecl->setForwardDecl(false);
+    CurContext->addDecl(PDecl);
+    // Repeat in dependent PCHs.
+    PDecl->setChangedSinceDeserialization(true);
   } else {
     PDecl = ObjCProtocolDecl::Create(Context, CurContext,
                                      AtProtoInterfaceLoc,ProtocolName);
@@ -384,13 +390,18 @@
   for (unsigned i = 0; i != NumElts; ++i) {
     IdentifierInfo *Ident = IdentList[i].first;
     ObjCProtocolDecl *PDecl = LookupProtocol(Ident, IdentList[i].second);
+    bool isNew = false;
     if (PDecl == 0) { // Not already seen?
       PDecl = ObjCProtocolDecl::Create(Context, CurContext,
                                        IdentList[i].second, Ident);
-      PushOnScopeChains(PDecl, TUScope);
+      PushOnScopeChains(PDecl, TUScope, false);
+      isNew = true;
     }
-    if (attrList)
+    if (attrList) {
       ProcessDeclAttributeList(TUScope, PDecl, attrList);
+      if (!isNew)
+        PDecl->setChangedSinceDeserialization(true);
+    }
     Protocols.push_back(PDecl);
     ProtoLocs.push_back(IdentList[i].second);
   }

Added: cfe/trunk/test/PCH/chain-predecl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/chain-predecl.h?rev=110989&view=auto
==============================================================================
--- cfe/trunk/test/PCH/chain-predecl.h (added)
+++ cfe/trunk/test/PCH/chain-predecl.h Thu Aug 12 19:28:03 2010
@@ -0,0 +1,3 @@
+// First header for chain-predecl.m
+ at class Foo;
+ at protocol Pro;

Added: cfe/trunk/test/PCH/chain-predecl.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/chain-predecl.m?rev=110989&view=auto
==============================================================================
--- cfe/trunk/test/PCH/chain-predecl.m (added)
+++ cfe/trunk/test/PCH/chain-predecl.m Thu Aug 12 19:28:03 2010
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -emit-pch -o %t1 %S/chain-predecl.h -x objective-c
+// RUN: %clang_cc1 -emit-pch -o %t2 %s -x objective-c -include-pch %t1 -chained-pch
+
+// Test predeclarations across chained PCH.
+ at interface Foo
+-(void)bar;
+ at end
+ at interface Boom
+-(void)bar;
+ at end
+ at protocol Pro
+-(void)baz;
+ at end
+ at protocol Kaboom
+-(void)baz;
+ at end





More information about the cfe-commits mailing list