[cfe-commits] r108340 - in /cfe/trunk: include/clang/Frontend/PCHReader.h lib/Frontend/PCHReader.cpp test/PCH/pchpch.c test/PCH/pchpch1.h test/PCH/pchpch2.h

Sebastian Redl sebastian.redl at getdesigned.at
Wed Jul 14 10:49:12 PDT 2010


Author: cornedbee
Date: Wed Jul 14 12:49:11 2010
New Revision: 108340

URL: http://llvm.org/viewvc/llvm-project?rev=108340&view=rev
Log:
Make PCHReader cope with PCH files containing more than one predefines buffer.

Added:
    cfe/trunk/test/PCH/pchpch.c
    cfe/trunk/test/PCH/pchpch1.h
    cfe/trunk/test/PCH/pchpch2.h
Modified:
    cfe/trunk/include/clang/Frontend/PCHReader.h
    cfe/trunk/lib/Frontend/PCHReader.cpp

Modified: cfe/trunk/include/clang/Frontend/PCHReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHReader.h?rev=108340&r1=108339&r2=108340&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHReader.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHReader.h Wed Jul 14 12:49:11 2010
@@ -65,6 +65,15 @@
 class PCHReader;
 struct HeaderFileInfo;
 
+struct PCHPredefinesBlock {
+  /// \brief The file ID for this predefines buffer in a PCH file.
+  FileID BufferID;
+
+  /// \brief This predefines buffer in a PCH file.
+  llvm::StringRef Data;
+};
+typedef llvm::SmallVector<PCHPredefinesBlock, 2> PCHPredefinesBlocks;
+
 /// \brief Abstract interface for callback invocations by the PCHReader.
 ///
 /// While reading a PCH file, the PCHReader will call the methods of the
@@ -103,8 +112,7 @@
   /// here.
   ///
   /// \returns true to indicate the predefines are invalid or false otherwise.
-  virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
-                                    FileID PCHBufferID,
+  virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
                                     llvm::StringRef OriginalFileName,
                                     std::string &SuggestedPredefines) {
     return false;
@@ -131,8 +139,7 @@
 
   virtual bool ReadLanguageOptions(const LangOptions &LangOpts);
   virtual bool ReadTargetTriple(llvm::StringRef Triple);
-  virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
-                                    FileID PCHBufferID,
+  virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
                                     llvm::StringRef OriginalFileName,
                                     std::string &SuggestedPredefines);
   virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID);
@@ -483,15 +490,9 @@
     ~ReadingKindTracker() { Reader.ReadingKind = PrevKind; }
   };
 
-  /// \brief The file ID for the predefines buffer in the PCH file.
-  FileID PCHPredefinesBufferID;
-
-  /// \brief Pointer to the beginning of the predefines buffer in the
-  /// PCH file.
-  const char *PCHPredefines;
-
-  /// \brief Length of the predefines buffer in the PCH file.
-  unsigned PCHPredefinesLen;
+  /// \brief All predefines buffers in all PCH files, to be treated as if
+  /// concatenated.
+  PCHPredefinesBlocks PCHPredefinesBuffers;
 
   /// \brief Suggested contents of the predefines buffer, after this
   /// PCH file has been processed.
@@ -509,7 +510,7 @@
   void MaybeAddSystemRootToFilename(std::string &Filename);
 
   PCHReadResult ReadPCHBlock();
-  bool CheckPredefinesBuffer(llvm::StringRef PCHPredef, FileID PCHBufferID);
+  bool CheckPredefinesBuffers();
   bool ParseLineTable(llvm::SmallVectorImpl<uint64_t> &Record);
   PCHReadResult ReadSourceManagerBlock();
   PCHReadResult ReadSLocEntryRecord(unsigned ID);

Modified: cfe/trunk/lib/Frontend/PCHReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReader.cpp?rev=108340&r1=108339&r2=108340&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHReader.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReader.cpp Wed Jul 14 12:49:11 2010
@@ -140,8 +140,86 @@
   return true;
 }
 
-bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef,
-                                        FileID PCHBufferID,
+struct EmptyStringRef {
+  bool operator ()(const llvm::StringRef &r) const { return r.empty(); }
+};
+struct EmptyBlock {
+  bool operator ()(const PCHPredefinesBlock &r) const { return r.Data.empty(); }
+};
+
+static bool EqualConcatenations(llvm::SmallVector<llvm::StringRef, 2> L,
+                                PCHPredefinesBlocks R) {
+  // First, sum up the lengths.
+  unsigned LL = 0, RL = 0;
+  for (unsigned I = 0, N = L.size(); I != N; ++I) {
+    LL += L[I].size();
+  }
+  for (unsigned I = 0, N = R.size(); I != N; ++I) {
+    RL += R[I].Data.size();
+  }
+  if (LL != RL)
+    return false;
+  if (LL == 0 && RL == 0)
+    return true;
+
+  // Kick out empty parts, they confuse the algorithm below.
+  L.erase(std::remove_if(L.begin(), L.end(), EmptyStringRef()), L.end());
+  R.erase(std::remove_if(R.begin(), R.end(), EmptyBlock()), R.end());
+
+  // Do it the hard way. At this point, both vectors must be non-empty.
+  llvm::StringRef LR = L[0], RR = R[0].Data;
+  unsigned LI = 0, RI = 0, LN = L.size(), RN = R.size();
+  for (;;) {
+    // Compare the current pieces.
+    if (LR.size() == RR.size()) {
+      // If they're the same length, it's pretty easy.
+      if (LR != RR)
+        return false;
+      // Both pieces are done, advance.
+      ++LI;
+      ++RI;
+      // If either string is done, they're both done, since they're the same
+      // length.
+      if (LI == LN) {
+        assert(RI == RN && "Strings not the same length after all?");
+        return true;
+      }
+      LR = L[LI];
+      RR = R[RI].Data;
+    } else if (LR.size() < RR.size()) {
+      // Right piece is longer.
+      if (!RR.startswith(LR))
+        return false;
+      ++LI;
+      assert(LI != LN && "Strings not the same length after all?");
+      RR = RR.substr(LR.size());
+      LR = L[LI];
+    } else {
+      // Left piece is longer.
+      if (!LR.startswith(RR))
+        return false;
+      ++RI;
+      assert(RI != RN && "Strings not the same length after all?");
+      LR = LR.substr(RR.size());
+      RR = R[RI].Data;
+    }
+  }
+}
+
+static std::pair<FileID, llvm::StringRef::size_type>
+FindMacro(const PCHPredefinesBlocks &Buffers, llvm::StringRef MacroDef) {
+  std::pair<FileID, llvm::StringRef::size_type> Res;
+  for (unsigned I = 0, N = Buffers.size(); I != N; ++I) {
+    Res.second = Buffers[I].Data.find(MacroDef);
+    if (Res.second != llvm::StringRef::npos) {
+      Res.first = Buffers[I].BufferID;
+      break;
+    }
+  }
+  return Res;
+}
+
+bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
                                         llvm::StringRef OriginalFileName,
                                         std::string &SuggestedPredefines) {
   // We are in the context of an implicit include, so the predefines buffer will
@@ -160,9 +238,15 @@
     return true;
   }
 
-  // If the predefines is equal to the joined left and right halves, we're done!
-  if (Left.size() + Right.size() == PCHPredef.size() &&
-      PCHPredef.startswith(Left) && PCHPredef.endswith(Right))
+  // If the concatenation of all the PCH buffers is equal to the adjusted
+  // command line, we're done.
+  // We build a SmallVector of the command line here, because we'll eventually
+  // need to support an arbitrary amount of pieces anyway (when we have chained
+  // PCH reading).
+  llvm::SmallVector<llvm::StringRef, 2> CommandLine;
+  CommandLine.push_back(Left);
+  CommandLine.push_back(Right);
+  if (EqualConcatenations(CommandLine, Buffers))
     return false;
 
   SourceManager &SourceMgr = PP.getSourceManager();
@@ -170,7 +254,8 @@
   // The predefines buffers are different. Determine what the differences are,
   // and whether they require us to reject the PCH file.
   llvm::SmallVector<llvm::StringRef, 8> PCHLines;
-  PCHPredef.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+  for (unsigned I = 0, N = Buffers.size(); I != N; ++I)
+    Buffers[I].Data.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
 
   llvm::SmallVector<llvm::StringRef, 8> CmdLineLines;
   Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
@@ -235,10 +320,12 @@
           << MacroName;
 
       // Show the definition of this macro within the PCH file.
-      llvm::StringRef::size_type Offset = PCHPredef.find(Missing);
-      assert(Offset != llvm::StringRef::npos && "Unable to find macro!");
-      SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID)
-        .getFileLocWithOffset(Offset);
+      std::pair<FileID, llvm::StringRef::size_type> MacroLoc =
+          FindMacro(Buffers, Missing);
+      assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!");
+      SourceLocation PCHMissingLoc =
+          SourceMgr.getLocForStartOfFile(MacroLoc.first)
+            .getFileLocWithOffset(MacroLoc.second);
       Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName;
 
       ConflictingDefines = true;
@@ -256,10 +343,12 @@
     }
 
     // Show the definition of this macro within the PCH file.
-    llvm::StringRef::size_type Offset = PCHPredef.find(Missing);
-    assert(Offset != llvm::StringRef::npos && "Unable to find macro!");
-    SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID)
-      .getFileLocWithOffset(Offset);
+    std::pair<FileID, llvm::StringRef::size_type> MacroLoc =
+        FindMacro(Buffers, Missing);
+    assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!");
+    SourceLocation PCHMissingLoc =
+        SourceMgr.getLocForStartOfFile(MacroLoc.first)
+          .getFileLocWithOffset(MacroLoc.second);
     Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch);
   }
 
@@ -609,27 +698,18 @@
   Diag(diag::err_fe_pch_malformed) << Msg;
 }
 
-/// \brief Check the contents of the predefines buffer against the
-/// contents of the predefines buffer used to build the PCH file.
-///
-/// The contents of the two predefines buffers should be the same. If
-/// not, then some command-line option changed the preprocessor state
-/// and we must reject the PCH file.
-///
-/// \param PCHPredef The start of the predefines buffer in the PCH
-/// file.
-///
-/// \param PCHPredefLen The length of the predefines buffer in the PCH
-/// file.
+/// \brief Check the contents of the concatenation of all predefines buffers in
+/// the PCH chain against the contents of the predefines buffer of the current
+/// compiler invocation.
 ///
-/// \param PCHBufferID The FileID for the PCH predefines buffer.
+/// The contents should be the same. If not, then some command-line option
+/// changed the preprocessor state and we must probably reject the PCH file.
 ///
 /// \returns true if there was a mismatch (in which case the PCH file
 /// should be ignored), or false otherwise.
-bool PCHReader::CheckPredefinesBuffer(llvm::StringRef PCHPredef,
-                                      FileID PCHBufferID) {
+bool PCHReader::CheckPredefinesBuffers() {
   if (Listener)
-    return Listener->ReadPredefinesBuffer(PCHPredef, PCHBufferID,
+    return Listener->ReadPredefinesBuffer(PCHPredefinesBuffers,
                                           ActualOriginalFileName,
                                           SuggestedPredefines);
   return false;
@@ -958,9 +1038,11 @@
     FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, Offset);
 
     if (strcmp(Name, "<built-in>") == 0) {
-      PCHPredefinesBufferID = BufferID;
-      PCHPredefines = BlobStart;
-      PCHPredefinesLen = BlobLen - 1;
+      PCHPredefinesBlock Block = {
+        BufferID,
+        llvm::StringRef(BlobStart, BlobLen - 1)
+      };
+      PCHPredefinesBuffers.push_back(Block);
     }
 
     break;
@@ -1636,8 +1718,7 @@
   }
 
   // Check the predefines buffer.
-  if (CheckPredefinesBuffer(llvm::StringRef(PCHPredefines, PCHPredefinesLen),
-                            PCHPredefinesBufferID))
+  if (CheckPredefinesBuffers())
     return IgnorePCH;
 
   if (PP) {

Added: cfe/trunk/test/PCH/pchpch.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/pchpch.c?rev=108340&view=auto
==============================================================================
--- cfe/trunk/test/PCH/pchpch.c (added)
+++ cfe/trunk/test/PCH/pchpch.c Wed Jul 14 12:49:11 2010
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pch -o %t1 %S/pchpch1.h
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pch -o %t2 %S/pchpch2.h -include-pch %t1
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fsyntax-only %s -include-pch %t2
+
+// The purpose of this test is to make sure that a PCH created while including
+// an existing PCH can be loaded.

Added: cfe/trunk/test/PCH/pchpch1.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/pchpch1.h?rev=108340&view=auto
==============================================================================
    (empty)

Added: cfe/trunk/test/PCH/pchpch2.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/pchpch2.h?rev=108340&view=auto
==============================================================================
    (empty)





More information about the cfe-commits mailing list