5858#include " clang/Basic/Module.h"
5959#include " clang/Basic/TargetInfo.h"
6060#include " clang/Basic/Version.h"
61+ #include " clang/CAS/CASOptions.h"
6162#include " clang/CodeGen/ObjectFilePCHContainerOperations.h"
63+ #include " clang/Frontend/CompilerInvocation.h"
6264#include " clang/Frontend/FrontendActions.h"
6365#include " clang/Frontend/TextDiagnosticPrinter.h"
6466#include " clang/Frontend/Utils.h"
7375#include " clang/Sema/Sema.h"
7476#include " clang/Serialization/ASTReader.h"
7577#include " clang/Serialization/ASTWriter.h"
78+ #include " clang/Tooling/DependencyScanning/ScanAndUpdateArgs.h"
7679#include " llvm/ADT/IntrusiveRefCntPtr.h"
7780#include " llvm/ADT/STLExtras.h"
81+ #include " llvm/ADT/SmallVector.h"
7882#include " llvm/ADT/StringExtras.h"
7983#include " llvm/Support/CrashRecoveryContext.h"
8084#include " llvm/Support/FileCollector.h"
@@ -1067,26 +1071,7 @@ std::optional<std::vector<std::string>> ClangImporter::getClangCC1Arguments(
10671071 ClangImporter *importer, ASTContext &ctx,
10681072 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
10691073 bool ignoreClangTarget) {
1070- // If using direct cc1 module build, return extra args only.
1071- if (ctx.ClangImporterOpts .DirectClangCC1ModuleBuild )
1072- return ctx.ClangImporterOpts .ExtraArgs ;
1073-
1074- // Otherwise, create cc1 arguments from driver args.
1075- auto driverArgs = getClangDriverArguments (ctx, ignoreClangTarget);
1076-
1077- llvm::SmallVector<const char *> invocationArgs;
1078- invocationArgs.reserve (driverArgs.size ());
1079- llvm::for_each (driverArgs, [&](const std::string &Arg) {
1080- invocationArgs.push_back (Arg.c_str ());
1081- });
1082-
1083- if (ctx.ClangImporterOpts .DumpClangDiagnostics ) {
1084- llvm::errs () << " clang importer driver args: '" ;
1085- llvm::interleave (
1086- invocationArgs, [](StringRef arg) { llvm::errs () << arg; },
1087- [] { llvm::errs () << " ' '" ; });
1088- llvm::errs () << " '\n " ;
1089- }
1074+ std::unique_ptr<clang::CompilerInvocation> CI;
10901075
10911076 // Set up a temporary diagnostic client to report errors from parsing the
10921077 // command line, which may be important for Swift clients if, for example,
@@ -1098,24 +1083,60 @@ std::optional<std::vector<std::string>> ClangImporter::getClangCC1Arguments(
10981083 // clang::CompilerInstance is created.
10991084 llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> tempDiagOpts{
11001085 new clang::DiagnosticOptions};
1101-
11021086 auto *tempDiagClient =
11031087 new ClangDiagnosticConsumer (importer->Impl , *tempDiagOpts,
11041088 ctx.ClangImporterOpts .DumpClangDiagnostics );
1105-
11061089 auto clangDiags = clang::CompilerInstance::createDiagnostics (
11071090 tempDiagOpts.get (), tempDiagClient,
11081091 /* owned*/ true );
11091092
1110- clang::CreateInvocationOptions CIOpts;
1111- CIOpts.VFS = VFS;
1112- CIOpts.Diags = clangDiags;
1113- CIOpts.RecoverOnError = false ;
1114- CIOpts.ProbePrecompiled = true ;
1115- auto CI = clang::createInvocation (invocationArgs, std::move (CIOpts));
1093+ // If using direct cc1 module build, use extra args to setup ClangImporter.
1094+ if (ctx.ClangImporterOpts .DirectClangCC1ModuleBuild ) {
1095+ llvm::SmallVector<const char *> clangArgs;
1096+ clangArgs.reserve (ctx.ClangImporterOpts .ExtraArgs .size ());
1097+ llvm::for_each (
1098+ ctx.ClangImporterOpts .ExtraArgs ,
1099+ [&](const std::string &Arg) { clangArgs.push_back (Arg.c_str ()); });
1100+
1101+ // Try parse extra args, if failed, return nullopt.
1102+ CI = std::make_unique<clang::CompilerInvocation>();
1103+ if (!clang::CompilerInvocation::CreateFromArgs (*CI, clangArgs,
1104+ *clangDiags))
1105+ return std::nullopt ;
11161106
1117- if (!CI)
1118- return std::nullopt ;
1107+ // Forwards some options from swift to clang even using direct mode. This is
1108+ // to reduce the number of argument passing on the command-line and swift
1109+ // compiler can be more efficient to compute swift cache key without having
1110+ // the knowledge about clang command-line options.
1111+ if (ctx.CASOpts .EnableCaching )
1112+ CI->getCASOpts () = ctx.CASOpts .CASOpts ;
1113+ } else {
1114+ // Otherwise, create cc1 arguments from driver args.
1115+ auto driverArgs = getClangDriverArguments (ctx, ignoreClangTarget);
1116+
1117+ llvm::SmallVector<const char *> invocationArgs;
1118+ invocationArgs.reserve (driverArgs.size ());
1119+ llvm::for_each (driverArgs, [&](const std::string &Arg) {
1120+ invocationArgs.push_back (Arg.c_str ());
1121+ });
1122+
1123+ if (ctx.ClangImporterOpts .DumpClangDiagnostics ) {
1124+ llvm::errs () << " clang importer driver args: '" ;
1125+ llvm::interleave (
1126+ invocationArgs, [](StringRef arg) { llvm::errs () << arg; },
1127+ [] { llvm::errs () << " ' '" ; });
1128+ llvm::errs () << " '\n " ;
1129+ }
1130+
1131+ clang::CreateInvocationOptions CIOpts;
1132+ CIOpts.VFS = VFS;
1133+ CIOpts.Diags = clangDiags;
1134+ CIOpts.RecoverOnError = false ;
1135+ CIOpts.ProbePrecompiled = true ;
1136+ CI = clang::createInvocation (invocationArgs, std::move (CIOpts));
1137+ if (!CI)
1138+ return std::nullopt ;
1139+ }
11191140
11201141 // FIXME: clang fails to generate a module if there is a `-fmodule-map-file`
11211142 // argument pointing to a missing file.
@@ -3919,6 +3940,63 @@ std::string ClangImporter::getClangModuleHash() const {
39193940 return Impl.Invocation ->getModuleHash (Impl.Instance ->getDiagnostics ());
39203941}
39213942
3943+ std::vector<std::string>
3944+ ClangImporter::getSwiftExplicitModuleDirectCC1Args () const {
3945+ llvm::SmallVector<const char *> clangArgs;
3946+ clangArgs.reserve (Impl.ClangArgs .size ());
3947+ llvm::for_each (Impl.ClangArgs , [&](const std::string &Arg) {
3948+ clangArgs.push_back (Arg.c_str ());
3949+ });
3950+
3951+ clang::CompilerInvocation instance;
3952+ clang::DiagnosticsEngine clangDiags (new clang::DiagnosticIDs (),
3953+ new clang::DiagnosticOptions (),
3954+ new clang::IgnoringDiagConsumer ());
3955+ bool success = clang::CompilerInvocation::CreateFromArgs (instance, clangArgs,
3956+ clangDiags);
3957+ (void )success;
3958+ assert (success && " clang options from clangImporter failed to parse" );
3959+
3960+ if (!Impl.SwiftContext .CASOpts .EnableCaching )
3961+ return instance.getCC1CommandLine ();
3962+
3963+ // Clear some options that are not needed.
3964+ instance.clearImplicitModuleBuildOptions ();
3965+
3966+ // CASOpts are forwarded from swift arguments.
3967+ instance.getCASOpts () = clang::CASOptions ();
3968+
3969+ // HeaderSearchOptions.
3970+ // Clang search options are only used by scanner and clang importer from main
3971+ // module should not using search paths to find modules.
3972+ auto &HSOpts = instance.getHeaderSearchOpts ();
3973+ HSOpts.VFSOverlayFiles .clear ();
3974+ HSOpts.UserEntries .clear ();
3975+ HSOpts.SystemHeaderPrefixes .clear ();
3976+
3977+ // FrontendOptions.
3978+ auto &FEOpts = instance.getFrontendOpts ();
3979+ FEOpts.IncludeTimestamps = false ;
3980+ FEOpts.ModuleMapFiles .clear ();
3981+
3982+ // PreprocessorOptions.
3983+ // Cannot clear macros as the main module clang importer doesn't have clang
3984+ // include tree created and it has to be created from command-line. However,
3985+ // include files are no collected into CASFS so they will not be found so
3986+ // clear them to avoid problem.
3987+ auto &PPOpts = instance.getPreprocessorOpts ();
3988+ PPOpts.MacroIncludes .clear ();
3989+ PPOpts.Includes .clear ();
3990+
3991+ if (Impl.SwiftContext .ClangImporterOpts .UseClangIncludeTree ) {
3992+ // FileSystemOptions.
3993+ auto &FSOpts = instance.getFileSystemOpts ();
3994+ FSOpts.WorkingDir .clear ();
3995+ }
3996+
3997+ return instance.getCC1CommandLine ();
3998+ }
3999+
39224000std::optional<Decl *>
39234001ClangImporter::importDeclCached (const clang::NamedDecl *ClangDecl) {
39244002 return Impl.importDeclCached (ClangDecl, Impl.CurrentVersion );
0 commit comments