Skip to content

Commit 6924a49

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
1 parent a13122c commit 6924a49

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 *> &AffectingClangModuleMaps);
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
@@ -161,8 +161,8 @@ static TypeCode getTypeCodeForTypeClass(Type::TypeClass id) {
161161

162162
namespace {
163163

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

1480-
std::set<const FileEntry *> AffectingClangModuleMaps;
1481-
if (WritingModule) {
1482-
AffectingClangModuleMaps =
1483-
GetAllModuleMaps(PP.getHeaderSearchInfo(), WritingModule);
1484-
}
1485-
14861480
WriteInputFiles(Context.SourceMgr,
1487-
PP.getHeaderSearchInfo().getHeaderSearchOpts(),
1488-
AffectingClangModuleMaps);
1481+
PP.getHeaderSearchInfo().getHeaderSearchOpts());
14891482
Stream.ExitBlock();
14901483
}
14911484

@@ -1503,9 +1496,8 @@ struct InputFileEntry {
15031496

15041497
} // namespace
15051498

1506-
void ASTWriter::WriteInputFiles(
1507-
SourceManager &SourceMgr, HeaderSearchOptions &HSOpts,
1508-
std::set<const FileEntry *> &AffectingClangModuleMaps) {
1499+
void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
1500+
HeaderSearchOptions &HSOpts) {
15091501
using namespace llvm;
15101502

15111503
Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
@@ -1545,15 +1537,9 @@ void ASTWriter::WriteInputFiles(
15451537
if (!Cache->OrigEntry)
15461538
continue;
15471539

1548-
if (isModuleMap(File.getFileCharacteristic()) &&
1549-
!isSystem(File.getFileCharacteristic()) &&
1550-
!AffectingClangModuleMaps.empty() &&
1551-
AffectingClangModuleMaps.find(Cache->OrigEntry) ==
1552-
AffectingClangModuleMaps.end()) {
1553-
SkippedModuleMaps.insert(Cache->OrigEntry);
1554-
// Do not emit modulemaps that do not affect current module.
1540+
// Do not emit input files that do not affect current module.
1541+
if (!IsSLocAffecting[I])
15551542
continue;
1556-
}
15571543

15581544
InputFileEntry Entry;
15591545
Entry.File = Cache->OrigEntry;
@@ -2064,12 +2050,9 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
20642050
if (SLoc->isFile()) {
20652051
const SrcMgr::FileInfo &File = SLoc->getFile();
20662052
const SrcMgr::ContentCache *Content = &File.getContentCache();
2067-
if (Content->OrigEntry && !SkippedModuleMaps.empty() &&
2068-
SkippedModuleMaps.find(Content->OrigEntry) !=
2069-
SkippedModuleMaps.end()) {
2070-
// Do not emit files that were not listed as inputs.
2053+
// Do not emit files that were not listed as inputs.
2054+
if (!IsSLocAffecting[I])
20712055
continue;
2072-
}
20732056
SLocEntryOffsets.push_back(Offset);
20742057
// Starting offset of this entry within this module, so skip the dummy.
20752058
Record.push_back(getAdjustedOffset(SLoc->getOffset()) - 2);
@@ -4527,6 +4510,69 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
45274510
}
45284511
}
45294512

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

4589+
collectNonAffectingInputFiles();
4590+
45434591
// Set up predefined declaration IDs.
45444592
auto RegisterPredefDecl = [&] (Decl *D, PredefinedDeclIDs ID) {
45454593
if (D) {
@@ -5229,32 +5277,65 @@ void ASTWriter::AddAlignPackInfo(const Sema::AlignPackInfo &Info,
52295277
}
52305278

52315279
FileID ASTWriter::getAdjustedFileID(FileID FID) const {
5232-
// TODO: Actually adjust this.
5233-
return FID;
5280+
if (FID.isInvalid() || PP->getSourceManager().isLoadedFileID(FID) ||
5281+
NonAffectingFileIDs.empty())
5282+
return FID;
5283+
auto It = llvm::lower_bound(NonAffectingFileIDs, FID);
5284+
unsigned Idx = std::distance(NonAffectingFileIDs.begin(), It);
5285+
unsigned Offset = NonAffectingFileIDAdjustments[Idx];
5286+
return FileID::get(FID.getOpaqueValue() - Offset);
52345287
}
52355288

52365289
unsigned ASTWriter::getAdjustedNumCreatedFIDs(FileID FID) const {
5237-
// TODO: Actually adjust this.
5238-
return PP->getSourceManager()
5239-
.getLocalSLocEntry(FID.ID)
5240-
.getFile()
5241-
.NumCreatedFIDs;
5290+
unsigned NumCreatedFIDs = PP->getSourceManager()
5291+
.getLocalSLocEntry(FID.ID)
5292+
.getFile()
5293+
.NumCreatedFIDs;
5294+
5295+
unsigned AdjustedNumCreatedFIDs = 0;
5296+
for (unsigned I = FID.ID, N = I + NumCreatedFIDs; I != N; ++I)
5297+
if (IsSLocAffecting[I])
5298+
++AdjustedNumCreatedFIDs;
5299+
return AdjustedNumCreatedFIDs;
52425300
}
52435301

52445302
SourceLocation ASTWriter::getAdjustedLocation(SourceLocation Loc) const {
5245-
// TODO: Actually adjust this.
5246-
return Loc;
5303+
if (Loc.isInvalid())
5304+
return Loc;
5305+
return Loc.getLocWithOffset(-getAdjustment(Loc.getOffset()));
52475306
}
52485307

52495308
SourceRange ASTWriter::getAdjustedRange(SourceRange Range) const {
5250-
// TODO: Actually adjust this.
5251-
return Range;
5309+
return SourceRange(getAdjustedLocation(Range.getBegin()),
5310+
getAdjustedLocation(Range.getEnd()));
52525311
}
52535312

52545313
SourceLocation::UIntTy
52555314
ASTWriter::getAdjustedOffset(SourceLocation::UIntTy Offset) const {
5256-
// TODO: Actually adjust this.
5257-
return Offset;
5315+
return Offset - getAdjustment(Offset);
5316+
}
5317+
5318+
SourceLocation::UIntTy
5319+
ASTWriter::getAdjustment(SourceLocation::UIntTy Offset) const {
5320+
if (NonAffectingRanges.empty())
5321+
return 0;
5322+
5323+
if (PP->getSourceManager().isLoadedOffset(Offset))
5324+
return 0;
5325+
5326+
if (Offset > NonAffectingRanges.back().getEnd().getOffset())
5327+
return NonAffectingOffsetAdjustments.back();
5328+
5329+
if (Offset < NonAffectingRanges.front().getBegin().getOffset())
5330+
return 0;
5331+
5332+
auto Contains = [](const SourceRange &Range, SourceLocation::UIntTy Offset) {
5333+
return Range.getEnd().getOffset() < Offset;
5334+
};
5335+
5336+
auto It = llvm::lower_bound(NonAffectingRanges, Offset, Contains);
5337+
unsigned Idx = std::distance(NonAffectingRanges.begin(), It);
5338+
return NonAffectingOffsetAdjustments[Idx];
52585339
}
52595340

52605341
void ASTWriter::AddFileID(FileID FID, RecordDataImpl &Record) {
@@ -5517,6 +5598,7 @@ void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
55175598
if (FID.isInvalid())
55185599
return;
55195600
assert(SM.getSLocEntry(FID).isFile());
5601+
assert(IsSLocAffecting[FID.ID]);
55205602

55215603
std::unique_ptr<DeclIDInFileInfo> &Info = FileDeclIDs[FID];
55225604
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)