Skip to content

Commit 961f337

Browse files
committed
[clang][modules] Account for non-affecting inputs in ASTWriter
In D106876, we stopped serializing module map files that didn't affect compilation of the current module. However, since each `SourceLocation` is simply an offset into `SourceManager`'s global buffer of concatenated input files in, these need to be adjusted during serialization. Otherwise, they can incorrectly point after the buffer or into subsequent input file. This patch starts adjusting `SourceLocation`s, `FileID`s and other `SourceManager` offsets in `ASTWriter`. Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D136624 (cherry picked from commit 6924a49)
1 parent 35c8c90 commit 961f337

File tree

3 files changed

+160
-89
lines changed

3 files changed

+160
-89
lines changed

clang/include/clang/Serialization/ASTWriter.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,21 @@ class ASTWriter : public ASTDeserializationListener,
444444
std::vector<std::unique_ptr<ModuleFileExtensionWriter>>
445445
ModuleFileExtensionWriters;
446446

447-
/// User ModuleMaps skipped when writing control block.
448-
std::set<const FileEntry *> SkippedModuleMaps;
447+
/// Mapping from a source location entry to whether it is affecting or not.
448+
llvm::BitVector IsSLocAffecting;
449+
450+
/// Mapping from \c FileID to an index into the FileID adjustment table.
451+
std::vector<FileID> NonAffectingFileIDs;
452+
std::vector<unsigned> NonAffectingFileIDAdjustments;
453+
454+
/// Mapping from an offset to an index into the offset adjustment table.
455+
std::vector<SourceRange> NonAffectingRanges;
456+
std::vector<SourceLocation::UIntTy> NonAffectingOffsetAdjustments;
457+
458+
/// Collects input files that didn't affect compilation of the current module,
459+
/// and initializes data structures necessary for leaving those files out
460+
/// during \c SourceManager serialization.
461+
void collectNonAffectingInputFiles();
449462

450463
/// Returns an adjusted \c FileID, accounting for any non-affecting input
451464
/// files.
@@ -462,6 +475,9 @@ class ASTWriter : public ASTDeserializationListener,
462475
/// Returns an adjusted \c SourceLocation offset, accounting for any
463476
/// non-affecting input files.
464477
SourceLocation::UIntTy getAdjustedOffset(SourceLocation::UIntTy Offset) const;
478+
/// Returns an adjustment for offset into SourceManager, accounting for any
479+
/// non-affecting input files.
480+
SourceLocation::UIntTy getAdjustment(SourceLocation::UIntTy Offset) const;
465481

466482
/// Retrieve or create a submodule ID for this module.
467483
unsigned getSubmoduleID(Module *Mod);
@@ -481,8 +497,7 @@ class ASTWriter : public ASTDeserializationListener,
481497
static std::pair<ASTFileSignature, ASTFileSignature>
482498
createSignature(StringRef AllBytes, StringRef ASTBlockBytes);
483499

484-
void WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOptions &HSOpts,
485-
std::set<const FileEntry *> &AffectingModuleMaps);
500+
void WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOptions &HSOpts);
486501
void WriteSourceManagerBlock(SourceManager &SourceMgr,
487502
const Preprocessor &PP);
488503
void writeIncludedFiles(raw_ostream &Out, const Preprocessor &PP);

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 121 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ static TypeCode getTypeCodeForTypeClass(Type::TypeClass id) {
160160

161161
namespace {
162162

163-
std::set<const FileEntry *> GetAllModuleMaps(const HeaderSearch &HS,
164-
Module *RootModule) {
163+
std::set<const FileEntry *> GetAffectingModuleMaps(const HeaderSearch &HS,
164+
Module *RootModule) {
165165
std::set<const FileEntry *> ModuleMaps{};
166166
std::set<const Module *> ProcessedModules;
167167
SmallVector<const Module *> ModulesToProcess{RootModule};
@@ -1495,15 +1495,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
14951495
AddFileID(SM.getMainFileID(), Record);
14961496
Stream.EmitRecord(ORIGINAL_FILE_ID, Record);
14971497

1498-
std::set<const FileEntry *> AffectingModuleMaps;
1499-
if (WritingModule) {
1500-
AffectingModuleMaps =
1501-
GetAllModuleMaps(PP.getHeaderSearchInfo(), WritingModule);
1502-
}
1503-
15041498
WriteInputFiles(Context.SourceMgr,
1505-
PP.getHeaderSearchInfo().getHeaderSearchOpts(),
1506-
AffectingModuleMaps);
1499+
PP.getHeaderSearchInfo().getHeaderSearchOpts());
15071500
Stream.ExitBlock();
15081501
}
15091502

@@ -1521,9 +1514,8 @@ struct InputFileEntry {
15211514

15221515
} // namespace
15231516

1524-
void ASTWriter::WriteInputFiles(
1525-
SourceManager &SourceMgr, HeaderSearchOptions &HSOpts,
1526-
std::set<const FileEntry *> &AffectingModuleMaps) {
1517+
void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
1518+
HeaderSearchOptions &HSOpts) {
15271519
using namespace llvm;
15281520

15291521
Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
@@ -1563,15 +1555,9 @@ void ASTWriter::WriteInputFiles(
15631555
if (!Cache->OrigEntry)
15641556
continue;
15651557

1566-
if (isModuleMap(File.getFileCharacteristic()) &&
1567-
!isSystem(File.getFileCharacteristic()) &&
1568-
!AffectingModuleMaps.empty() &&
1569-
AffectingModuleMaps.find(Cache->OrigEntry) ==
1570-
AffectingModuleMaps.end()) {
1571-
SkippedModuleMaps.insert(Cache->OrigEntry);
1572-
// Do not emit modulemaps that do not affect current module.
1558+
// Do not emit input files that do not affect current module.
1559+
if (!IsSLocAffecting[I])
15731560
continue;
1574-
}
15751561

15761562
InputFileEntry Entry;
15771563
Entry.File = Cache->OrigEntry;
@@ -2082,12 +2068,9 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
20822068
if (SLoc->isFile()) {
20832069
const SrcMgr::FileInfo &File = SLoc->getFile();
20842070
const SrcMgr::ContentCache *Content = &File.getContentCache();
2085-
if (Content->OrigEntry && !SkippedModuleMaps.empty() &&
2086-
SkippedModuleMaps.find(Content->OrigEntry) !=
2087-
SkippedModuleMaps.end()) {
2088-
// Do not emit files that were not listed as inputs.
2071+
// Do not emit files that were not listed as inputs.
2072+
if (!IsSLocAffecting[I])
20892073
continue;
2090-
}
20912074
SLocEntryOffsets.push_back(Offset);
20922075
// Starting offset of this entry within this module, so skip the dummy.
20932076
Record.push_back(getAdjustedOffset(SLoc->getOffset()) - 2);
@@ -4531,6 +4514,69 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
45314514
}
45324515
}
45334516

4517+
void ASTWriter::collectNonAffectingInputFiles() {
4518+
SourceManager &SrcMgr = PP->getSourceManager();
4519+
unsigned N = SrcMgr.local_sloc_entry_size();
4520+
4521+
IsSLocAffecting.resize(N, true);
4522+
4523+
if (!WritingModule)
4524+
return;
4525+
4526+
auto AffectingModuleMaps =
4527+
GetAffectingModuleMaps(PP->getHeaderSearchInfo(), WritingModule);
4528+
4529+
unsigned FileIDAdjustment = 0;
4530+
unsigned OffsetAdjustment = 0;
4531+
4532+
NonAffectingFileIDAdjustments.reserve(N);
4533+
NonAffectingOffsetAdjustments.reserve(N);
4534+
4535+
NonAffectingFileIDAdjustments.push_back(FileIDAdjustment);
4536+
NonAffectingOffsetAdjustments.push_back(OffsetAdjustment);
4537+
4538+
for (unsigned I = 1; I != N; ++I) {
4539+
const SrcMgr::SLocEntry *SLoc = &SrcMgr.getLocalSLocEntry(I);
4540+
FileID FID = FileID::get(I);
4541+
assert(&SrcMgr.getSLocEntry(FID) == SLoc);
4542+
4543+
if (!SLoc->isFile())
4544+
continue;
4545+
const SrcMgr::FileInfo &File = SLoc->getFile();
4546+
const SrcMgr::ContentCache *Cache = &File.getContentCache();
4547+
if (!Cache->OrigEntry)
4548+
continue;
4549+
4550+
if (!isModuleMap(File.getFileCharacteristic()) ||
4551+
isSystem(File.getFileCharacteristic()) || AffectingModuleMaps.empty() ||
4552+
AffectingModuleMaps.find(Cache->OrigEntry) != AffectingModuleMaps.end())
4553+
continue;
4554+
4555+
IsSLocAffecting[I] = false;
4556+
4557+
FileIDAdjustment += 1;
4558+
// Even empty files take up one element in the offset table.
4559+
OffsetAdjustment += SrcMgr.getFileIDSize(FID) + 1;
4560+
4561+
// If the previous file was non-affecting as well, just extend its entry
4562+
// with our information.
4563+
if (!NonAffectingFileIDs.empty() &&
4564+
NonAffectingFileIDs.back().ID == FID.ID - 1) {
4565+
NonAffectingFileIDs.back() = FID;
4566+
NonAffectingRanges.back().setEnd(SrcMgr.getLocForEndOfFile(FID));
4567+
NonAffectingFileIDAdjustments.back() = FileIDAdjustment;
4568+
NonAffectingOffsetAdjustments.back() = OffsetAdjustment;
4569+
continue;
4570+
}
4571+
4572+
NonAffectingFileIDs.push_back(FID);
4573+
NonAffectingRanges.emplace_back(SrcMgr.getLocForStartOfFile(FID),
4574+
SrcMgr.getLocForEndOfFile(FID));
4575+
NonAffectingFileIDAdjustments.push_back(FileIDAdjustment);
4576+
NonAffectingOffsetAdjustments.push_back(OffsetAdjustment);
4577+
}
4578+
}
4579+
45344580
ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
45354581
Module *WritingModule) {
45364582
using namespace llvm;
@@ -4544,6 +4590,8 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
45444590
ASTContext &Context = SemaRef.Context;
45454591
Preprocessor &PP = SemaRef.PP;
45464592

4593+
collectNonAffectingInputFiles();
4594+
45474595
// Set up predefined declaration IDs.
45484596
auto RegisterPredefDecl = [&] (Decl *D, PredefinedDeclIDs ID) {
45494597
if (D) {
@@ -5233,32 +5281,65 @@ void ASTWriter::AddAlignPackInfo(const Sema::AlignPackInfo &Info,
52335281
}
52345282

52355283
FileID ASTWriter::getAdjustedFileID(FileID FID) const {
5236-
// TODO: Actually adjust this.
5237-
return FID;
5284+
if (FID.isInvalid() || PP->getSourceManager().isLoadedFileID(FID) ||
5285+
NonAffectingFileIDs.empty())
5286+
return FID;
5287+
auto It = llvm::lower_bound(NonAffectingFileIDs, FID);
5288+
unsigned Idx = std::distance(NonAffectingFileIDs.begin(), It);
5289+
unsigned Offset = NonAffectingFileIDAdjustments[Idx];
5290+
return FileID::get(FID.getOpaqueValue() - Offset);
52385291
}
52395292

52405293
unsigned ASTWriter::getAdjustedNumCreatedFIDs(FileID FID) const {
5241-
// TODO: Actually adjust this.
5242-
return PP->getSourceManager()
5243-
.getLocalSLocEntry(FID.ID)
5244-
.getFile()
5245-
.NumCreatedFIDs;
5294+
unsigned NumCreatedFIDs = PP->getSourceManager()
5295+
.getLocalSLocEntry(FID.ID)
5296+
.getFile()
5297+
.NumCreatedFIDs;
5298+
5299+
unsigned AdjustedNumCreatedFIDs = 0;
5300+
for (unsigned I = FID.ID, N = I + NumCreatedFIDs; I != N; ++I)
5301+
if (IsSLocAffecting[I])
5302+
++AdjustedNumCreatedFIDs;
5303+
return AdjustedNumCreatedFIDs;
52465304
}
52475305

52485306
SourceLocation ASTWriter::getAdjustedLocation(SourceLocation Loc) const {
5249-
// TODO: Actually adjust this.
5250-
return Loc;
5307+
if (Loc.isInvalid())
5308+
return Loc;
5309+
return Loc.getLocWithOffset(-getAdjustment(Loc.getOffset()));
52515310
}
52525311

52535312
SourceRange ASTWriter::getAdjustedRange(SourceRange Range) const {
5254-
// TODO: Actually adjust this.
5255-
return Range;
5313+
return SourceRange(getAdjustedLocation(Range.getBegin()),
5314+
getAdjustedLocation(Range.getEnd()));
52565315
}
52575316

52585317
SourceLocation::UIntTy
52595318
ASTWriter::getAdjustedOffset(SourceLocation::UIntTy Offset) const {
5260-
// TODO: Actually adjust this.
5261-
return Offset;
5319+
return Offset - getAdjustment(Offset);
5320+
}
5321+
5322+
SourceLocation::UIntTy
5323+
ASTWriter::getAdjustment(SourceLocation::UIntTy Offset) const {
5324+
if (NonAffectingRanges.empty())
5325+
return 0;
5326+
5327+
if (PP->getSourceManager().isLoadedOffset(Offset))
5328+
return 0;
5329+
5330+
if (Offset > NonAffectingRanges.back().getEnd().getOffset())
5331+
return NonAffectingOffsetAdjustments.back();
5332+
5333+
if (Offset < NonAffectingRanges.front().getBegin().getOffset())
5334+
return 0;
5335+
5336+
auto Contains = [](const SourceRange &Range, SourceLocation::UIntTy Offset) {
5337+
return Range.getEnd().getOffset() < Offset;
5338+
};
5339+
5340+
auto It = llvm::lower_bound(NonAffectingRanges, Offset, Contains);
5341+
unsigned Idx = std::distance(NonAffectingRanges.begin(), It);
5342+
return NonAffectingOffsetAdjustments[Idx];
52625343
}
52635344

52645345
void ASTWriter::AddFileID(FileID FID, RecordDataImpl &Record) {
@@ -5521,6 +5602,7 @@ void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
55215602
if (FID.isInvalid())
55225603
return;
55235604
assert(SM.getSLocEntry(FID).isFile());
5605+
assert(IsSLocAffecting[FID.ID]);
55245606

55255607
std::unique_ptr<DeclIDInFileInfo> &Info = FileDeclIDs[FID];
55265608
if (!Info)
Lines changed: 20 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,32 @@
11
// RUN: rm -rf %t && mkdir %t
22
// RUN: split-file %s %t
33

4-
//--- a.modulemap
4+
//--- a/module.modulemap
55
module a {}
66

7-
//--- b.modulemap
7+
//--- b/module.modulemap
88
module b {}
99

10-
//--- test-simple.m
11-
// expected-no-diagnostics
12-
@import a;
13-
14-
// Build without b.modulemap:
15-
//
16-
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -fdisable-module-hash \
17-
// RUN: -fmodule-map-file=%t/a.modulemap %t/test-simple.m -verify
18-
// RUN: mv %t/cache %t/cache-without-b
19-
20-
// Build with b.modulemap:
21-
//
22-
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -fdisable-module-hash \
23-
// RUN: -fmodule-map-file=%t/a.modulemap -fmodule-map-file=%t/b.modulemap %t/test-simple.m -verify
24-
// RUN: mv %t/cache %t/cache-with-b
25-
26-
// Neither PCM file considers 'b.modulemap' an input:
27-
//
28-
// RUN: %clang_cc1 -module-file-info %t/cache-without-b/a.pcm | FileCheck %s --check-prefix=CHECK-B
29-
// RUN: %clang_cc1 -module-file-info %t/cache-with-b/a.pcm | FileCheck %s --check-prefix=CHECK-B
30-
// CHECK-B-NOT: Input file: {{.*}}b.modulemap
31-
32-
//--- c.modulemap
33-
module c [no_undeclared_includes] { header "c.h" }
10+
//--- c/module.modulemap
11+
module c {}
3412

35-
//--- c.h
36-
#if __has_include("d.h") // This should use 'd.modulemap' in order to determine that 'd.h'
37-
// doesn't exist for 'c' because of its '[no_undeclared_includes]'.
38-
#endif
39-
40-
//--- d.modulemap
41-
module d { header "d.h" }
42-
43-
//--- d.h
44-
// empty
13+
//--- module.modulemap
14+
module m { header "m.h" }
15+
//--- m.h
16+
@import c;
4517

46-
//--- test-no-undeclared-includes.m
18+
//--- test-simple.m
4719
// expected-no-diagnostics
48-
@import c;
20+
@import m;
21+
22+
// Build modules with the non-affecting "a/module.modulemap".
23+
// RUN: %clang_cc1 -I %t/a -I %t/b -I %t/c -I %t -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -fdisable-module-hash %t/test-simple.m -verify
24+
// RUN: mv %t/cache %t/cache-with
4925

50-
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fdisable-module-hash \
51-
// RUN: -fmodule-map-file=%t/c.modulemap -fmodule-map-file=%t/d.modulemap \
52-
// RUN: %t/test-no-undeclared-includes.m -verify
26+
// Build modules without the non-affecting "a/module.modulemap".
27+
// RUN: rm -rf %t/a/module.modulemap
28+
// RUN: %clang_cc1 -I %t/a -I %t/b -I %t/c -I %t -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -fdisable-module-hash %t/test-simple.m -verify
29+
// RUN: mv %t/cache %t/cache-without
5330

54-
// The PCM file considers 'd.modulemap' an input because it affects the compilation,
55-
// although it doesn't describe the built module or its imports.
56-
//
57-
// RUN: %clang_cc1 -module-file-info %t/cache/c.pcm | FileCheck %s --check-prefix=CHECK-D
58-
// CHECK-D: Input file: {{.*}}d.modulemap
31+
// Check that the PCM files are bit-for-bit identical.
32+
// RUN: diff %t/cache-with/m.pcm %t/cache-without/m.pcm

0 commit comments

Comments
 (0)