Skip to content

Commit 9cc149d

Browse files
jansvoboda11qiongsiwu
authored andcommitted
[clang][modules] Track included files per submodule
(cherry picked from commit 9debc58) Conflicts: clang/include/clang/Lex/Preprocessor.h clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTReaderInternals.h clang/lib/Serialization/ASTWriter.cpp
1 parent 88e9a78 commit 9cc149d

File tree

5 files changed

+145
-27
lines changed

5 files changed

+145
-27
lines changed

clang/include/clang/Basic/Module.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,8 @@ class alignas(8) Module {
498498
/// to import but didn't because they are not direct uses.
499499
llvm::SmallSetVector<const Module *, 2> UndeclaredUses;
500500

501+
llvm::DenseSet<const FileEntry *> Includes;
502+
501503
/// A library or framework to link against when an entity from this
502504
/// module is used.
503505
struct LinkLibrary {

clang/include/clang/Lex/Preprocessor.h

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,8 @@ class Preprocessor {
10211021
/// The set of modules that are visible within the submodule.
10221022
VisibleModuleSet VisibleModules;
10231023

1024+
/// The files that have been included.
1025+
IncludedFilesSet IncludedFiles;
10241026
// FIXME: CounterValue?
10251027
// FIXME: PragmaPushMacroInfo?
10261028
};
@@ -1033,8 +1035,8 @@ class Preprocessor {
10331035
/// in a submodule.
10341036
SubmoduleState *CurSubmoduleState;
10351037

1036-
/// The files that have been included.
1037-
IncludedFilesSet IncludedFiles;
1038+
/// The files that have been included outside of (sub)modules.
1039+
IncludedFilesSet Includes;
10381040

10391041
/// The set of top-level modules that affected preprocessing, but were not
10401042
/// imported.
@@ -1516,19 +1518,41 @@ class Preprocessor {
15161518
/// Mark the file as included.
15171519
/// Returns true if this is the first time the file was included.
15181520
bool markIncluded(FileEntryRef File) {
1521+
bool AlreadyIncluded = alreadyIncluded(File);
15191522
HeaderInfo.getFileInfo(File).IsLocallyIncluded = true;
1520-
return IncludedFiles.insert(File).second;
1523+
CurSubmoduleState->IncludedFiles.insert(File);
1524+
if (!BuildingSubmoduleStack.empty())
1525+
BuildingSubmoduleStack.back().M->Includes.insert(File);
1526+
else if (Module *M = getCurrentModule())
1527+
M->Includes.insert(File);
1528+
else
1529+
Includes.insert(File);
1530+
return !AlreadyIncluded;
15211531
}
15221532

15231533
/// Return true if this header has already been included.
15241534
bool alreadyIncluded(FileEntryRef File) const {
15251535
HeaderInfo.getFileInfo(File);
1526-
return IncludedFiles.count(File);
1536+
if (CurSubmoduleState->IncludedFiles.contains(File))
1537+
return true;
1538+
// TODO: Do this more efficiently.
1539+
for (const auto &[Name, M] : HeaderInfo.getModuleMap().modules())
1540+
if (CurSubmoduleState->VisibleModules.isVisible(M))
1541+
if (M->Includes.contains(File))
1542+
return true;
1543+
return false;
1544+
}
1545+
1546+
void markIncludedOnTopLevel(const FileEntry *File) {
1547+
Includes.insert(File);
1548+
CurSubmoduleState->IncludedFiles.insert(File);
1549+
}
1550+
1551+
void markIncludedInModule(Module *M, const FileEntry *File) {
1552+
M->Includes.insert(File);
15271553
}
15281554

1529-
/// Get the set of included files.
1530-
IncludedFilesSet &getIncludedFiles() { return IncludedFiles; }
1531-
const IncludedFilesSet &getIncludedFiles() const { return IncludedFiles; }
1555+
const IncludedFilesSet &getTopLevelIncludes() const { return Includes; }
15321556

15331557
/// Return the name of the macro defined before \p Loc that has
15341558
/// spelling \p Tokens. If there are multiple macros with same spelling,

clang/lib/Serialization/ASTReader.cpp

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2346,21 +2346,34 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
23462346
HeaderFileInfo HFI;
23472347
unsigned Flags = *d++;
23482348

2349-
OptionalFileEntryRef FE;
2350-
bool Included = (Flags >> 6) & 0x01;
2351-
if (Included)
2352-
if ((FE = getFile(key)))
2353-
// Not using \c Preprocessor::markIncluded(), since that would attempt to
2354-
// deserialize this header file info again.
2355-
Reader.getPreprocessor().getIncludedFiles().insert(*FE);
2356-
23572349
// FIXME: Refactor with mergeHeaderFileInfo in HeaderSearch.cpp.
23582350
HFI.isImport |= (Flags >> 5) & 0x01;
23592351
HFI.isPragmaOnce |= (Flags >> 4) & 0x01;
23602352
HFI.DirInfo = (Flags >> 1) & 0x07;
23612353
HFI.LazyControllingMacro = Reader.getGlobalIdentifierID(
23622354
M, endian::readNext<IdentifierID, llvm::endianness::little>(d));
23632355

2356+
auto FE = getFile(key);
2357+
Preprocessor &PP = Reader.getPreprocessor();
2358+
ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
2359+
2360+
unsigned IncludedCount =
2361+
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
2362+
for (unsigned I = 0; I < IncludedCount; ++I) {
2363+
uint32_t LocalSMID =
2364+
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
2365+
if (!FE)
2366+
continue;
2367+
2368+
if (LocalSMID == 0) {
2369+
PP.markIncludedOnTopLevel(*FE);
2370+
} else {
2371+
SubmoduleID GlobalSMID = Reader.getGlobalSubmoduleID(M, LocalSMID);
2372+
Module *Mod = Reader.getSubmodule(GlobalSMID);
2373+
PP.markIncludedInModule(Mod, *FE);
2374+
}
2375+
}
2376+
23642377
assert((End - d) % 4 == 0 &&
23652378
"Wrong data length in HeaderFileInfo deserialization");
23662379
while (d != End) {
@@ -2373,10 +2386,8 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
23732386
// implicit module import.
23742387
SubmoduleID GlobalSMID = Reader.getGlobalSubmoduleID(M, LocalSMID);
23752388
Module *Mod = Reader.getSubmodule(GlobalSMID);
2376-
ModuleMap &ModMap =
2377-
Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap();
23782389

2379-
if (FE || (FE = getFile(key))) {
2390+
if (FE) {
23802391
// FIXME: NameAsWritten
23812392
Module::Header H = {std::string(key.Filename), "", *FE};
23822393
ModMap.addHeader(Mod, H, HeaderRole, /*Imported=*/true);

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,14 +2094,15 @@ namespace {
20942094
llvm::PointerIntPair<Module *, 2, ModuleMap::ModuleHeaderRole>;
20952095

20962096
struct data_type {
2097-
data_type(const HeaderFileInfo &HFI, bool AlreadyIncluded,
2097+
data_type(const HeaderFileInfo &HFI,
2098+
const std::vector<const Module *> &Includers,
20982099
ArrayRef<ModuleMap::KnownHeader> KnownHeaders,
20992100
UnresolvedModule Unresolved)
2100-
: HFI(HFI), AlreadyIncluded(AlreadyIncluded),
2101-
KnownHeaders(KnownHeaders), Unresolved(Unresolved) {}
2101+
: HFI(HFI), Includers(Includers), KnownHeaders(KnownHeaders),
2102+
Unresolved(Unresolved) {}
21022103

21032104
HeaderFileInfo HFI;
2104-
bool AlreadyIncluded;
2105+
std::vector<const Module *> Includers;
21052106
SmallVector<ModuleMap::KnownHeader, 1> KnownHeaders;
21062107
UnresolvedModule Unresolved;
21072108
};
@@ -2124,6 +2125,12 @@ namespace {
21242125
EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) {
21252126
unsigned KeyLen = key.Filename.size() + 1 + 8 + 8;
21262127
unsigned DataLen = 1 + sizeof(IdentifierID);
2128+
2129+
DataLen += 4;
2130+
for (const Module *M : Data.Includers)
2131+
if (!M || Writer.getLocalOrImportedSubmoduleID(M))
2132+
DataLen += 4;
2133+
21272134
for (auto ModInfo : Data.KnownHeaders)
21282135
if (Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule()))
21292136
DataLen += 4;
@@ -2150,8 +2157,7 @@ namespace {
21502157
endian::Writer LE(Out, llvm::endianness::little);
21512158
uint64_t Start = Out.tell(); (void)Start;
21522159

2153-
unsigned char Flags = (Data.AlreadyIncluded << 6)
2154-
| (Data.HFI.isImport << 5)
2160+
unsigned char Flags = (Data.HFI.isImport << 5)
21552161
| (Writer.isWritingStdCXXNamedModules() ? 0 :
21562162
Data.HFI.isPragmaOnce << 4)
21572163
| (Data.HFI.DirInfo << 1);
@@ -2163,6 +2169,14 @@ namespace {
21632169
LE.write<IdentifierID>(
21642170
Writer.getIdentifierRef(Data.HFI.LazyControllingMacro.getPtr()));
21652171

2172+
LE.write<uint32_t>(Data.Includers.size());
2173+
for (const Module *M : Data.Includers) {
2174+
if (!M)
2175+
LE.write<uint32_t>(0);
2176+
else if (uint32_t ModID = Writer.getLocalOrImportedSubmoduleID(M))
2177+
LE.write<uint32_t>(ModID);
2178+
}
2179+
21662180
auto EmitModule = [&](Module *M, ModuleMap::ModuleHeaderRole Role) {
21672181
if (uint32_t ModID = Writer.getLocalOrImportedSubmoduleID(M)) {
21682182
uint32_t Value = (ModID << 3) | (unsigned)Role;
@@ -2234,7 +2248,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
22342248
HeaderFileInfoTrait::key_type Key = {
22352249
FilenameDup, *U.Size, IncludeTimestamps ? *U.ModTime : 0};
22362250
HeaderFileInfoTrait::data_type Data = {
2237-
Empty, false, {}, {M, ModuleMap::headerKindToRole(U.Kind)}};
2251+
Empty, {}, {}, {M, ModuleMap::headerKindToRole(U.Kind)}};
22382252
// FIXME: Deal with cases where there are multiple unresolved header
22392253
// directives in different submodules for the same header.
22402254
Generator.insert(Key, Data, GeneratorTrait);
@@ -2274,13 +2288,27 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
22742288
SavedStrings.push_back(Filename.data());
22752289
}
22762290

2277-
bool Included = HFI->IsLocallyIncluded || PP->alreadyIncluded(*File);
2291+
std::vector<const Module *> Includers;
2292+
if (WritingModule) {
2293+
llvm::DenseSet<const Module *> Seen;
2294+
std::function<void(const Module *)> Visit = [&](const Module *M) {
2295+
if (!Seen.insert(M).second)
2296+
return;
2297+
if (M->Includes.contains(*File))
2298+
Includers.push_back(M);
2299+
for (const Module *SubM : M->submodules())
2300+
Visit(SubM);
2301+
};
2302+
Visit(WritingModule);
2303+
} else if (PP->getTopLevelIncludes().contains(*File)) {
2304+
Includers.push_back(nullptr);
2305+
}
22782306

22792307
HeaderFileInfoTrait::key_type Key = {
22802308
Filename, File->getSize(), getTimestampForOutput(*File)
22812309
};
22822310
HeaderFileInfoTrait::data_type Data = {
2283-
*HFI, Included, HS.getModuleMap().findResolvedModulesForHeader(*File), {}
2311+
*HFI, Includers, HS.getModuleMap().findResolvedModulesForHeader(*File), {}
22842312
};
22852313
Generator.insert(Key, Data, GeneratorTrait);
22862314
++NumHeaderSearchEntries;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
4+
//--- frameworks/Textual.framework/Headers/Header.h
5+
static int symbol;
6+
7+
//--- frameworks/FW.framework/Modules/module.modulemap
8+
framework module FW {
9+
umbrella header "FW.h"
10+
export *
11+
module * { export * }
12+
}
13+
//--- frameworks/FW.framework/Headers/FW.h
14+
#import <FW/Sub1.h>
15+
#import <FW/Sub2.h>
16+
//--- frameworks/FW.framework/Headers/Sub1.h
17+
//--- frameworks/FW.framework/Headers/Sub2.h
18+
#import <Textual/Header.h>
19+
20+
//--- pch.modulemap
21+
module __PCH {
22+
header "pch.h"
23+
export *
24+
}
25+
//--- pch.h
26+
#import <FW/Sub1.h>
27+
28+
//--- tu.m
29+
#import <Textual/Header.h>
30+
int fn() { return symbol; }
31+
32+
// Compilation using the PCH regularly succeeds. The import of FW/Sub1.h in the
33+
// PCH is treated textually due to -fmodule-name=FW.
34+
//
35+
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fimplicit-module-maps -F %t/frameworks -fmodule-name=FW \
36+
// RUN: -emit-pch -x objective-c %t/pch.h -o %t/pch.h.gch
37+
//
38+
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fimplicit-module-maps -F %t/frameworks -fmodule-name=FW \
39+
// RUN: -include-pch %t/pch.h.gch -fsyntax-only %t/tu.m
40+
41+
// Compilation using the PCH as precompiled module fails. The import of FW/Sub1.h
42+
// in the PCH is translated to an import. Nothing is preventing that now that
43+
// -fmodule-name=FW has been replaced with -fmodule-name=__PCH.
44+
//
45+
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fimplicit-module-maps -F %t/frameworks \
46+
// RUN: -emit-module -fmodule-name=__PCH -x objective-c %t/pch.modulemap -o %t/pch.h.pcm
47+
//
48+
// Loading FW.pcm marks Textual/Header.h as imported (because it is imported in
49+
// FW.Sub2), so the TU does not import it again. It's contents remain invisible,
50+
// though.
51+
//
52+
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fimplicit-module-maps -F %t/frameworks \
53+
// RUN: -include %t/pch.h -fmodule-map-file=%t/pch.modulemap -fsyntax-only %t/tu.m

0 commit comments

Comments
 (0)