Skip to content

Commit 8d2f091

Browse files
authored
[clang] Extract CompilerInstance creation out of compileModuleImpl() (llvm#134887)
This PR extracts the creation of `CompilerInstance` for compiling an implicitly-discovered module out of `compileModuleImpl()` into its own separate function and passes it into `compileModuleImpl()` from the outside. This makes the instance creation logic reusable (useful for my experiments) and also simplifies the API, removing the `PreBuildStep` and `PostBuildStep` hooks from `compileModuleImpl()`.
1 parent 70627af commit 8d2f091

File tree

1 file changed

+104
-89
lines changed

1 file changed

+104
-89
lines changed

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 104 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,29 +1150,16 @@ static Language getLanguageFromOptions(const LangOptions &LangOpts) {
11501150
return LangOpts.CPlusPlus ? Language::CXX : Language::C;
11511151
}
11521152

1153-
/// Compile a module file for the given module, using the options
1154-
/// provided by the importing compiler instance. Returns true if the module
1155-
/// was built without errors.
1156-
static bool
1157-
compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
1158-
StringRef ModuleName, FrontendInputFile Input,
1159-
StringRef OriginalModuleMapFile, StringRef ModuleFileName,
1160-
llvm::function_ref<void(CompilerInstance &)> PreBuildStep =
1161-
[](CompilerInstance &) {},
1162-
llvm::function_ref<void(CompilerInstance &)> PostBuildStep =
1163-
[](CompilerInstance &) {}) {
1164-
llvm::TimeTraceScope TimeScope("Module Compile", ModuleName);
1165-
1166-
// Never compile a module that's already finalized - this would cause the
1167-
// existing module to be freed, causing crashes if it is later referenced
1168-
if (ImportingInstance.getModuleCache().getInMemoryModuleCache().isPCMFinal(
1169-
ModuleFileName)) {
1170-
ImportingInstance.getDiagnostics().Report(
1171-
ImportLoc, diag::err_module_rebuild_finalized)
1172-
<< ModuleName;
1173-
return false;
1174-
}
1175-
1153+
/// Creates a \c CompilerInstance for compiling a module.
1154+
///
1155+
/// This expects a properly initialized \c FrontendInputFile.
1156+
static std::unique_ptr<CompilerInstance>
1157+
createCompilerInstanceForModuleCompileImpl(CompilerInstance &ImportingInstance,
1158+
SourceLocation ImportLoc,
1159+
StringRef ModuleName,
1160+
FrontendInputFile Input,
1161+
StringRef OriginalModuleMapFile,
1162+
StringRef ModuleFileName) {
11761163
// Construct a compiler invocation for creating this module.
11771164
auto Invocation =
11781165
std::make_shared<CompilerInvocation>(ImportingInstance.getInvocation());
@@ -1226,8 +1213,11 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
12261213
// module. Since we're sharing an in-memory module cache,
12271214
// CompilerInstance::CompilerInstance is responsible for finalizing the
12281215
// buffers to prevent use-after-frees.
1229-
CompilerInstance Instance(ImportingInstance.getPCHContainerOperations(),
1230-
&ImportingInstance.getModuleCache());
1216+
auto InstancePtr = std::make_unique<CompilerInstance>(
1217+
ImportingInstance.getPCHContainerOperations(),
1218+
&ImportingInstance.getModuleCache());
1219+
auto &Instance = *InstancePtr;
1220+
12311221
auto &Inv = *Invocation;
12321222
Instance.setInvocation(std::move(Invocation));
12331223

@@ -1267,12 +1257,32 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
12671257
Instance.setModuleDepCollector(ImportingInstance.getModuleDepCollector());
12681258
Inv.getDependencyOutputOpts() = DependencyOutputOptions();
12691259

1260+
return InstancePtr;
1261+
}
1262+
1263+
/// Compile a module file for the given module, using the options
1264+
/// provided by the importing compiler instance. Returns true if the module
1265+
/// was built without errors.
1266+
static bool compileModule(CompilerInstance &ImportingInstance,
1267+
SourceLocation ImportLoc, StringRef ModuleName,
1268+
StringRef ModuleFileName,
1269+
CompilerInstance &Instance) {
1270+
llvm::TimeTraceScope TimeScope("Module Compile", ModuleName);
1271+
1272+
// Never compile a module that's already finalized - this would cause the
1273+
// existing module to be freed, causing crashes if it is later referenced
1274+
if (ImportingInstance.getModuleCache().getInMemoryModuleCache().isPCMFinal(
1275+
ModuleFileName)) {
1276+
ImportingInstance.getDiagnostics().Report(
1277+
ImportLoc, diag::err_module_rebuild_finalized)
1278+
<< ModuleName;
1279+
return false;
1280+
}
1281+
12701282
ImportingInstance.getDiagnostics().Report(ImportLoc,
12711283
diag::remark_module_build)
12721284
<< ModuleName << ModuleFileName;
12731285

1274-
PreBuildStep(Instance);
1275-
12761286
// Execute the action to actually build the module in-place. Use a separate
12771287
// thread so that we get a stack large enough.
12781288
bool Crashed = !llvm::CrashRecoveryContext().RunSafelyOnThread(
@@ -1282,14 +1292,12 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
12821292
},
12831293
DesiredStackSize);
12841294

1285-
PostBuildStep(Instance);
1286-
12871295
ImportingInstance.getDiagnostics().Report(ImportLoc,
12881296
diag::remark_module_build_done)
12891297
<< ModuleName;
12901298

12911299
// Propagate the statistics to the parent FileManager.
1292-
if (!FrontendOpts.ModulesShareFileManager)
1300+
if (!ImportingInstance.getFrontendOpts().ModulesShareFileManager)
12931301
ImportingInstance.getFileManager().AddStats(Instance.getFileManager());
12941302

12951303
if (Crashed) {
@@ -1302,6 +1310,12 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
13021310
Instance.clearOutputFiles(/*EraseFiles=*/true);
13031311
}
13041312

1313+
// We've rebuilt a module. If we're allowed to generate or update the global
1314+
// module index, record that fact in the importing compiler instance.
1315+
if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) {
1316+
ImportingInstance.setBuildGlobalModuleIndex(true);
1317+
}
1318+
13051319
// If \p AllowPCMWithCompilerErrors is set return 'success' even if errors
13061320
// occurred.
13071321
return !Instance.getDiagnostics().hasErrorOccurred() ||
@@ -1321,20 +1335,24 @@ static OptionalFileEntryRef getPublicModuleMap(FileEntryRef File,
13211335
return FileMgr.getOptionalFileRef(PublicFilename);
13221336
}
13231337

1324-
/// Compile a module file for the given module in a separate compiler instance,
1325-
/// using the options provided by the importing compiler instance. Returns true
1326-
/// if the module was built without errors.
1327-
static bool compileModule(CompilerInstance &ImportingInstance,
1328-
SourceLocation ImportLoc, Module *Module,
1329-
StringRef ModuleFileName) {
1338+
/// Creates a \c CompilerInstance for compiling a module.
1339+
///
1340+
/// This takes care of creating appropriate \c FrontendInputFile for
1341+
/// public/private frameworks, inferred modules and such.
1342+
static std::unique_ptr<CompilerInstance>
1343+
createCompilerInstanceForModuleCompile(CompilerInstance &ImportingInstance,
1344+
SourceLocation ImportLoc, Module *Module,
1345+
StringRef ModuleFileName) {
1346+
StringRef ModuleName = Module->getTopLevelModuleName();
1347+
13301348
InputKind IK(getLanguageFromOptions(ImportingInstance.getLangOpts()),
13311349
InputKind::ModuleMap);
13321350

13331351
// Get or create the module map that we'll use to build this module.
1334-
ModuleMap &ModMap
1335-
= ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
1352+
ModuleMap &ModMap =
1353+
ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
13361354
SourceManager &SourceMgr = ImportingInstance.getSourceManager();
1337-
bool Result;
1355+
13381356
if (FileID ModuleMapFID = ModMap.getContainingModuleMapFileID(Module);
13391357
ModuleMapFID.isValid()) {
13401358
// We want to use the top-level module map. If we don't, the compiling
@@ -1368,44 +1386,36 @@ static bool compileModule(CompilerInstance &ImportingInstance,
13681386
bool IsSystem = isSystem(SLoc.getFile().getFileCharacteristic());
13691387

13701388
// Use the module map where this module resides.
1371-
Result = compileModuleImpl(
1372-
ImportingInstance, ImportLoc, Module->getTopLevelModuleName(),
1389+
return createCompilerInstanceForModuleCompileImpl(
1390+
ImportingInstance, ImportLoc, ModuleName,
13731391
FrontendInputFile(ModuleMapFilePath, IK, IsSystem),
13741392
ModMap.getModuleMapFileForUniquing(Module)->getName(), ModuleFileName);
1375-
} else {
1376-
// FIXME: We only need to fake up an input file here as a way of
1377-
// transporting the module's directory to the module map parser. We should
1378-
// be able to do that more directly, and parse from a memory buffer without
1379-
// inventing this file.
1380-
SmallString<128> FakeModuleMapFile(Module->Directory->getName());
1381-
llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map");
1382-
1383-
std::string InferredModuleMapContent;
1384-
llvm::raw_string_ostream OS(InferredModuleMapContent);
1385-
Module->print(OS);
1386-
1387-
Result = compileModuleImpl(
1388-
ImportingInstance, ImportLoc, Module->getTopLevelModuleName(),
1389-
FrontendInputFile(FakeModuleMapFile, IK, +Module->IsSystem),
1390-
ModMap.getModuleMapFileForUniquing(Module)->getName(),
1391-
ModuleFileName,
1392-
[&](CompilerInstance &Instance) {
1393-
std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
1394-
llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
1395-
FileEntryRef ModuleMapFile = Instance.getFileManager().getVirtualFileRef(
1396-
FakeModuleMapFile, InferredModuleMapContent.size(), 0);
1397-
Instance.getSourceManager().overrideFileContents(
1398-
ModuleMapFile, std::move(ModuleMapBuffer));
1399-
});
14001393
}
14011394

1402-
// We've rebuilt a module. If we're allowed to generate or update the global
1403-
// module index, record that fact in the importing compiler instance.
1404-
if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) {
1405-
ImportingInstance.setBuildGlobalModuleIndex(true);
1406-
}
1395+
// FIXME: We only need to fake up an input file here as a way of
1396+
// transporting the module's directory to the module map parser. We should
1397+
// be able to do that more directly, and parse from a memory buffer without
1398+
// inventing this file.
1399+
SmallString<128> FakeModuleMapFile(Module->Directory->getName());
1400+
llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map");
1401+
1402+
std::string InferredModuleMapContent;
1403+
llvm::raw_string_ostream OS(InferredModuleMapContent);
1404+
Module->print(OS);
1405+
1406+
auto Instance = createCompilerInstanceForModuleCompileImpl(
1407+
ImportingInstance, ImportLoc, ModuleName,
1408+
FrontendInputFile(FakeModuleMapFile, IK, +Module->IsSystem),
1409+
ModMap.getModuleMapFileForUniquing(Module)->getName(), ModuleFileName);
1410+
1411+
std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
1412+
llvm::MemoryBuffer::getMemBufferCopy(InferredModuleMapContent);
1413+
FileEntryRef ModuleMapFile = Instance->getFileManager().getVirtualFileRef(
1414+
FakeModuleMapFile, InferredModuleMapContent.size(), 0);
1415+
Instance->getSourceManager().overrideFileContents(ModuleMapFile,
1416+
std::move(ModuleMapBuffer));
14071417

1408-
return Result;
1418+
return Instance;
14091419
}
14101420

14111421
/// Read the AST right after compiling the module.
@@ -1455,8 +1465,12 @@ static bool compileModuleAndReadASTImpl(CompilerInstance &ImportingInstance,
14551465
SourceLocation ModuleNameLoc,
14561466
Module *Module,
14571467
StringRef ModuleFileName) {
1458-
if (!compileModule(ImportingInstance, ModuleNameLoc, Module,
1459-
ModuleFileName)) {
1468+
auto Instance = createCompilerInstanceForModuleCompile(
1469+
ImportingInstance, ModuleNameLoc, Module, ModuleFileName);
1470+
1471+
if (!compileModule(ImportingInstance, ModuleNameLoc,
1472+
Module->getTopLevelModuleName(), ModuleFileName,
1473+
*Instance)) {
14601474
ImportingInstance.getDiagnostics().Report(ModuleNameLoc,
14611475
diag::err_module_not_built)
14621476
<< Module->Name << SourceRange(ImportLoc, ModuleNameLoc);
@@ -2232,25 +2246,26 @@ void CompilerInstance::createModuleFromSource(SourceLocation ImportLoc,
22322246

22332247
std::string NullTerminatedSource(Source.str());
22342248

2235-
auto PreBuildStep = [&](CompilerInstance &Other) {
2236-
// Create a virtual file containing our desired source.
2237-
// FIXME: We shouldn't need to do this.
2238-
FileEntryRef ModuleMapFile = Other.getFileManager().getVirtualFileRef(
2239-
ModuleMapFileName, NullTerminatedSource.size(), 0);
2240-
Other.getSourceManager().overrideFileContents(
2241-
ModuleMapFile, llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource));
2249+
auto Other = createCompilerInstanceForModuleCompileImpl(
2250+
*this, ImportLoc, ModuleName, Input, StringRef(), ModuleFileName);
22422251

2243-
Other.BuiltModules = std::move(BuiltModules);
2244-
Other.DeleteBuiltModules = false;
2245-
};
2252+
// Create a virtual file containing our desired source.
2253+
// FIXME: We shouldn't need to do this.
2254+
FileEntryRef ModuleMapFile = Other->getFileManager().getVirtualFileRef(
2255+
ModuleMapFileName, NullTerminatedSource.size(), 0);
2256+
Other->getSourceManager().overrideFileContents(
2257+
ModuleMapFile, llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource));
22462258

2247-
auto PostBuildStep = [this](CompilerInstance &Other) {
2248-
BuiltModules = std::move(Other.BuiltModules);
2249-
};
2259+
Other->BuiltModules = std::move(BuiltModules);
2260+
Other->DeleteBuiltModules = false;
22502261

22512262
// Build the module, inheriting any modules that we've built locally.
2252-
if (compileModuleImpl(*this, ImportLoc, ModuleName, Input, StringRef(),
2253-
ModuleFileName, PreBuildStep, PostBuildStep)) {
2263+
bool Success =
2264+
compileModule(*this, ImportLoc, ModuleName, ModuleFileName, *Other);
2265+
2266+
BuiltModules = std::move(Other->BuiltModules);
2267+
2268+
if (Success) {
22542269
BuiltModules[std::string(ModuleName)] = std::string(ModuleFileName);
22552270
llvm::sys::RemoveFileOnSignal(ModuleFileName);
22562271
}

0 commit comments

Comments
 (0)