Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.

Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.

This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.

This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135484 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 6f72976..20eebaf 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -16,6 +16,7 @@
 
 #include "clang/Basic/DiagnosticIDs.h"
 #include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/OwningPtr.h"
@@ -984,6 +985,10 @@
   StoredDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info);
   StoredDiagnostic(Diagnostic::Level Level, unsigned ID, 
                    llvm::StringRef Message);
+  StoredDiagnostic(Diagnostic::Level Level, unsigned ID, 
+                   llvm::StringRef Message, FullSourceLoc Loc,
+                   llvm::ArrayRef<CharSourceRange> Ranges,
+                   llvm::ArrayRef<FixItHint> Fixits);
   ~StoredDiagnostic();
 
   /// \brief Evaluates true when this object stores a diagnostic.
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index ee5f96f..1cbcd40 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -35,8 +35,9 @@
 /// a source file (MemoryBuffer) along with its #include path and #line data.
 ///
 class FileID {
-  /// ID - Opaque identifier, 0 is "invalid".
-  unsigned ID;
+  /// ID - Opaque identifier, 0 is "invalid". >0 is this module, <-1 is
+  /// something loaded from another module.
+  int ID;
 public:
   FileID() : ID(0) {}
 
@@ -49,26 +50,38 @@
   bool operator>(const FileID &RHS) const { return RHS < *this; }
   bool operator>=(const FileID &RHS) const { return RHS <= *this; }
 
-  static FileID getSentinel() { return get(~0U); }
-  unsigned getHashValue() const { return ID; }
+  static FileID getSentinel() { return get(-1); }
+  unsigned getHashValue() const { return static_cast<unsigned>(ID); }
 
 private:
   friend class SourceManager;
   friend class ASTWriter;
   friend class ASTReader;
   
-  static FileID get(unsigned V) {
+  static FileID get(int V) {
     FileID F;
     F.ID = V;
     return F;
   }
-  unsigned getOpaqueValue() const { return ID; }
+  int getOpaqueValue() const { return ID; }
 };
 
 
-/// SourceLocation - This is a carefully crafted 32-bit identifier that encodes
-/// a full include stack, line and column number information for a position in
-/// an input translation unit.
+/// \brief Encodes a location in the source. The SourceManager can decode this
+/// to get at the full include stack, line and column information.
+///
+/// Technically, a source location is simply an offset into the manager's view
+/// of the input source, which is all input buffers (including macro
+/// instantiations) concatenated in an effectively arbitrary order. The manager
+/// actually maintains two blocks of input buffers. One, starting at offset 0
+/// and growing upwards, contains all buffers from this module. The other,
+/// starting at the highest possible offset and growing downwards, contains
+/// buffers of loaded modules.
+///
+/// In addition, one bit of SourceLocation is used for quick access to the
+/// information whether the location is in a file or a macro instantiation.
+///
+/// It is important that this type remains small. It is currently 32 bits wide.
 class SourceLocation {
   unsigned ID;
   friend class SourceManager;
@@ -77,21 +90,21 @@
   };
 public:
 
-  SourceLocation() : ID(0) {}  // 0 is an invalid FileID.
+  SourceLocation() : ID(0) {}
 
   bool isFileID() const  { return (ID & MacroIDBit) == 0; }
   bool isMacroID() const { return (ID & MacroIDBit) != 0; }
 
-  /// isValid - Return true if this is a valid SourceLocation object.  Invalid
-  /// SourceLocations are often used when events have no corresponding location
-  /// in the source (e.g. a diagnostic is required for a command line option).
+  /// \brief Return true if this is a valid SourceLocation object.
   ///
+  /// Invalid SourceLocations are often used when events have no corresponding
+  /// location in the source (e.g. a diagnostic is required for a command line
+  /// option).
   bool isValid() const { return ID != 0; }
   bool isInvalid() const { return ID == 0; }
 
 private:
-  /// getOffset - Return the index for SourceManager's SLocEntryTable table,
-  /// note that this is not an index *into* it though.
+  /// \brief Return the offset into the manager's global input view.
   unsigned getOffset() const {
     return ID & ~MacroIDBit;
   }
@@ -114,7 +127,8 @@
   /// getFileLocWithOffset - Return a source location with the specified offset
   /// from this file SourceLocation.
   SourceLocation getFileLocWithOffset(int Offset) const {
-    assert(((getOffset()+Offset) & MacroIDBit) == 0 && "invalid location");
+    assert(((getOffset()+Offset) & MacroIDBit) == 0 &&
+           "offset overflow or macro loc");
     SourceLocation L;
     L.ID = ID+Offset;
     return L;
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 6301f31..c08e691 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -46,7 +46,7 @@
   /// holds normal user code, system code, or system code which is implicitly
   /// 'extern "C"' in C++ mode.  Entire directories can be tagged with this
   /// (this is maintained by DirectoryLookup and friends) as can specific
-  /// FileIDInfos when a #pragma system_header is seen or various other cases.
+  /// FileInfos when a #pragma system_header is seen or various other cases.
   ///
   enum CharacteristicKind {
     C_User, C_System, C_ExternCSystem
@@ -356,11 +356,12 @@
 public:
   virtual ~ExternalSLocEntrySource();
 
-  /// \brief Read the source location entry with index ID.
+  /// \brief Read the source location entry with index ID, which will always be
+  /// less than -1.
   ///
   /// \returns true if an error occurred that prevented the source-location
   /// entry from being loaded.
-  virtual bool ReadSLocEntry(unsigned ID) = 0;
+  virtual bool ReadSLocEntry(int ID) = 0;
 };
   
 
@@ -414,8 +415,9 @@
   
 };
 
-/// SourceManager - This file handles loading and caching of source files into
-/// memory.  This object owns the MemoryBuffer objects for all of the loaded
+/// \brief This class handles loading and caching of source files into memory.
+///
+/// This object owns the MemoryBuffer objects for all of the loaded
 /// files and assigns unique FileID's for each unique #include chain.
 ///
 /// The SourceManager can be queried for information about SourceLocation
@@ -451,16 +453,33 @@
   /// as they do not refer to a file.
   std::vector<SrcMgr::ContentCache*> MemBufferInfos;
 
-  /// SLocEntryTable - This is an array of SLocEntry's that we have created.
-  /// FileID is an index into this vector.  This array is sorted by the offset.
-  std::vector<SrcMgr::SLocEntry> SLocEntryTable;
-  /// NextOffset - This is the next available offset that a new SLocEntry can
-  /// start at.  It is SLocEntryTable.back().getOffset()+size of back() entry.
-  unsigned NextOffset;
+  /// \brief The table of SLocEntries that are local to this module.
+  ///
+  /// Positive FileIDs are indexes into this table. Entry 0 indicates an invalid
+  /// instantiation.
+  std::vector<SrcMgr::SLocEntry> LocalSLocEntryTable;
 
-  /// \brief If source location entries are being lazily loaded from
-  /// an external source, this vector indicates whether the Ith source
-  /// location entry has already been loaded from the external storage.
+  /// \brief The table of SLocEntries that are loaded from other modules.
+  ///
+  /// Negative FileIDs are indexes into this table. To get from ID to an index,
+  /// use (-ID - 2).
+  std::vector<SrcMgr::SLocEntry> LoadedSLocEntryTable;
+
+  /// \brief The starting offset of the next local SLocEntry.
+  ///
+  /// This is LocalSLocEntryTable.back().Offset + the size of that entry.
+  unsigned NextLocalOffset;
+
+  /// \brief The starting offset of the latest batch of loaded SLocEntries.
+  ///
+  /// This is LoadedSLocEntryTable.back().Offset, except that that entry might
+  /// not have been loaded, so that value would be unknown.
+  unsigned CurrentLoadedOffset;
+
+  /// \brief A bitmap that indicates whether the entries of LoadedSLocEntryTable
+  /// have already been loaded from the external source.
+  ///
+  /// Same indexing as LoadedSLocEntryTable.
   std::vector<bool> SLocEntryLoaded;
 
   /// \brief An external source for source location entries.
@@ -513,6 +532,15 @@
     OverridenFilesKeepOriginalName = value;
   }
 
+  /// createMainFileIDForMembuffer - Create the FileID for a memory buffer
+  ///  that will represent the FileID for the main source.  One example
+  ///  of when this would be used is when the main source is read from STDIN.
+  FileID createMainFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer) {
+    assert(MainFileID.isInvalid() && "MainFileID already set!");
+    MainFileID = createFileIDForMemBuffer(Buffer);
+    return MainFileID;
+  }
+
   //===--------------------------------------------------------------------===//
   // MainFileID creation and querying methods.
   //===--------------------------------------------------------------------===//
@@ -541,34 +569,21 @@
   /// createFileID - Create a new FileID that represents the specified file
   /// being #included from the specified IncludePosition.  This translates NULL
   /// into standard input.
-  /// PreallocateID should be non-zero to specify which pre-allocated,
-  /// lazily computed source location is being filled in by this operation.
   FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos,
                       SrcMgr::CharacteristicKind FileCharacter,
-                      unsigned PreallocatedID = 0,
-                      unsigned Offset = 0) {
+                      int LoadedID = 0, unsigned LoadedOffset = 0) {
     const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile);
     assert(IR && "getOrCreateContentCache() cannot return NULL");
-    return createFileID(IR, IncludePos, FileCharacter, PreallocatedID, Offset);
+    return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset);
   }
 
   /// createFileIDForMemBuffer - Create a new FileID that represents the
   /// specified memory buffer.  This does no caching of the buffer and takes
   /// ownership of the MemoryBuffer, so only pass a MemoryBuffer to this once.
   FileID createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer,
-                                  unsigned PreallocatedID = 0,
-                                  unsigned Offset = 0) {
+                                  int LoadedID = 0, unsigned LoadedOffset = 0) {
     return createFileID(createMemBufferContentCache(Buffer), SourceLocation(),
-                        SrcMgr::C_User, PreallocatedID, Offset);
-  }
-
-  /// createMainFileIDForMembuffer - Create the FileID for a memory buffer
-  ///  that will represent the FileID for the main source.  One example
-  ///  of when this would be used is when the main source is read from STDIN.
-  FileID createMainFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer) {
-    assert(MainFileID.isInvalid() && "MainFileID already set!");
-    MainFileID = createFileIDForMemBuffer(Buffer);
-    return MainFileID;
+                        SrcMgr::C_User, LoadedID, LoadedOffset);
   }
 
   /// createMacroArgInstantiationLoc - Return a new SourceLocation that encodes
@@ -586,8 +601,8 @@
                                         SourceLocation InstantiationLocStart,
                                         SourceLocation InstantiationLocEnd,
                                         unsigned TokLength,
-                                        unsigned PreallocatedID = 0,
-                                        unsigned Offset = 0);
+                                        int LoadedID = 0,
+                                        unsigned LoadedOffset = 0);
 
   /// \brief Retrieve the memory buffer associated with the given file.
   ///
@@ -702,7 +717,6 @@
   /// getLocForStartOfFile - Return the source location corresponding to the
   /// first byte of the specified file.
   SourceLocation getLocForStartOfFile(FileID FID) const {
-    assert(FID.ID < SLocEntryTable.size() && "FileID out of range");
     bool Invalid = false;
     const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
     if (Invalid || !Entry.isFile())
@@ -900,10 +914,12 @@
 #ifndef NDEBUG
     // Make sure offset/length describe a chunk inside the given FileID.
     unsigned NextOffset;
-    if (FID.ID+1 == SLocEntryTable.size())
-      NextOffset = getNextOffset();
+    if (FID.ID == -2)
+      NextOffset = 1U << 31U;
+    else if (FID.ID+1 == (int)LocalSLocEntryTable.size())
+      NextOffset = getNextLocalOffset();
     else
-      NextOffset = getSLocEntry(FID.ID+1).getOffset();
+      NextOffset = getSLocEntryByID(FID.ID+1).getOffset();
     assert(start < NextOffset);
     assert(end   < NextOffset);
 #endif
@@ -979,15 +995,23 @@
 
   /// \brief Determines the order of 2 source locations in the "source location
   /// address space".
-  static bool isBeforeInSourceLocationOffset(SourceLocation LHS,
-                                             SourceLocation RHS) {
+  bool isBeforeInSourceLocationOffset(SourceLocation LHS, 
+                                      SourceLocation RHS) const {
     return isBeforeInSourceLocationOffset(LHS, RHS.getOffset());
   }
 
   /// \brief Determines the order of a source location and a source location
   /// offset in the "source location address space".
-  static bool isBeforeInSourceLocationOffset(SourceLocation LHS, unsigned RHS) {
-    return LHS.getOffset() < RHS;
+  ///
+  /// Note that we always consider source locations loaded from 
+  bool isBeforeInSourceLocationOffset(SourceLocation LHS, unsigned RHS) const {
+    unsigned LHSOffset = LHS.getOffset();
+    bool LHSLoaded = LHSOffset >= CurrentLoadedOffset;
+    bool RHSLoaded = RHS >= CurrentLoadedOffset;
+    if (LHSLoaded == RHSLoaded)
+      return LHS.getOffset() < RHS;
+    
+    return LHSLoaded;
   }
 
   // Iterators over FileInfos.
@@ -1003,53 +1027,70 @@
   ///
   void PrintStats() const;
 
-  unsigned sloc_entry_size() const { return SLocEntryTable.size(); }
-
-  // FIXME: Exposing this is a little gross; what we want is a good way
-  //  to iterate the entries that were not defined in an AST file (or
-  //  any other external source).
-  unsigned sloc_loaded_entry_size() const { return SLocEntryLoaded.size(); }
-
-  const SrcMgr::SLocEntry &getSLocEntry(unsigned ID, bool *Invalid = 0) const {
-    assert(ID < SLocEntryTable.size() && "Invalid id");
-    // If we haven't loaded this source-location entry from the external source
-    // yet, do so now.
-    if (ExternalSLocEntries &&
-        ID < SLocEntryLoaded.size() &&
-        !SLocEntryLoaded[ID] &&
-        ExternalSLocEntries->ReadSLocEntry(ID) &&
-        Invalid)
-      *Invalid = true;
-
-    return SLocEntryTable[ID];
+  /// \brief Get the number of local SLocEntries we have.
+  unsigned local_sloc_entry_size() const { return LocalSLocEntryTable.size(); }
+  
+  /// \brief Get a local SLocEntry. This is exposed for indexing.
+  const SrcMgr::SLocEntry &getLocalSLocEntry(unsigned Index, 
+                                             bool *Invalid = 0) const {
+    assert(Index < LocalSLocEntryTable.size() && "Invalid index");
+    return LocalSLocEntryTable[Index];
   }
-
+  
+  /// \brief Get the number of loaded SLocEntries we have.
+  unsigned loaded_sloc_entry_size() const { return LoadedSLocEntryTable.size();}
+  
+  /// \brief Get a loaded SLocEntry. This is exposed for indexing.
+  const SrcMgr::SLocEntry &getLoadedSLocEntry(unsigned Index, bool *Invalid=0) const {
+    assert(Index < LoadedSLocEntryTable.size() && "Invalid index");
+    if (!SLocEntryLoaded[Index])
+      ExternalSLocEntries->ReadSLocEntry(-(static_cast<int>(Index) + 2));
+    return LoadedSLocEntryTable[Index];
+  }
+  
   const SrcMgr::SLocEntry &getSLocEntry(FileID FID, bool *Invalid = 0) const {
-    return getSLocEntry(FID.ID, Invalid);
+    return getSLocEntryByID(FID.ID);
   }
 
-  unsigned getNextOffset() const { return NextOffset; }
-
-  /// \brief Preallocate some number of source location entries, which
-  /// will be loaded as needed from the given external source.
-  void PreallocateSLocEntries(ExternalSLocEntrySource *Source,
-                              unsigned NumSLocEntries,
-                              unsigned NextOffset);
-
-  /// \brief Clear out any preallocated source location entries that
-  /// haven't already been loaded.
-  void ClearPreallocatedSLocEntries();
-
+  unsigned getNextLocalOffset() const { return NextLocalOffset; }
+  
+  void setExternalSLocEntrySource(ExternalSLocEntrySource *Source) {
+    assert(LoadedSLocEntryTable.empty() &&
+           "Invalidating existing loaded entries");
+    ExternalSLocEntries = Source;
+  }
+  
+  /// \brief Allocate a number of loaded SLocEntries, which will be actually
+  /// loaded on demand from the external source.
+  ///
+  /// NumSLocEntries will be allocated, which occupy a total of TotalSize space
+  /// in the global source view. The lowest ID and the base offset of the
+  /// entries will be returned.
+  std::pair<int, unsigned>
+  AllocateLoadedSLocEntries(unsigned NumSLocEntries, unsigned TotalSize);
+  
 private:
   const llvm::MemoryBuffer *getFakeBufferForRecovery() const;
 
+  /// \brief Get the entry with the given unwrapped FileID.
+  const SrcMgr::SLocEntry &getSLocEntryByID(int ID) const {
+    assert(ID != -1 && "Using FileID sentinel value");
+    if (ID < 0)
+      return getLoadedSLocEntryByID(ID);
+    return getLocalSLocEntry(static_cast<unsigned>(ID));
+  }
+  
+  const SrcMgr::SLocEntry &getLoadedSLocEntryByID(int ID) const {
+    return getLoadedSLocEntry(static_cast<unsigned>(-ID - 2));
+  }
+  
   /// createInstantiationLoc - Implements the common elements of storing an
   /// instantiation info struct into the SLocEntry table and producing a source
   /// location that refers to it.
   SourceLocation createInstantiationLocImpl(const SrcMgr::InstantiationInfo &II,
                                             unsigned TokLength,
-                                            unsigned PreallocatedID = 0,
-                                            unsigned Offset = 0);
+                                            int LoadedID = 0,
+                                            unsigned LoadedOffset = 0);
 
   /// isOffsetInFileID - Return true if the specified FileID contains the
   /// specified SourceLocation offset.  This is a very hot method.
@@ -1058,10 +1099,17 @@
     // If the entry is after the offset, it can't contain it.
     if (SLocOffset < Entry.getOffset()) return false;
 
-    // If this is the last entry than it does.  Otherwise, the entry after it
-    // has to not include it.
-    if (FID.ID+1 == SLocEntryTable.size()) return true;
+    // If this is the very last entry then it does.
+    if (FID.ID == -2)
+      return true;
 
+    // If it is the last local entry, then it does if the location is local.
+    if (static_cast<unsigned>(FID.ID+1) == LocalSLocEntryTable.size()) {
+      return SLocOffset < NextLocalOffset;
+    }
+
+    // Otherwise, the entry after it has to not include it. This works for both
+    // local and loaded entries.
     return SLocOffset < getSLocEntry(FileID::get(FID.ID+1)).getOffset();
   }
 
@@ -1071,8 +1119,7 @@
   FileID createFileID(const SrcMgr::ContentCache* File,
                       SourceLocation IncludePos,
                       SrcMgr::CharacteristicKind DirCharacter,
-                      unsigned PreallocatedID = 0,
-                      unsigned Offset = 0);
+                      int LoadedID, unsigned LoadedOffset);
 
   const SrcMgr::ContentCache *
     getOrCreateContentCache(const FileEntry *SourceFile);
@@ -1083,6 +1130,8 @@
   createMemBufferContentCache(const llvm::MemoryBuffer *Buf);
 
   FileID getFileIDSlow(unsigned SLocOffset) const;
+  FileID getFileIDLocal(unsigned SLocOffset) const;
+  FileID getFileIDLoaded(unsigned SLocOffset) const;
 
   SourceLocation getInstantiationLocSlowCase(SourceLocation Loc) const;
   SourceLocation getSpellingLocSlowCase(SourceLocation Loc) const;
diff --git a/include/clang/Basic/SourceManagerInternals.h b/include/clang/Basic/SourceManagerInternals.h
index 3f5d1a3..6a74d41 100644
--- a/include/clang/Basic/SourceManagerInternals.h
+++ b/include/clang/Basic/SourceManagerInternals.h
@@ -84,7 +84,7 @@
 
   /// LineEntries - This is a map from FileIDs to a list of line entries (sorted
   /// by the offset they occur in the file.
-  std::map<unsigned, std::vector<LineEntry> > LineEntries;
+  std::map<int, std::vector<LineEntry> > LineEntries;
 public:
   LineTableInfo() {
   }
@@ -104,25 +104,25 @@
   }
   unsigned getNumFilenames() const { return FilenamesByID.size(); }
 
-  void AddLineNote(unsigned FID, unsigned Offset,
+  void AddLineNote(int FID, unsigned Offset,
                    unsigned LineNo, int FilenameID);
-  void AddLineNote(unsigned FID, unsigned Offset,
+  void AddLineNote(int FID, unsigned Offset,
                    unsigned LineNo, int FilenameID,
                    unsigned EntryExit, SrcMgr::CharacteristicKind FileKind);
 
 
   /// FindNearestLineEntry - Find the line entry nearest to FID that is before
   /// it.  If there is no line entry before Offset in FID, return null.
-  const LineEntry *FindNearestLineEntry(unsigned FID, unsigned Offset);
+  const LineEntry *FindNearestLineEntry(int FID, unsigned Offset);
 
   // Low-level access
-  typedef std::map<unsigned, std::vector<LineEntry> >::iterator iterator;
+  typedef std::map<int, std::vector<LineEntry> >::iterator iterator;
   iterator begin() { return LineEntries.begin(); }
   iterator end() { return LineEntries.end(); }
 
   /// \brief Add a new line entry that has already been encoded into
   /// the internal representation of the line table.
-  void AddEntry(unsigned FID, const std::vector<LineEntry> &Entries);
+  void AddEntry(int FID, const std::vector<LineEntry> &Entries);
 };
 
 } // end namespace clang
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 58a60a1..9fb5521 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -41,6 +41,7 @@
 
 namespace clang {
 class ASTContext;
+class ASTReader;
 class CodeCompleteConsumer;
 class CompilerInvocation;
 class Decl;
@@ -143,6 +144,9 @@
   // Critical optimization when using clang_getCursor().
   ASTLocation LastLoc;
 
+  /// \brief The set of diagnostics produced when creating the preamble.
+  llvm::SmallVector<StoredDiagnostic, 4> PreambleDiagnostics;
+
   /// \brief The set of diagnostics produced when creating this
   /// translation unit.
   llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
@@ -230,14 +234,6 @@
   /// when any errors are present.
   unsigned NumWarningsInPreamble;
 
-  /// \brief The number of diagnostics that were stored when parsing
-  /// the precompiled preamble.
-  ///
-  /// This value is used to determine how many of the stored
-  /// diagnostics should be retained when reparsing in the presence of
-  /// a precompiled preamble.
-  unsigned NumStoredDiagnosticsInPreamble;
-
   /// \brief A list of the serialization ID numbers for each of the top-level
   /// declarations parsed within the precompiled preamble.
   std::vector<serialization::DeclID> TopLevelDeclsInPreamble;
@@ -257,6 +253,11 @@
                              const char **ArgBegin, const char **ArgEnd,
                              ASTUnit &AST, bool CaptureDiagnostics);
 
+  void TranslateStoredDiagnostics(ASTReader *MMan, llvm::StringRef ModName,
+                                  SourceManager &SrcMan,
+                      const llvm::SmallVectorImpl<StoredDiagnostic> &Diags,
+                            llvm::SmallVectorImpl<StoredDiagnostic> &Out);
+
 public:
   /// \brief A cached code-completion result, which may be introduced in one of
   /// many different contexts.
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 004c889..b2c877a 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -27,13 +27,13 @@
 namespace clang {
 class ASTContext;
 class ASTConsumer;
+class ASTReader;
 class CodeCompleteConsumer;
 class Diagnostic;
 class DiagnosticClient;
 class ExternalASTSource;
 class FileManager;
 class FrontendAction;
-class ASTReader;
 class Preprocessor;
 class Sema;
 class SourceManager;
@@ -88,9 +88,12 @@
   /// \brief The semantic analysis object.
   llvm::OwningPtr<Sema> TheSema;
   
-  /// The frontend timer
+  /// \brief The frontend timer
   llvm::OwningPtr<llvm::Timer> FrontendTimer;
 
+  /// \brief Non-owning reference to the ASTReader, if one exists.
+  ASTReader *ModuleManager;
+
   /// \brief Holds information about the output file.
   ///
   /// If TempFilename is not empty we must rename it to Filename at the end.
@@ -388,6 +391,12 @@
   Sema *takeSema() { return TheSema.take(); }
   
   /// }
+  /// @name Module Management
+  /// {
+
+  ASTReader *getModuleManager() const { return ModuleManager; }
+
+  /// }
   /// @name Code Completion
   /// {
 
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 11b8bed..a01bf62 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -375,8 +375,14 @@
       
       /// \brief Record code for the set of known namespaces, which are used
       /// for typo correction.
-      KNOWN_NAMESPACES = 46
+      KNOWN_NAMESPACES = 46,
 
+      /// \brief Record code for the source location remapping information.
+      SOURCE_LOCATION_MAP = 47,
+
+      /// \brief Record code for the source manager line table information,
+      /// which stores information about #line directives.
+      SOURCE_MANAGER_LINE_TABLE = 48
     };
 
     /// \brief Record types used within a source manager block.
@@ -393,10 +399,7 @@
       SM_SLOC_BUFFER_BLOB = 3,
       /// \brief Describes a source location entry (SLocEntry) for a
       /// macro expansion.
-      SM_SLOC_EXPANSION_ENTRY = 4,
-      /// \brief Describes the SourceManager's line table, with
-      /// information about #line directives.
-      SM_LINE_TABLE = 5
+      SM_SLOC_EXPANSION_ENTRY = 4
     };
 
     /// \brief Record types used within a preprocessor block.
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 9e210c3..a0bc899 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_FRONTEND_AST_READER_H
 
 #include "clang/Serialization/ASTBitCodes.h"
+#include "clang/Serialization/ContinuousRangeMap.h"
 #include "clang/Sema/ExternalSemaSource.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/DeclObjC.h"
@@ -49,6 +50,7 @@
 class ASTConsumer;
 class ASTContext;
 class ASTIdentifierIterator;
+class ASTUnit; // FIXME: Layering violation and egregious hack.
 class Attr;
 class Decl;
 class DeclContext;
@@ -64,6 +66,7 @@
 class Sema;
 class SwitchCase;
 class ASTDeserializationListener;
+class ASTWriter;
 class ASTReader;
 class ASTDeclReader;
 class ASTStmtReader;
@@ -191,6 +194,8 @@
   friend class ASTIdentifierIterator;
   friend class ASTIdentifierLookupTrait;
   friend class TypeLocReader;
+  friend class ASTWriter;
+  friend class ASTUnit; // ASTUnit needs to remap source locations.
 private:
   /// \brief The receiver of some callbacks invoked by ASTReader.
   llvm::OwningPtr<ASTReaderListener> Listener;
@@ -245,6 +250,12 @@
     /// \brief The main bitstream cursor for the main block.
     llvm::BitstreamCursor Stream;
 
+    /// \brief The source location where this module was first imported.
+    SourceLocation ImportLoc;
+
+    /// \brief The first source location in this module.
+    SourceLocation FirstLoc;
+
     // === Source Locations ===
 
     /// \brief Cursor used to read source location entries.
@@ -253,9 +264,15 @@
     /// \brief The number of source location entries in this AST file.
     unsigned LocalNumSLocEntries;
 
+    /// \brief The base ID in the source manager's view of this module.
+    int SLocEntryBaseID;
+
+    /// \brief The base offset in the source manager's view of this module.
+    unsigned SLocEntryBaseOffset;
+
     /// \brief Offsets for all of the source location entries in the
     /// AST file.
-    const uint32_t *SLocOffsets;
+    const uint32_t *SLocEntryOffsets;
 
     /// \brief The number of source location file entries in this AST file.
     unsigned LocalNumSLocFileEntries;
@@ -264,8 +281,8 @@
     /// AST file.
     const uint32_t *SLocFileOffsets;
 
-    /// \brief The entire size of this module's source location offset range.
-    unsigned LocalSLocSize;
+    /// \brief Remapping table for source locations in this module.
+    ContinuousRangeMap<uint32_t, int, 2> SLocRemap;
 
     // === Identifiers ===
 
@@ -397,6 +414,9 @@
 
     // === Miscellaneous ===
 
+    /// \brief Diagnostic IDs and their mappings that the user changed.
+    llvm::SmallVector<uint64_t, 8> PragmaDiagMappings;
+
     /// \brief The AST stat cache installed for this file, if any.
     ///
     /// The dynamic type of this stat cache is always ASTStatCache
@@ -426,7 +446,10 @@
   llvm::SmallVector<PerFileData*, 2> Chain;
 
   /// \brief SLocEntries that we're going to preload.
-  llvm::SmallVector<uint64_t, 64> PreloadSLocEntries;
+  llvm::SmallVector<int, 64> PreloadSLocEntries;
+
+  /// \brief A map of negated SLocEntryIDs to the modules containing them.
+  ContinuousRangeMap<unsigned, PerFileData*, 64> GlobalSLocEntryMap;
 
   /// \brief Types that have already been loaded from the chain.
   ///
@@ -630,9 +653,6 @@
 
   //@}
 
-  /// \brief Diagnostic IDs and their mappings that the user changed.
-  llvm::SmallVector<uint64_t, 8> PragmaDiagMappings;
-
   /// \brief The original file name that was used to build the primary AST file,
   /// which may have been modified for relocatable-pch support.
   std::string OriginalFileName;
@@ -686,9 +706,6 @@
   /// \brief The number of source location entries in the chain.
   unsigned TotalNumSLocEntries;
 
-  /// \brief The next offset for a SLocEntry after everything in this reader.
-  unsigned NextSLocOffset;
-
   /// \brief The number of statements (and expressions) de-serialized
   /// from the chain.
   unsigned NumStatementsRead;
@@ -810,8 +827,8 @@
   bool CheckPredefinesBuffers();
   bool ParseLineTable(PerFileData &F, llvm::SmallVectorImpl<uint64_t> &Record);
   ASTReadResult ReadSourceManagerBlock(PerFileData &F);
-  ASTReadResult ReadSLocEntryRecord(unsigned ID);
-  PerFileData *SLocCursorForID(unsigned ID);
+  ASTReadResult ReadSLocEntryRecord(int ID);
+  llvm::BitstreamCursor &SLocCursorForID(int ID);
   SourceLocation getImportLocation(PerFileData *F);
   bool ParseLanguageOptions(const llvm::SmallVectorImpl<uint64_t> &Record);
 
@@ -960,11 +977,6 @@
     return TotalNumSLocEntries;
   }
 
-  /// \brief Returns the next SLocEntry offset after the chain.
-  unsigned getNextSLocOffset() const {
-    return NextSLocOffset;
-  }
-
   /// \brief Returns the number of identifiers found in the chain.
   unsigned getTotalNumIdentifiers() const {
     return static_cast<unsigned>(IdentifiersLoaded.size());
@@ -1158,7 +1170,7 @@
   }
 
   /// \brief Read the source location entry with index ID.
-  virtual bool ReadSLocEntry(unsigned ID);
+  virtual bool ReadSLocEntry(int ID);
 
   Selector DecodeSelector(unsigned Idx);
 
@@ -1221,8 +1233,15 @@
 
   /// \brief Read a source location from raw form.
   SourceLocation ReadSourceLocation(PerFileData &Module, unsigned Raw) {
-    (void)Module; // No remapping yet
-    return SourceLocation::getFromRawEncoding(Raw);
+    unsigned Flag = Raw & (1U << 31);
+    unsigned Offset = Raw & ~(1U << 31);
+    assert(Module.SLocRemap.find(Offset) != Module.SLocRemap.end() &&
+           "Cannot find offset to remap.");
+    int Remap = Module.SLocRemap.find(Offset)->second;
+    Offset += Remap;
+    assert((Offset & (1U << 31)) == 0 &&
+           "Bad offset in reading source location");
+    return SourceLocation::getFromRawEncoding(Offset | Flag);
   }
 
   /// \brief Read a source location.
diff --git a/include/clang/Serialization/ContinuousRangeMap.h b/include/clang/Serialization/ContinuousRangeMap.h
new file mode 100644
index 0000000..2a27b91
--- /dev/null
+++ b/include/clang/Serialization/ContinuousRangeMap.h
@@ -0,0 +1,90 @@
+//===--- ContinuousRangeMap.h - Map with int range as key -------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the ContinuousRangeMap class, which is a highly
+//  specialized container used by serialization.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SERIALIZATION_CONTINUOUS_RANGE_MAP_H
+#define LLVM_CLANG_SERIALIZATION_CONTINUOUS_RANGE_MAP_H
+
+#include "llvm/ADT/SmallVector.h"
+#include <algorithm>
+#include <utility>
+
+namespace clang {
+
+/// \brief A map from continuous integer ranges to some value, with a very
+/// specialized interface.
+///
+/// CRM maps from integer ranges to values. The ranges are continuous, i.e.
+/// where one ends, the next one begins. So if the map contains the stops I0-3,
+/// the first range is from I0 to I1, the second from I1 to I2, the third from
+/// I2 to I3 and the last from I3 to infinity.
+///
+/// Ranges must be inserted in order. Inserting a new stop I4 into the map will
+/// shrink the fourth range to I3 to I4 and add the new range I4 to inf.
+template <typename Int, typename V, unsigned InitialCapacity>
+class ContinuousRangeMap {
+public:
+  typedef std::pair<const Int, V> value_type;
+  typedef value_type &reference;
+  typedef const value_type &const_reference;
+  typedef value_type *pointer;
+  typedef const value_type *const_pointer;
+
+private:
+  typedef llvm::SmallVector<value_type, InitialCapacity> Representation;
+  Representation Rep;
+
+  struct Compare {
+    bool operator ()(const_reference L, Int R) const {
+      return L.first < R;
+    }
+    bool operator ()(Int L, const_reference R) const {
+      return L < R.first;
+    }
+  };
+
+public:
+  void insert(const value_type &Val) {
+    assert((Rep.empty() || Rep.back().first < Val.first) &&
+           "Must insert keys in order.");
+    Rep.push_back(Val);
+  }
+
+  typedef typename Representation::iterator iterator;
+  typedef typename Representation::const_iterator const_iterator;
+
+  iterator begin() { return Rep.begin(); }
+  iterator end() { return Rep.end(); }
+  const_iterator begin() const { return Rep.begin(); }
+  const_iterator end() const { return Rep.end(); }
+
+  iterator find(Int K) {
+    iterator I = std::upper_bound(Rep.begin(), Rep.end(), K, Compare());
+    // I points to the first entry with a key > K, which is the range that
+    // follows the one containing K.
+    if (I == Rep.begin())
+      return Rep.end();
+    --I;
+    return I;
+  }
+  const_iterator find(Int K) const {
+    return const_cast<ContinuousRangeMap*>(this)->find(K);
+  }
+
+  reference back() { return Rep.back(); }
+  const_reference back() const { return Rep.back(); }
+};
+
+}
+
+#endif