Index: include/clang/Lex/PreprocessingRecord.h =================================================================== --- include/clang/Lex/PreprocessingRecord.h +++ include/clang/Lex/PreprocessingRecord.h @@ -282,6 +282,9 @@ FileID FID) { return None; } + + /// \brief Read a preallocated skipped range from the external source. + virtual SourceRange ReadSkippedRange(unsigned Index) = 0; }; /// \brief A record of the steps taken while preprocessing a source file, @@ -307,6 +310,8 @@ /// \brief The set of ranges that were skipped by the preprocessor, std::vector SkippedRanges; + bool SkippedRangesAllLoaded; + /// \brief Global (loaded or local) ID for a preprocessed entity. /// Negative values are used to indicate preprocessed entities /// loaded from the external source while non-negative values are used to @@ -359,6 +364,15 @@ /// corresponds to the first newly-allocated entity. unsigned allocateLoadedEntities(unsigned NumEntities); + /// \brief Allocate space for a new set of loaded preprocessed skipped ranges. + /// + /// \returns The index into the set of loaded preprocessed ranges, which + /// corresponds to the first newly-allocated range. + unsigned allocateSkippedRanges(unsigned NumRanges); + + /// \brief Ensures that all external skipped ranges have been loaded. + void ensureSkippedRangesLoaded(); + /// \brief Register a new macro definition. void RegisterMacroDefinition(MacroInfo *Macro, MacroDefinitionRecord *Def); @@ -481,7 +495,8 @@ MacroDefinitionRecord *findMacroDefinition(const MacroInfo *MI); /// \brief Retrieve all ranges that got skipped while preprocessing. - const std::vector &getSkippedRanges() const { + const std::vector &getSkippedRanges() { + ensureSkippedRangesLoaded(); return SkippedRanges; } Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -183,6 +183,25 @@ } }; + /// \brief Source range of a skipped preprocessor region + struct PPSkippedRange { + /// \brief Raw source location of beginning of range. + unsigned Begin; + /// \brief Raw source location of end of range. + unsigned End; + + PPSkippedRange(SourceRange R) + : Begin(R.getBegin().getRawEncoding()), + End(R.getEnd().getRawEncoding()) { } + + SourceLocation getBegin() const { + return SourceLocation::getFromRawEncoding(Begin); + } + SourceLocation getEnd() const { + return SourceLocation::getFromRawEncoding(End); + } + }; + /// \brief Source range/offset of a preprocessed entity. struct DeclOffset { /// \brief Raw source location. @@ -580,7 +599,10 @@ MSSTRUCT_PRAGMA_OPTIONS = 55, /// \brief Record code for \#pragma ms_struct options. - POINTERS_TO_MEMBERS_PRAGMA_OPTIONS = 56 + POINTERS_TO_MEMBERS_PRAGMA_OPTIONS = 56, + + /// \brief A table of skipped ranges within the preprocessing record. + PPD_SKIPPED_RANGES = 57 }; /// \brief Record types used within a source manager block. Index: include/clang/Serialization/ASTReader.h =================================================================== --- include/clang/Serialization/ASTReader.h +++ include/clang/Serialization/ASTReader.h @@ -686,6 +686,13 @@ /// added to the global preprocessing entitiy ID to produce a local ID. GlobalPreprocessedEntityMapType GlobalPreprocessedEntityMap; + typedef ContinuousRangeMap + GlobalSkippedRangeMapType; + + /// \brief Mapping from global skipped range base IDs to the module in which + /// the skipped ranges reside. + GlobalSkippedRangeMapType GlobalSkippedRangeMap; + /// \name CodeGen-relevant special data /// \brief Fields containing data that is relevant to CodeGen. //@{ @@ -1529,6 +1536,9 @@ Optional isPreprocessedEntityInFileID(unsigned Index, FileID FID) override; + /// \brief Read a preallocated skipped range from the external source. + SourceRange ReadSkippedRange(unsigned Index) override; + /// \brief Read the header file information for the given file entry. HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE) override; Index: include/clang/Serialization/Module.h =================================================================== --- include/clang/Serialization/Module.h +++ include/clang/Serialization/Module.h @@ -315,6 +315,10 @@ const PPEntityOffset *PreprocessedEntityOffsets; unsigned NumPreprocessedEntities; + unsigned BasePreprocessedSkippedRangeID; + const PPSkippedRange *PreprocessedSkippedRangeOffsets; + unsigned NumPreprocessedSkippedRanges; + // === Header search information === /// \brief The number of local HeaderFileInfo structures. Index: lib/Lex/PreprocessingRecord.cpp =================================================================== --- lib/Lex/PreprocessingRecord.cpp +++ lib/Lex/PreprocessingRecord.cpp @@ -40,7 +40,8 @@ PreprocessingRecord::PreprocessingRecord(SourceManager &SM) : SourceMgr(SM), - ExternalSource(nullptr) { + ExternalSource(nullptr), + SkippedRangesAllLoaded(true) { } /// \brief Returns a pair of [Begin, End) iterators of preprocessed entities @@ -318,6 +319,24 @@ return Result; } +unsigned PreprocessingRecord::allocateSkippedRanges(unsigned NumRanges) { + unsigned Result = SkippedRanges.size(); + SkippedRanges.resize(SkippedRanges.size() + NumRanges); + SkippedRangesAllLoaded = false; + return Result; +} + +void PreprocessingRecord::ensureSkippedRangesLoaded() { + if (SkippedRangesAllLoaded || !ExternalSource) + return; + for (unsigned Index = 0; Index != SkippedRanges.size(); ++Index) { + if (SkippedRanges[Index].isInvalid()) + SkippedRanges[Index] = ExternalSource->ReadSkippedRange(Index); + } + SkippedRangesAllLoaded = true; +} + + void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro, MacroDefinitionRecord *Def) { MacroDefinitions[Macro] = Def; @@ -406,6 +425,7 @@ } void PreprocessingRecord::SourceRangeSkipped(SourceRange Range) { + assert(Range.isValid()); SkippedRanges.push_back(Range); } @@ -484,5 +504,6 @@ return BumpAlloc.getTotalMemory() + llvm::capacity_in_bytes(MacroDefinitions) + llvm::capacity_in_bytes(PreprocessedEntities) - + llvm::capacity_in_bytes(LoadedPreprocessedEntities); + + llvm::capacity_in_bytes(LoadedPreprocessedEntities) + + llvm::capacity_in_bytes(SkippedRanges); } Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -3020,6 +3020,24 @@ break; } + + case PPD_SKIPPED_RANGES: { + F.PreprocessedSkippedRangeOffsets = (const PPSkippedRange*)Blob.data(); + assert(Blob.size() % sizeof(PPSkippedRange) == 0); + F.NumPreprocessedSkippedRanges = Blob.size() / sizeof(PPSkippedRange); + + if (!PP.getPreprocessingRecord()) + PP.createPreprocessingRecord(); + if (!PP.getPreprocessingRecord()->getExternalSource()) + PP.getPreprocessingRecord()->SetExternalSource(*this); + F.BasePreprocessedSkippedRangeID = PP.getPreprocessingRecord() + ->allocateSkippedRanges(F.NumPreprocessedSkippedRanges); + + if (F.NumPreprocessedSkippedRanges > 0) + GlobalSkippedRangeMap.insert( + std::make_pair(F.BasePreprocessedSkippedRangeID, &F)); + break; + } case DECL_UPDATE_OFFSETS: { if (Record.size() % 2 != 0) { @@ -4874,6 +4892,20 @@ Mod.FileSortedDecls + Mod.NumFileSortedDecls)); } +SourceRange ASTReader::ReadSkippedRange(unsigned GlobalIndex) { + auto I = GlobalSkippedRangeMap.find(GlobalIndex); + assert(I != GlobalSkippedRangeMap.end() && + "Corrupted global skipped range map"); + ModuleFile *M = I->second; + unsigned LocalIndex = GlobalIndex - M->BasePreprocessedSkippedRangeID; + assert(LocalIndex < M->NumPreprocessedSkippedRanges); + PPSkippedRange RawRange = M->PreprocessedSkippedRangeOffsets[LocalIndex]; + SourceRange Range(TranslateSourceLocation(*M, RawRange.getBegin()), + TranslateSourceLocation(*M, RawRange.getEnd())); + assert(Range.isValid()); + return Range; +} + PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) { PreprocessedEntityID PPID = Index+1; std::pair PPInfo = getModulePreprocessedEntity(Index); Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -953,6 +953,7 @@ RECORD(UNUSED_FILESCOPED_DECLS); RECORD(PPD_ENTITIES_OFFSETS); RECORD(VTABLE_USES); + RECORD(PPD_SKIPPED_RANGES); RECORD(REFERENCED_SELECTOR_POOL); RECORD(TU_UPDATE_LEXICAL); RECORD(SEMA_DECL_REFS); @@ -2408,6 +2409,26 @@ Stream.EmitRecordWithBlob(PPEOffsetAbbrev, Record, bytes(PreprocessedEntityOffsets)); } + + // Write the skipped region table for the preprocessing record. + const std::vector &SkippedRanges = PPRec.getSkippedRanges(); + if (SkippedRanges.size() > 0) { + std::vector SerializedSkippedRanges; + SerializedSkippedRanges.reserve(SkippedRanges.size()); + for (auto const& Range : SkippedRanges) + SerializedSkippedRanges.emplace_back(Range); + + using namespace llvm; + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(PPD_SKIPPED_RANGES)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned PPESkippedRangeAbbrev = Stream.EmitAbbrev(Abbrev); + + Record.clear(); + Record.push_back(PPD_SKIPPED_RANGES); + Stream.EmitRecordWithBlob(PPESkippedRangeAbbrev, Record, + bytes(SerializedSkippedRanges)); + } } unsigned ASTWriter::getLocalOrImportedSubmoduleID(Module *Mod) { Index: lib/Serialization/Module.cpp =================================================================== --- lib/Serialization/Module.cpp +++ lib/Serialization/Module.cpp @@ -31,6 +31,8 @@ LocalNumMacros(0), MacroOffsets(nullptr), BasePreprocessedEntityID(0), PreprocessedEntityOffsets(nullptr), NumPreprocessedEntities(0), + BasePreprocessedSkippedRangeID(0), + PreprocessedSkippedRangeOffsets(nullptr), NumPreprocessedSkippedRanges(0), LocalNumHeaderFileInfos(0), HeaderFileInfoTableData(nullptr), HeaderFileInfoTable(nullptr), LocalNumSubmodules(0), BaseSubmoduleID(0),