This fixes, for example, libclang's clang_getSkippedRanges returning zero ranges after reparsing a translation unit.
Fixes PR34971.
Differential D20124
[PCH] Serialize skipped preprocessor ranges cameron314 on May 10 2016, 12:32 PM. Authored by
Details This fixes, for example, libclang's clang_getSkippedRanges returning zero ranges after reparsing a translation unit. Fixes PR34971.
Diff Detail
Event TimelineComment Actions The patch has aged a bit since upload, so does it still apply? And, can you add a testcase please? Comment Actions Here are my observations:
Apart from that the patch applies cleanly and all tests pass (check-clang). However, some new warnings are emitted during building: /home/nik/dev/llvm/trunk/source/tools/clang/include/clang/Lex/PreprocessingRecord.h: In constructor ‘clang::PreprocessingRecord::PreprocessingRecord(clang::SourceManager&)’: /home/nik/dev/llvm/trunk/source/tools/clang/include/clang/Lex/PreprocessingRecord.h:339:40: warning: ‘clang::PreprocessingRecord::ExternalSource’ will be initialized after [-Wreorder] ExternalPreprocessingRecordSource *ExternalSource; ^~~~~~~~~~~~~~ /home/nik/dev/llvm/trunk/source/tools/clang/include/clang/Lex/PreprocessingRecord.h:312:10: warning: ‘bool clang::PreprocessingRecord::SkippedRangesAllLoaded’ [-Wreorder] bool SkippedRangesAllLoaded; ^~~~~~~~~~~~~~~~~~~~~~ /home/nik/dev/llvm/trunk/source/tools/clang/lib/Lex/PreprocessingRecord.cpp:36:1: warning: when initialized here [-Wreorder]
Comment Actions
Comment Actions Alright, with my patch the c-index-test *does* correctly serialize and restore the skipped ranges; the problem is that it searches for only ranges matching the target file. When there's a preamble, it's seen as a different file than the main file, even though they're really one and the same in this case. So my test, which uses clang_getAllSkippedRanges, passes, but c-index-test, which uses clang_getSkippedRanges, fails. I'll update my test to use both. I'm trying to figure out how to fix this. Comment Actions Well, it seems like preamble PCH source location translation is fundamentally broken. The entry file has a single, positive file ID. The preamble PCH is treated as an imported module, so it has a negative file ID for the part that overlaps the preamble of the entry file. That means locations in the preamble part of the entry file can have two different file IDs depending on how they are arrived at. I really don't know how to fix this. Any ideas? Comment Actions Why do we store raw source locations in PPSkippedRange? Would storing SourceLocation and using ASTWriter::AddSourceLocation and ASTReader:: ReadSourceLocation do the trick? Comment Actions I followed the pattern used to store PPEntityOffsets; it allows the entire array to be written in one chunk. Using AddSourceLocation/ReadSourceLocation boils down to the same thing -- AddSourceLocation simply rotates by one bit, and ReadSourceLocation simply rotates back and calls ASTReader::TranslateSourceLocation (which I call from AST::ReadSkippedRange explicitly instead). So the source location translation path is exactly the same either way. The thing is, the PCH created for the preamble is imported as a module, meaning the part of the source code that overlaps the preamble of the entry file has a different file ID from the entry file itself. Is there any way to force source locations in the preamble to map to the actual entry file instead of the module's version of the entry file? Comment Actions Maybe something like this works: --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -8090,6 +8090,7 @@ CXSourceRangeList *clang_getSkippedRanges(CXTranslationUnit TU, CXFile file) { SourceManager &sm = Ctx.getSourceManager(); FileEntry *fileEntry = static_cast<FileEntry *>(file); FileID wantedFileID = sm.translateFile(fileEntry); + bool isMainFile = wantedFileID == sm.getMainFileID(); const std::vector<SourceRange> &SkippedRanges = ppRec->getSkippedRanges(); std::vector<SourceRange> wantedRanges; @@ -8097,6 +8098,8 @@ CXSourceRangeList *clang_getSkippedRanges(CXTranslationUnit TU, CXFile file) { i != ei; ++i) { if (sm.getFileID(i->getBegin()) == wantedFileID || sm.getFileID(i->getEnd()) == wantedFileID) wantedRanges.push_back(*i); + else if (isMainFile && (astUnit->isInPreambleFileID(i->getBegin()) || astUnit->isInPreambleFileID(i->getEnd()))) + wantedRanges.push_back(*i); } skipped->count = wantedRanges.size(); Comment Actions Brilliant, didn't know isInPreambleFileID existed. All my tests pass for me now with that change, thanks :-) Comment Actions Here's the final patch that fixes clang_getSkippedRegions with regions in the preamble (as well as serializing the skipped regions in the PCH file). Comment Actions Works fine for me, thanks! Test from the bug report is fixed by this one. You should probably add "Fixes PR34971." to the summary. @erikjv @ilya-biryukov - please review as you know the details here :) |
Remove excess new line.