Skip to content

Commit b74d766

Browse files
authored
Merge pull request #61303 from artemcm/DirectCC1ExplicitPCMBuild
[ClangImporter] Add a mode to create the underlying Clang 'CompilerInvocation' directly from 'cc1' arguments, bypassing the Clang driver, only in the 'emit-pcm' compilation flow.
2 parents fa3c951 + bfa6375 commit b74d766

File tree

6 files changed

+75
-24
lines changed

6 files changed

+75
-24
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ WARNING(warning_cannot_multithread_batch_mode,none,
106106
"ignoring -num-threads argument; cannot multithread batch mode", ())
107107
ERROR(error_cannot_explicit_interface_build_in_mode,none,
108108
"'-explicit-interface-module-build' only supported when building a module from interface ('-compile-module-from-interface')'", ())
109+
ERROR(error_cannot_direct_cc1_pcm_build_in_mode,none,
110+
"'-direct-clang-cc1-module-build' only supported when building a PCM ('-emit-pcm')'", ())
109111
ERROR(error_unsupported_option_argument,none,
110112
"unsupported argument '%1' to option '%0'", (StringRef, StringRef))
111113
ERROR(error_immediate_mode_missing_stdlib,none,

include/swift/Basic/LangOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,11 @@ namespace swift {
808808
/// contains the full option set.
809809
bool ExtraArgsOnly = false;
810810

811+
/// When building a PCM, rely on the Swift frontend's command-line -Xcc flags
812+
/// to build the Clang module via Clang frontend directly,
813+
/// and completly bypass the Clang driver.
814+
bool DirectClangCC1ModuleBuild = false;
815+
811816
/// Return a hash code of any components from these options that should
812817
/// contribute to a Swift Bridging PCH hash.
813818
llvm::hash_code getPCHHashComponents() const {

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,10 @@ def explicit_interface_module_build :
889889
Flag<["-"], "explicit-interface-module-build">,
890890
HelpText<"Use the specified command-line to build the module from interface, instead of flags specified in the interface">;
891891

892+
def direct_clang_cc1_module_build :
893+
Flag<["-"], "direct-clang-cc1-module-build">,
894+
HelpText<"Use the specified -Xcc options to build a PCM by using Clang frontend directly, bypassing the Clang driver">;
895+
892896
def build_module_from_parseable_interface :
893897
Flag<["-"], "build-module-from-parseable-interface">,
894898
Alias<compile_module_from_interface>,

lib/ClangImporter/ClangImporter.cpp

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -993,27 +993,51 @@ std::unique_ptr<clang::CompilerInvocation> ClangImporter::createClangInvocation(
993993
invocationArgs.reserve(invocationArgStrs.size());
994994
for (auto &argStr : invocationArgStrs)
995995
invocationArgs.push_back(argStr.c_str());
996-
// Set up a temporary diagnostic client to report errors from parsing the
997-
// command line, which may be important for Swift clients if, for example,
998-
// they're using -Xcc options. Unfortunately this diagnostic engine has to
999-
// use the default options because the /actual/ options haven't been parsed
1000-
// yet.
1001-
//
1002-
// The long-term client for Clang diagnostics is set up below, after the
1003-
// clang::CompilerInstance is created.
1004-
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> tempDiagOpts{
1005-
new clang::DiagnosticOptions
1006-
};
1007996

1008-
ClangDiagnosticConsumer tempDiagClient{importer->Impl, *tempDiagOpts,
1009-
importerOpts.DumpClangDiagnostics};
1010-
llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> tempClangDiags =
1011-
clang::CompilerInstance::createDiagnostics(tempDiagOpts.get(),
1012-
&tempDiagClient,
1013-
/*owned*/false);
997+
llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> clangDiags;
998+
std::unique_ptr<clang::CompilerInvocation> CI;
999+
if (importerOpts.DirectClangCC1ModuleBuild) {
1000+
// In this mode, we bypass createInvocationFromCommandLine, which goes
1001+
// through the Clang driver, and use strictly cc1 arguments to instantiate a
1002+
// clang Instance directly, assuming that the set of '-Xcc <X>' frontend flags is
1003+
// fully sufficient to do so.
1004+
1005+
// Because we are bypassing the Clang driver, we must populate
1006+
// the diagnostic options here explicitly.
1007+
std::unique_ptr<clang::DiagnosticOptions> clangDiagOpts =
1008+
clang::CreateAndPopulateDiagOpts(invocationArgs);
1009+
ClangDiagnosticConsumer diagClient{importer->Impl, *clangDiagOpts,
1010+
importerOpts.DumpClangDiagnostics};
1011+
clangDiags = clang::CompilerInstance::createDiagnostics(
1012+
clangDiagOpts.release(), &diagClient,
1013+
/*owned*/ false);
1014+
1015+
// Finally, use the CC1 command-line and the diagnostic engine
1016+
// to instantiate our Invocation.
1017+
CI = std::make_unique<clang::CompilerInvocation>();
1018+
if (!clang::CompilerInvocation::CreateFromArgs(
1019+
*CI, invocationArgs, *clangDiags, invocationArgs[0]))
1020+
return nullptr;
1021+
} else {
1022+
// Set up a temporary diagnostic client to report errors from parsing the
1023+
// command line, which may be important for Swift clients if, for example,
1024+
// they're using -Xcc options. Unfortunately this diagnostic engine has to
1025+
// use the default options because the /actual/ options haven't been parsed
1026+
// yet.
1027+
//
1028+
// The long-term client for Clang diagnostics is set up below, after the
1029+
// clang::CompilerInstance is created.
1030+
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> tempDiagOpts{
1031+
new clang::DiagnosticOptions};
10141032

1015-
auto CI = clang::createInvocationFromCommandLine(
1016-
invocationArgs, tempClangDiags, VFS, false, CC1Args);
1033+
ClangDiagnosticConsumer tempDiagClient{importer->Impl, *tempDiagOpts,
1034+
importerOpts.DumpClangDiagnostics};
1035+
clangDiags = clang::CompilerInstance::createDiagnostics(tempDiagOpts.get(),
1036+
&tempDiagClient,
1037+
/*owned*/ false);
1038+
CI = clang::createInvocationFromCommandLine(invocationArgs, clangDiags, VFS,
1039+
false, CC1Args);
1040+
}
10171041

10181042
if (!CI) {
10191043
return CI;
@@ -1030,8 +1054,9 @@ std::unique_ptr<clang::CompilerInvocation> ClangImporter::createClangInvocation(
10301054
// rdar://77516546 is tracking that the clang importer should be more
10311055
// resilient and provide a module even if there were building it.
10321056
auto TempVFS = clang::createVFSFromCompilerInvocation(
1033-
*CI, *tempClangDiags,
1057+
*CI, *clangDiags,
10341058
VFS ? VFS : importer->Impl.SwiftContext.SourceMgr.getFileSystem());
1059+
10351060
std::vector<std::string> FilteredModuleMapFiles;
10361061
for (auto ModuleMapFile : CI->getFrontendOpts().ModuleMapFiles) {
10371062
if (TempVFS->exists(ModuleMapFile)) {
@@ -1058,13 +1083,11 @@ ClangImporter::create(ASTContext &ctx,
10581083
if (importerOpts.DumpClangDiagnostics) {
10591084
llvm::errs() << "'";
10601085
llvm::interleave(
1061-
invocationArgStrs, [](StringRef arg) { llvm::errs() << arg; },
1062-
[] { llvm::errs() << "' '"; });
1086+
invocationArgStrs, [](StringRef arg) { llvm::errs() << arg; },
1087+
[] { llvm::errs() << "' '"; });
10631088
llvm::errs() << "'\n";
10641089
}
10651090

1066-
1067-
10681091
if (isPCHFilenameExtension(importerOpts.BridgingHeader)) {
10691092
importer->Impl.setSinglePCHImport(importerOpts.BridgingHeader);
10701093
importer->Impl.IsReadingBridgingPCH = true;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,7 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts,
12731273
}
12741274

12751275
Opts.ExtraArgsOnly |= Args.hasArg(OPT_extra_clang_options_only);
1276+
Opts.DirectClangCC1ModuleBuild |= Args.hasArg(OPT_direct_clang_cc1_module_build);
12761277

12771278
if (const Arg *A = Args.getLastArg(OPT_pch_output_dir)) {
12781279
Opts.PrecompiledHeaderOutputDir = A->getValue();
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Emit the explicit module.
2+
// RUN: %empty-directory(%t)
3+
// RUN: %swift-frontend -emit-pcm -direct-clang-cc1-module-build -only-use-extra-clang-opts -module-name script -o %t/script.pcm %S/Inputs/custom-modules/module.map -Xcc %S/Inputs/custom-modules/module.map -Xcc -o -Xcc %t/script.pcm -Xcc -fmodules -Xcc -triple -Xcc %target-triple -Xcc -x -Xcc objective-c -dump-clang-diagnostics 2> %t.diags.txt
4+
5+
// Verify some of the output of the -dump-pcm flag.
6+
// RUN: %swift-dump-pcm %t/script.pcm | %FileCheck %s --check-prefix=CHECK-DUMP
7+
// CHECK-DUMP: Information for module file '{{.*}}/script.pcm':
8+
// CHECK-DUMP: Module name: script
9+
// CHECK-DUMP: Module map file: {{.*[/\\]}}Inputs{{/|\\}}custom-modules{{/|\\}}module.map
10+
11+
// Verify that the clang command-line used is cc1
12+
// RUN: %FileCheck -check-prefix CHECK-CLANG %s < %t.diags.txt
13+
// CHECK-CLANG: '{{.*[/\\]}}clang'{{.*}}'-fmodules'
14+
15+
import script
16+
var _ : ScriptTy

0 commit comments

Comments
 (0)