[cxx-interop] Remove symbolic import mode

Importing C++ class templates in symbolic mode has proven to be problematic in interaction with other compiler features, and it isn't used widely. This change removes the feature.

rdar://150528798
This commit is contained in:
Egor Zhdan
2025-05-02 18:43:09 +01:00
parent 9de2419153
commit b51cfa5c76
20 changed files with 14 additions and 857 deletions

View File

@@ -426,199 +426,6 @@ emitDataForSwiftSerializedModule(ModuleDecl *module,
const PathRemapper &pathRemapper,
SourceFile *initialFile);
static void
appendSymbolicInterfaceToIndexStorePath(SmallVectorImpl<char> &resultingPath) {
llvm::sys::path::append(resultingPath, "interfaces");
}
static llvm::Error initSymbolicInterfaceStorePath(StringRef storePath) {
SmallString<128> subPath = storePath;
appendSymbolicInterfaceToIndexStorePath(subPath);
std::error_code ec = llvm::sys::fs::create_directories(subPath);
if (ec)
return llvm::errorCodeToError(ec);
return llvm::Error::success();
}
static void appendSymbolicInterfaceClangModuleFilename(
StringRef filePath, SmallVectorImpl<char> &resultingPath) {
llvm::sys::path::append(resultingPath, llvm::sys::path::filename(filePath));
StringRef extension = ".symbolicswiftinterface";
resultingPath.append(extension.begin(), extension.end());
}
// FIXME (Alex): Share code with IndexUnitWriter in LLVM after refactoring it.
static llvm::Expected<bool>
isFileUpToDateForOutputFile(StringRef filePath, StringRef timeCompareFilePath) {
auto makeError = [](StringRef path, std::error_code ec) -> llvm::Error {
std::string error;
llvm::raw_string_ostream(error)
<< "could not access path '" << path << "': " << ec.message();
return llvm::createStringError(ec, error.c_str());
};
llvm::sys::fs::file_status unitStat;
if (std::error_code ec = llvm::sys::fs::status(filePath, unitStat)) {
if (ec != std::errc::no_such_file_or_directory && ec != llvm::errc::delete_pending)
return makeError(filePath, ec);
return false;
}
if (timeCompareFilePath.empty())
return true;
llvm::sys::fs::file_status compareStat;
if (std::error_code ec =
llvm::sys::fs::status(timeCompareFilePath, compareStat)) {
if (ec != std::errc::no_such_file_or_directory && ec != llvm::errc::delete_pending)
return makeError(timeCompareFilePath, ec);
return true;
}
// Return true (unit is up-to-date) if the file to compare is older than the
// unit file.
return compareStat.getLastModificationTime() <=
unitStat.getLastModificationTime();
}
/// Emit the symbolic swift interface file for an imported Clang module into the
/// index store directory.
///
/// The swift interface file is emitted only when it doesn't exist yet, or when
/// the PCM for the Clang module has been updated.
///
/// System modules without the 'cplusplus' requirement are not emitted.
static void emitSymbolicInterfaceForClangModule(
ClangModuleUnit *clangModUnit, ModuleDecl *M,
const clang::Module *clangModule, StringRef indexStorePath,
const clang::CompilerInstance &clangCI, DiagnosticEngine &diags) {
if (!M->getASTContext().LangOpts.EnableCXXInterop)
return;
// Skip system modules without an explicit 'cplusplus' requirement.
bool isSystem = clangModUnit->isSystemModule();
if (isSystem && !importer::requiresCPlusPlus(clangModule))
return;
// Make sure the `interfaces` directory is created.
if (auto err = initSymbolicInterfaceStorePath(indexStorePath)) {
llvm::handleAllErrors(std::move(err), [&](const llvm::ECError &ec) {
diags.diagnose(SourceLoc(), diag::error_create_symbolic_interfaces_dir,
ec.convertToErrorCode().message());
});
return;
}
auto moduleRef = clangModule->getASTFile();
if (!moduleRef)
return;
// Determine the output name for the symbolic interface file.
clang::serialization::ModuleFile *ModFile =
clangCI.getASTReader()->getModuleManager().lookup(*moduleRef);
assert(ModFile && "no module file loaded for module ?");
SmallString<128> interfaceOutputPath = indexStorePath;
appendSymbolicInterfaceToIndexStorePath(interfaceOutputPath);
appendSymbolicInterfaceClangModuleFilename(ModFile->FileName,
interfaceOutputPath);
// Check if the symbolic interface file is already up to date.
std::string error;
auto upToDate =
isFileUpToDateForOutputFile(interfaceOutputPath, ModFile->FileName);
if (!upToDate) {
llvm::handleAllErrors(
upToDate.takeError(), [&](const llvm::StringError &ec) {
diags.diagnose(SourceLoc(),
diag::error_symbolic_interfaces_failed_status_check,
ec.getMessage());
});
return;
}
if (M->getASTContext().LangOpts.EnableIndexingSystemModuleRemarks) {
diags.diagnose(SourceLoc(), diag::remark_emitting_symbolic_interface_module,
interfaceOutputPath, *upToDate);
}
if (*upToDate)
return;
// Output the interface to a temporary file first.
SmallString<128> tempOutputPath = interfaceOutputPath;
tempOutputPath += "-%%%%%%%%";
int tempFD;
if (llvm::sys::fs::createUniqueFile(tempOutputPath.str(), tempFD,
tempOutputPath)) {
llvm::raw_string_ostream errOS(error);
errOS << "failed to create temporary file: " << tempOutputPath;
diags.diagnose(SourceLoc(), diag::error_write_symbolic_interface,
errOS.str());
return;
}
llvm::raw_fd_ostream os(tempFD, /*shouldClose=*/true);
StreamPrinter printer(os);
ide::printSymbolicSwiftClangModuleInterface(M, printer, clangModule);
os.close();
if (os.has_error()) {
llvm::raw_string_ostream errOS(error);
errOS << "failed to write '" << tempOutputPath
<< "': " << os.error().message();
diags.diagnose(SourceLoc(), diag::error_write_symbolic_interface,
errOS.str());
os.clear_error();
llvm::sys::fs::remove(tempOutputPath);
return;
}
// Move the resulting output to the destination symbolic interface file.
std::error_code ec = llvm::sys::fs::rename(
/*from=*/tempOutputPath, /*to=*/interfaceOutputPath);
if (ec) {
llvm::raw_string_ostream errOS(error);
errOS << "failed to rename '" << tempOutputPath << "' to '"
<< interfaceOutputPath << "': " << ec.message();
diags.diagnose(SourceLoc(), diag::error_write_symbolic_interface,
errOS.str());
llvm::sys::fs::remove(tempOutputPath);
return;
}
}
static void emitTransitiveClangSymbolicInterfacesForSwiftModuleImports(
ArrayRef<ImportedModule> imports, StringRef indexStorePath,
const clang::CompilerInstance &clangCI, DiagnosticEngine &diags) {
auto &fileMgr = clangCI.getFileManager();
for (auto &import : imports) {
ModuleDecl *mod = import.importedModule;
if (mod->isOnoneSupportModule())
continue; // ignore the Onone support library.
if (mod->isSwiftShimsModule())
continue;
for (auto *FU : mod->getFiles()) {
switch (FU->getKind()) {
default:
break;
case FileUnitKind::SerializedAST:
case FileUnitKind::DWARFModule:
case FileUnitKind::ClangModule: {
auto *LFU = cast<LoadedFile>(FU);
if (auto F = fileMgr.getFile(LFU->getFilename())) {
if (FU->getKind() == FileUnitKind::ClangModule) {
auto clangModUnit = cast<ClangModuleUnit>(LFU);
if (auto clangMod = clangModUnit->getUnderlyingClangModule()) {
// Emit the symbolic interface file in addition to index data.
emitSymbolicInterfaceForClangModule(
clangModUnit, mod, clangMod, indexStorePath, clangCI, diags);
}
}
// FIXME: We should keep recursing here into other Swift modules.
}
}
}
}
}
}
static void addModuleDependencies(ArrayRef<ImportedModule> imports,
StringRef indexStorePath,
bool indexClangModules,
@@ -688,11 +495,6 @@ static void addModuleDependencies(ArrayRef<ImportedModule> imports,
if (shouldIndexModule)
clang::index::emitIndexDataForModuleFile(clangMod,
clangCI, unitWriter);
// Emit the symbolic interface file in addition to index data.
if (indexClangModules)
emitSymbolicInterfaceForClangModule(clangModUnit, mod, clangMod,
indexStorePath, clangCI,
diags);
}
} else {
// Serialized AST file.
@@ -727,9 +529,6 @@ static void addModuleDependencies(ArrayRef<ImportedModule> imports,
SmallVector<ImportedModule, 4> imports;
mod->getImportedModules(imports,
ModuleDecl::ImportFilterKind::Exported);
if (indexClangModules)
emitTransitiveClangSymbolicInterfacesForSwiftModuleImports(
imports, indexStorePath, clangCI, diags);
}
}
clang::index::writer::OpaqueModule opaqMod =