Introduce basic support for loading a precompiled preamble while
reparsing an ASTUnit. When saving a preamble, create a buffer larger
than the actual file we're working with but fill everything from the
end of the preamble to the end of the file with spaces (so the lexer
will quickly skip them). When we load the file, create a buffer of the
same size, filling it with the file and then spaces. Then, instruct
the lexer to start lexing after the preamble, therefore continuing the
parse from the spot where the preamble left off.

It's now possible to perform a simple preamble build + parse (+
reparse) with ASTUnit. However, one has to disable a bunch of checking
in the PCH reader to do so. That part isn't committed; it will likely
be handled with some other kind of flag (e.g., -fno-validate-pch).

As part of this, fix some issues with null termination of the memory
buffers created for the preamble; we were trying to explicitly
NULL-terminate them, even though they were also getting implicitly
NULL terminated, leading to excess warnings about NULL characters in
source files.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109445 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index e6d9785..4a1eb30 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -32,7 +32,8 @@
 //===----------------------------------------------------------------------===//
 
 ContentCache::~ContentCache() {
-  delete Buffer.getPointer();
+  if (shouldFreeBuffer())
+    delete Buffer.getPointer();
 }
 
 /// getSizeBytesMapped - Returns the number of bytes actually mapped for
@@ -51,12 +52,14 @@
                              : (unsigned) Entry->getSize();
 }
 
-void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) {
+void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B,
+                                 bool DoNotFree) {
   assert(B != Buffer.getPointer());
   
-  delete Buffer.getPointer();
+  if (shouldFreeBuffer())
+    delete Buffer.getPointer();
   Buffer.setPointer(B);
-  Buffer.setInt(false);
+  Buffer.setInt(DoNotFree? DoNotFreeFlag : 0);
 }
 
 const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
@@ -72,7 +75,6 @@
     struct stat FileInfo;
     Buffer.setPointer(MemoryBuffer::getFile(Entry->getName(), &ErrorStr,
                                             Entry->getSize(), &FileInfo));
-    Buffer.setInt(false);
     
     // If we were unable to open the file, then we are in an inconsistent
     // situation where the content cache referenced a file which no longer
@@ -99,7 +101,7 @@
         Diag.Report(FullSourceLoc(Loc, SM), diag::err_cannot_open_file)
           << Entry->getName() << ErrorStr;
 
-      Buffer.setInt(true);
+      Buffer.setInt(Buffer.getInt() | InvalidFlag);
 
     // FIXME: This conditionalization is horrible, but we see spurious failures
     // in the test suite due to this warning and no one has had time to hunt it
@@ -119,14 +121,14 @@
         Diag.Report(FullSourceLoc(Loc, SM), diag::err_file_modified)
           << Entry->getName();
 
-      Buffer.setInt(true);
+      Buffer.setInt(Buffer.getInt() | InvalidFlag);
 #endif
     }
     
     // If the buffer is valid, check to see if it has a UTF Byte Order Mark
     // (BOM).  We only support UTF-8 without a BOM right now.  See
     // http://en.wikipedia.org/wiki/Byte_order_mark for more information.
-    if (!Buffer.getInt()) {
+    if (!isBufferInvalid()) {
       llvm::StringRef BufStr = Buffer.getPointer()->getBuffer();
       const char *BOM = 0;
       if (BufStr.startswith("\xFE\xBB\xBF"))
@@ -161,7 +163,7 @@
   }
   
   if (Invalid)
-    *Invalid = Buffer.getInt();
+    *Invalid = isBufferInvalid();
   
   return Buffer.getPointer();
 }
@@ -521,12 +523,13 @@
 }
 
 bool SourceManager::overrideFileContents(const FileEntry *SourceFile,
-                                         const llvm::MemoryBuffer *Buffer) {
+                                         const llvm::MemoryBuffer *Buffer,
+                                         bool DoNotFree) {
   const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile);
   if (IR == 0)
     return true;
 
-  const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer);
+  const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer, DoNotFree);
   return false;
 }