jansvoboda11 updated this revision to Diff 388253.
jansvoboda11 added a comment.
Add missed newline.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D112915/new/
https://reviews.llvm.org/D112915
Files:
clang/include/clang/Lex/ExternalPreprocessorSource.h
clang/include/clang/Lex/Preprocessor.h
clang/include/clang/Serialization/ASTBitCodes.h
clang/include/clang/Serialization/ASTReader.h
clang/include/clang/Serialization/ASTWriter.h
clang/include/clang/Serialization/ModuleFile.h
clang/lib/Basic/Module.cpp
clang/lib/Lex/PPLexerChange.cpp
clang/lib/Lex/Preprocessor.cpp
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/test/Modules/import-submodule-visibility.c
Index: clang/test/Modules/import-submodule-visibility.c
===================================================================
--- /dev/null
+++ clang/test/Modules/import-submodule-visibility.c
@@ -0,0 +1,99 @@
+// This test checks that imports of headers that appeared in a different submodule than
+// what is imported by the current TU don't affect the compilation.
+
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+
+//--- A.framework/Headers/A.h
+#include "Textual.h"
+//--- A.framework/Modules/module.modulemap
+framework module A { header "A.h" }
+
+//--- B.framework/Headers/B1.h
+#include "Textual.h"
+//--- B.framework/Headers/B2.h
+//--- B.framework/Modules/module.modulemap
+framework module B {
+ module B1 { header "B1.h" }
+ module B2 { header "B2.h" }
+}
+
+//--- C/C.h
+#include "Textual.h"
+//--- C/module.modulemap
+module C { header "C.h" }
+
+//--- D/D1.h
+#include "Textual.h"
+//--- D/D2.h
+//--- D/module.modulemap
+module D {
+ module D1 { header "D1.h" }
+ module D2 { header "D2.h" }
+}
+
+//--- E/E1.h
+#include "E2.h"
+//--- E/E2.h
+#include "Textual.h"
+//--- E/module.modulemap
+module E {
+ module E1 { header "E1.h" }
+ module E2 { header "E2.h" }
+}
+
+//--- Textual.h
+#define MACRO_TEXTUAL 1
+
+//--- test.c
+
+#ifdef A
+//
+#endif
+
+#ifdef B
+#import <B/B2.h>
+#endif
+
+#ifdef C
+//
+#endif
+
+#ifdef D
+#import "D/D2.h"
+#endif
+
+#ifdef E
+#import "E/E1.h"
+#endif
+
+#import "Textual.h"
+
+static int x = MACRO_TEXTUAL;
+
+// Specifying the PCM file on the command line (without actually importing "A") should not
+// prevent "Textual.h" to be included in the TU.
+//
+// RUN: %clang_cc1 -fmodules -I %t -emit-module %t/A.framework/Modules/module.modulemap -fmodule-name=A -o %t/A.pcm
+// RUN: %clang_cc1 -fmodules -I %t -fsyntax-only %t/test.c -DA -fmodule-file=%t/A.pcm
+
+// Specifying the PCM file on the command line and importing "B2" in the source does not
+// prevent "Textual.h" to be included in the TU.
+//
+// RUN: %clang_cc1 -fmodules -I %t -emit-module %t/B.framework/Modules/module.modulemap -fmodule-name=B -o %t/B.pcm
+// RUN: %clang_cc1 -fmodules -I %t -fsyntax-only %t/test.c -DB -iframework %t -fmodule-file=%t/B.pcm
+
+// Module-only version of the test with framework A.
+//
+// RUN: %clang_cc1 -fmodules -I %t -emit-module %t/C/module.modulemap -fmodule-name=C -o %t/C.pcm
+// RUN: %clang_cc1 -fmodules -I %t -fsyntax-only %t/test.c -DC -fmodule-file=%t/C.pcm
+
+// Module-only version of the test with framework B.
+//
+// RUN: %clang_cc1 -fmodules -I %t -emit-module %t/D/module.modulemap -fmodule-name=D -o %t/D.pcm
+// RUN: %clang_cc1 -fmodules -I %t -fsyntax-only %t/test.c -DD -fmodule-file=%t/D.pcm
+
+// Transitively imported, but not exported.
+//
+// RUN: %clang_cc1 -fmodules -I %t -emit-module %t/E/module.modulemap -fmodule-name=E -o %t/E.pcm
+// RUN: %clang_cc1 -fmodules -I %t -fsyntax-only %t/test.c -DE -fmodule-file=%t/E.pcm
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -2245,11 +2245,12 @@
return false;
}
-void ASTWriter::writeIncludedFiles(raw_ostream &Out, const Preprocessor &PP) {
+void ASTWriter::writeIncludedFiles(
+ raw_ostream &Out, const Preprocessor::IncludedFilesSet &Files) {
using namespace llvm::support;
std::vector<bool> IncludedInputFiles;
- for (const auto &File : PP.getIncludedFiles()) {
+ for (const auto &File : Files) {
auto InputFileIt = InputFileIDs.find(File);
if (InputFileIt == InputFileIDs.end())
continue;
@@ -2473,15 +2474,15 @@
Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record, bytes(MacroOffsets));
}
- {
- auto Abbrev = std::make_shared<BitCodeAbbrev>();
+ if (const auto *Includes = PP.getNullSubmoduleIncludes()) {
+ Abbrev = std::make_shared<BitCodeAbbrev>();
Abbrev->Add(BitCodeAbbrevOp(PP_INCLUDED_FILES));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned IncludedFilesAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
SmallString<2048> Buffer;
raw_svector_ostream Out(Buffer);
- writeIncludedFiles(Out, PP);
+ writeIncludedFiles(Out, *Includes);
RecordData::value_type Record[] = {PP_INCLUDED_FILES};
Stream.EmitRecordWithBlob(IncludedFilesAbbrev, Record, Buffer.data(),
Buffer.size());
@@ -2741,6 +2742,11 @@
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name
unsigned ExportAsAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
+ Abbrev = std::make_shared<BitCodeAbbrev>();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_INCLUDED_FILES));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned IncludedFilesAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
+
// Write the submodule metadata block.
RecordData::value_type Record[] = {
getNumberOfModules(WritingModule),
@@ -2882,6 +2888,15 @@
Stream.EmitRecordWithBlob(ExportAsAbbrev, Record, Mod->ExportAsModule);
}
+ if (const auto *Includes = PP->getLocalSubmoduleIncludes(Mod)) {
+ SmallString<2048> Buffer;
+ raw_svector_ostream Out(Buffer);
+ writeIncludedFiles(Out, *Includes);
+ RecordData::value_type Record[] = {SUBMODULE_INCLUDED_FILES};
+ Stream.EmitRecordWithBlob(IncludedFilesAbbrev, Record, Buffer.data(),
+ Buffer.size());
+ }
+
// Queue up the submodules of this module.
for (auto *M : Mod->submodules())
Q.push(M);
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -2959,10 +2959,12 @@
}
}
-void ASTReader::readIncludedFiles(ModuleFile &F, StringRef Blob,
- Preprocessor &PP) {
+Preprocessor::IncludedFilesSet ASTReader::readIncludedFiles(ModuleFile &F,
+ StringRef Blob) {
using namespace llvm::support;
+ Preprocessor::IncludedFilesSet Result;
+
const unsigned char *D = (const unsigned char *)Blob.data();
unsigned FileCount = endian::readNext<uint32_t, little, unaligned>(D);
@@ -2971,8 +2973,10 @@
if (*D & (1 << Bit)) {
auto InputFileInfo = readInputFileInfo(F, I);
if (auto File = PP.getFileManager().getFile(InputFileInfo.Filename))
- PP.getIncludedFiles().insert(*File);
+ Result.insert(*File);
}
+
+ return Result;
}
llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
@@ -3714,7 +3718,10 @@
}
case PP_INCLUDED_FILES:
- readIncludedFiles(F, Blob, PP);
+ if (F.isModule())
+ break;
+ for (const auto &File : readIncludedFiles(F, Blob))
+ PP.markTransitivelyIncluded(File);
break;
case LATE_PARSED_TEMPLATE:
@@ -5727,6 +5734,10 @@
CurrentModule->ExportAsModule = Blob.str();
ModMap.addLinkAsDependency(CurrentModule);
break;
+
+ case SUBMODULE_INCLUDED_FILES:
+ F.SubmoduleIncludedFiles.insert(
+ {CurrentModule->getFullModuleName(), Blob});
}
}
}
@@ -8612,6 +8623,26 @@
return LocalID + I->second;
}
+const Preprocessor::IncludedFilesSet *ASTReader::getIncludedFiles(Module *M) {
+ ModuleFile *F = getModuleManager().lookup(M->getASTFile());
+ if (!F)
+ return nullptr;
+
+ auto ResultIt =
+ SubmoduleIncludedFiles.insert({M, Preprocessor::IncludedFilesSet{}});
+ auto &Result = ResultIt.first->second;
+ if (!ResultIt.second)
+ return &Result;
+
+ auto It = F->SubmoduleIncludedFiles.find(M->getFullModuleName());
+ if (It == F->SubmoduleIncludedFiles.end())
+ return nullptr;
+ auto &Record = It->second;
+
+ Result = readIncludedFiles(*F, Record);
+ return &Result;
+}
+
Module *ASTReader::getSubmodule(SubmoduleID GlobalID) {
if (GlobalID < NUM_PREDEF_SUBMODULE_IDS) {
assert(GlobalID == 0 && "Unhandled global submodule ID");
Index: clang/lib/Lex/Preprocessor.cpp
===================================================================
--- clang/lib/Lex/Preprocessor.cpp
+++ clang/lib/Lex/Preprocessor.cpp
@@ -1307,7 +1307,14 @@
void Preprocessor::makeModuleVisible(Module *M, SourceLocation Loc) {
CurSubmoduleState->VisibleModules.setVisible(
- M, Loc, [](Module *) {},
+ M, Loc, [&](Module *M) {
+ const auto *Includes = getLocalSubmoduleIncludes(M);
+ if (!Includes)
+ Includes = getExternalSubmoduleIncludes(M);
+ if (Includes)
+ for (const auto &E : *Includes)
+ markTransitivelyIncluded(E);
+ },
[&](ArrayRef<Module *> Path, Module *Conflict, StringRef Message) {
// FIXME: Include the path in the diagnostic.
// FIXME: Include the import location for the conflicting module.
@@ -1468,3 +1475,26 @@
Record = new PreprocessingRecord(getSourceManager());
addPPCallbacks(std::unique_ptr<PPCallbacks>(Record));
}
+
+bool Preprocessor::markIncluded(const FileEntry *File) {
+ Module *CurrentSubmodule = getCurrentModule();
+ if (!BuildingSubmoduleStack.empty())
+ CurrentSubmodule = BuildingSubmoduleStack.back().M;
+ IncludedFilesPerSubmodule[CurrentSubmodule].insert(File);
+
+ return IncludedFiles.insert(File).second;
+}
+
+void Preprocessor::markTransitivelyIncluded(const FileEntry *File) {
+ IncludedFiles.insert(File);
+}
+
+/// Return true if this header has already been included.
+bool Preprocessor::alreadyIncluded(const FileEntry *File) const {
+ return IncludedFiles.count(File);
+}
+
+const Preprocessor::IncludedFilesSet *
+Preprocessor::getExternalSubmoduleIncludes(Module *M) const {
+ return ExternalSource ? ExternalSource->getIncludedFiles(M) : nullptr;
+}
Index: clang/lib/Lex/PPLexerChange.cpp
===================================================================
--- clang/lib/Lex/PPLexerChange.cpp
+++ clang/lib/Lex/PPLexerChange.cpp
@@ -688,6 +688,10 @@
void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc,
bool ForPragma) {
+ // Ensure that even if this submodule doesn't include anything, it's present
+ // in the map.
+ IncludedFilesPerSubmodule[M];
+
if (!getLangOpts().ModulesLocalVisibility) {
// Just track that we entered this submodule.
BuildingSubmoduleStack.push_back(
Index: clang/lib/Basic/Module.cpp
===================================================================
--- clang/lib/Basic/Module.cpp
+++ clang/lib/Basic/Module.cpp
@@ -650,7 +650,7 @@
return;
ImportLocs[ID] = Loc;
- Vis(M);
+ Vis(V.M);
// Make any exported modules visible.
SmallVector<Module *, 16> Exports;
Index: clang/include/clang/Serialization/ModuleFile.h
===================================================================
--- clang/include/clang/Serialization/ModuleFile.h
+++ clang/include/clang/Serialization/ModuleFile.h
@@ -111,7 +111,8 @@
class ModuleFile {
public:
ModuleFile(ModuleKind Kind, unsigned Generation)
- : Kind(Kind), Generation(Generation) {}
+ : Kind(Kind), Generation(Generation),
+ SubmoduleIncludedFiles(SubmoduleIncludedFilesAlloc) {}
~ModuleFile();
// === General information ===
@@ -394,6 +395,12 @@
/// Remapping table for submodule IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> SubmoduleRemap;
+ /// Allocator for the serialized set of included files.
+ llvm::BumpPtrAllocator SubmoduleIncludedFilesAlloc;
+ /// Mapping between (sub)module names and the serialized set of included
+ /// files. Initialized by the allocator above.
+ llvm::StringMap<StringRef, llvm::BumpPtrAllocator> SubmoduleIncludedFiles;
+
// === Selectors ===
/// The number of selectors new to this file.
Index: clang/include/clang/Serialization/ASTWriter.h
===================================================================
--- clang/include/clang/Serialization/ASTWriter.h
+++ clang/include/clang/Serialization/ASTWriter.h
@@ -19,6 +19,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaConsumer.h"
#include "clang/Serialization/ASTBitCodes.h"
@@ -481,7 +482,8 @@
std::set<const FileEntry *> &AffectingModuleMaps);
void WriteSourceManagerBlock(SourceManager &SourceMgr,
const Preprocessor &PP);
- void writeIncludedFiles(raw_ostream &Out, const Preprocessor &PP);
+ void writeIncludedFiles(raw_ostream &Out,
+ const Preprocessor::IncludedFilesSet &Files);
void WritePreprocessor(const Preprocessor &PP, bool IsModule);
void WriteHeaderSearch(const HeaderSearch &HS);
void WritePreprocessorDetail(PreprocessingRecord &PPRec,
Index: clang/include/clang/Serialization/ASTReader.h
===================================================================
--- clang/include/clang/Serialization/ASTReader.h
+++ clang/include/clang/Serialization/ASTReader.h
@@ -927,6 +927,10 @@
/// A list of modules that were imported by precompiled headers or
/// any other non-module AST file.
SmallVector<ImportedSubmodule, 2> ImportedModules;
+
+ /// Mapping between a (sub)module and deserialized set of included files.
+ llvm::DenseMap<Module *, Preprocessor::IncludedFilesSet>
+ SubmoduleIncludedFiles;
//@}
/// The system include root to be used when loading the
@@ -1331,7 +1335,8 @@
llvm::Error ReadSourceManagerBlock(ModuleFile &F);
llvm::BitstreamCursor &SLocCursorForID(int ID);
SourceLocation getImportLocation(ModuleFile *F);
- void readIncludedFiles(ModuleFile &F, StringRef Blob, Preprocessor &PP);
+ Preprocessor::IncludedFilesSet readIncludedFiles(ModuleFile &F,
+ StringRef Blob);
ASTReadResult ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
const ModuleFile *ImportedBy,
unsigned ClientLoadCapabilities);
@@ -2100,6 +2105,9 @@
///
Module *getSubmodule(serialization::SubmoduleID GlobalID);
+ /// Return the set of files directly included in the given (sub)module.
+ const Preprocessor::IncludedFilesSet *getIncludedFiles(Module *M) override;
+
/// Retrieve the module that corresponds to the given module ID.
///
/// Note: overrides method in ExternalASTSource
Index: clang/include/clang/Serialization/ASTBitCodes.h
===================================================================
--- clang/include/clang/Serialization/ASTBitCodes.h
+++ clang/include/clang/Serialization/ASTBitCodes.h
@@ -828,6 +828,9 @@
/// Specifies the name of the module that will eventually
/// re-export the entities in this module.
SUBMODULE_EXPORT_AS = 17,
+
+ /// Specifies files included in this module.
+ SUBMODULE_INCLUDED_FILES = 18,
};
/// Record types used within a comments block.
Index: clang/include/clang/Lex/Preprocessor.h
===================================================================
--- clang/include/clang/Lex/Preprocessor.h
+++ clang/include/clang/Lex/Preprocessor.h
@@ -767,7 +767,12 @@
/// in a submodule.
SubmoduleState *CurSubmoduleState;
- /// The files that have been included.
+ /// The set files that have been included in each submodule.
+ /// Files included outside of any module (e.g. in PCH) have nullptr key.
+ llvm::DenseMap<Module *, IncludedFilesSet> IncludedFilesPerSubmodule;
+
+ /// The global set of files that have been included.
+ // TODO: Move this into SubmoduleState.
IncludedFilesSet IncludedFiles;
/// The set of known macros exported from modules.
@@ -925,6 +930,9 @@
void updateOutOfDateIdentifier(IdentifierInfo &II) const;
+ /// Get the external include information for the given (sub)module.
+ const IncludedFilesSet *getExternalSubmoduleIncludes(Module *M) const;
+
public:
Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
DiagnosticsEngine &diags, LangOptions &opts, SourceManager &SM,
@@ -1231,18 +1239,25 @@
/// Mark the file as included.
/// Returns true if this is the first time the file was included.
- bool markIncluded(const FileEntry *File) {
- return IncludedFiles.insert(File).second;
- }
+ bool markIncluded(const FileEntry *File);
+
+ /// Mark the file as transitively included.
+ void markTransitivelyIncluded(const FileEntry *File);
/// Return true if this header has already been included.
- bool alreadyIncluded(const FileEntry *File) const {
- return IncludedFiles.count(File);
+ bool alreadyIncluded(const FileEntry *File) const;
+
+ /// Get the set of files included outside of any (sub)module.
+ const IncludedFilesSet *getNullSubmoduleIncludes() const {
+ auto It = IncludedFilesPerSubmodule.find(nullptr);
+ return It == IncludedFilesPerSubmodule.end() ? nullptr : &It->second;
}
- /// Get the set of included files.
- IncludedFilesSet &getIncludedFiles() { return IncludedFiles; }
- const IncludedFilesSet &getIncludedFiles() const { return IncludedFiles; }
+ /// Get the set of files included in the given (sub)module.
+ const IncludedFilesSet *getLocalSubmoduleIncludes(Module *M) const {
+ auto It = IncludedFilesPerSubmodule.find(M);
+ return It == IncludedFilesPerSubmodule.end() ? nullptr : &It->second;
+ }
/// Return the name of the macro defined before \p Loc that has
/// spelling \p Tokens. If there are multiple macros with same spelling,
Index: clang/include/clang/Lex/ExternalPreprocessorSource.h
===================================================================
--- clang/include/clang/Lex/ExternalPreprocessorSource.h
+++ clang/include/clang/Lex/ExternalPreprocessorSource.h
@@ -13,6 +13,8 @@
#ifndef LLVM_CLANG_LEX_EXTERNALPREPROCESSORSOURCE_H
#define LLVM_CLANG_LEX_EXTERNALPREPROCESSORSOURCE_H
+#include "clang/Lex/Preprocessor.h"
+
namespace clang {
class IdentifierInfo;
@@ -40,6 +42,9 @@
/// Map a module ID to a module.
virtual Module *getModule(unsigned ModuleID) = 0;
+
+ /// Return the set of files directly included in the given (sub)module.
+ virtual const Preprocessor::IncludedFilesSet *getIncludedFiles(Module *M) = 0;
};
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits