52
52
#include " swift/Subsystems.h"
53
53
#include " clang/AST/ASTContext.h"
54
54
#include " clang/AST/Mangle.h"
55
+ #include " clang/Basic/DiagnosticOptions.h"
55
56
#include " clang/Basic/FileEntry.h"
56
57
#include " clang/Basic/IdentifierTable.h"
57
58
#include " clang/Basic/Module.h"
58
59
#include " clang/Basic/TargetInfo.h"
59
60
#include " clang/Basic/Version.h"
60
61
#include " clang/CodeGen/ObjectFilePCHContainerOperations.h"
61
62
#include " clang/Frontend/FrontendActions.h"
63
+ #include " clang/Frontend/TextDiagnosticPrinter.h"
62
64
#include " clang/Frontend/Utils.h"
63
65
#include " clang/Index/IndexingAction.h"
64
66
#include " clang/Lex/Preprocessor.h"
85
87
#include " llvm/TextAPI/TextAPIReader.h"
86
88
#include < algorithm>
87
89
#include < memory>
90
+ #include < optional>
88
91
#include < string>
89
92
90
93
using namespace swift ;
@@ -1040,19 +1043,13 @@ ClangImporter::getOrCreatePCH(const ClangImporterOptions &ImporterOptions,
1040
1043
}
1041
1044
1042
1045
std::vector<std::string>
1043
- ClangImporter::getClangArguments (ASTContext &ctx, bool ignoreClangTarget) {
1046
+ ClangImporter::getClangDriverArguments (ASTContext &ctx, bool ignoreClangTarget) {
1047
+ assert (!ctx.ClangImporterOpts .DirectClangCC1ModuleBuild &&
1048
+ " direct-clang-cc1-module-build should not call this function" );
1044
1049
std::vector<std::string> invocationArgStrs;
1045
1050
// When creating from driver commands, clang expects this to be like an actual
1046
1051
// command line. So we need to pass in "clang" for argv[0]
1047
- if (!ctx.ClangImporterOpts .DirectClangCC1ModuleBuild )
1048
- invocationArgStrs.push_back (ctx.ClangImporterOpts .clangPath );
1049
- if (ctx.ClangImporterOpts .ExtraArgsOnly ) {
1050
- invocationArgStrs.insert (invocationArgStrs.end (),
1051
- ctx.ClangImporterOpts .ExtraArgs .begin (),
1052
- ctx.ClangImporterOpts .ExtraArgs .end ());
1053
- return invocationArgStrs;
1054
- }
1055
-
1052
+ invocationArgStrs.push_back (ctx.ClangImporterOpts .clangPath );
1056
1053
switch (ctx.ClangImporterOpts .Mode ) {
1057
1054
case ClangImporterOptions::Modes::Normal:
1058
1055
case ClangImporterOptions::Modes::PrecompiledModule:
@@ -1066,69 +1063,59 @@ ClangImporter::getClangArguments(ASTContext &ctx, bool ignoreClangTarget) {
1066
1063
return invocationArgStrs;
1067
1064
}
1068
1065
1069
- std::unique_ptr<clang::CompilerInvocation> ClangImporter::createClangInvocation (
1070
- ClangImporter *importer, const ClangImporterOptions &importerOpts ,
1066
+ std::optional<std::vector<std::string>> ClangImporter::getClangCC1Arguments (
1067
+ ClangImporter *importer, ASTContext &ctx ,
1071
1068
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
1072
- ArrayRef<std::string> invocationArgStrs,
1073
- std::vector<std::string> *CC1Args) {
1074
- std::vector<const char *> invocationArgs;
1075
- invocationArgs.reserve (invocationArgStrs.size ());
1076
- for (auto &argStr : invocationArgStrs)
1077
- invocationArgs.push_back (argStr.c_str ());
1078
-
1079
- llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> clangDiags;
1080
- std::unique_ptr<clang::CompilerInvocation> CI;
1081
- if (importerOpts.DirectClangCC1ModuleBuild ) {
1082
- // In this mode, we bypass createInvocationFromCommandLine, which goes
1083
- // through the Clang driver, and use strictly cc1 arguments to instantiate a
1084
- // clang Instance directly, assuming that the set of '-Xcc <X>' frontend flags is
1085
- // fully sufficient to do so.
1086
-
1087
- // Because we are bypassing the Clang driver, we must populate
1088
- // the diagnostic options here explicitly.
1089
- std::unique_ptr<clang::DiagnosticOptions> clangDiagOpts =
1090
- clang::CreateAndPopulateDiagOpts (invocationArgs);
1091
- auto *diagClient = new ClangDiagnosticConsumer (
1092
- importer->Impl , *clangDiagOpts, importerOpts.DumpClangDiagnostics );
1093
- clangDiags = clang::CompilerInstance::createDiagnostics (
1094
- clangDiagOpts.release (), diagClient,
1095
- /* owned*/ true );
1096
-
1097
- // Finally, use the CC1 command-line and the diagnostic engine
1098
- // to instantiate our Invocation.
1099
- CI = std::make_unique<clang::CompilerInvocation>();
1100
- if (!clang::CompilerInvocation::CreateFromArgs (
1101
- *CI, invocationArgs, *clangDiags, invocationArgs[0 ]))
1102
- return nullptr ;
1103
- } else {
1104
- // Set up a temporary diagnostic client to report errors from parsing the
1105
- // command line, which may be important for Swift clients if, for example,
1106
- // they're using -Xcc options. Unfortunately this diagnostic engine has to
1107
- // use the default options because the /actual/ options haven't been parsed
1108
- // yet.
1109
- //
1110
- // The long-term client for Clang diagnostics is set up below, after the
1111
- // clang::CompilerInstance is created.
1112
- llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> tempDiagOpts{
1113
- new clang::DiagnosticOptions};
1069
+ 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
+ });
1114
1082
1115
- auto *tempDiagClient = new ClangDiagnosticConsumer (
1116
- importer->Impl , *tempDiagOpts, importerOpts.DumpClangDiagnostics );
1117
- clangDiags = clang::CompilerInstance::createDiagnostics (tempDiagOpts.get (),
1118
- tempDiagClient,
1119
- /* owned*/ true );
1120
- clang::CreateInvocationOptions CIOpts;
1121
- CIOpts.VFS = VFS;
1122
- CIOpts.Diags = clangDiags;
1123
- CIOpts.RecoverOnError = false ;
1124
- CIOpts.CC1Args = CC1Args;
1125
- CIOpts.ProbePrecompiled = true ;
1126
- CI = clang::createInvocation (invocationArgs, std::move (CIOpts));
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 " ;
1127
1089
}
1128
1090
1129
- if (!CI) {
1130
- return CI;
1131
- }
1091
+ // Set up a temporary diagnostic client to report errors from parsing the
1092
+ // command line, which may be important for Swift clients if, for example,
1093
+ // they're using -Xcc options. Unfortunately this diagnostic engine has to
1094
+ // use the default options because the /actual/ options haven't been parsed
1095
+ // yet.
1096
+ //
1097
+ // The long-term client for Clang diagnostics is set up afterwards, after the
1098
+ // clang::CompilerInstance is created.
1099
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> tempDiagOpts{
1100
+ new clang::DiagnosticOptions};
1101
+
1102
+ auto *tempDiagClient =
1103
+ new ClangDiagnosticConsumer (importer->Impl , *tempDiagOpts,
1104
+ ctx.ClangImporterOpts .DumpClangDiagnostics );
1105
+
1106
+ auto clangDiags = clang::CompilerInstance::createDiagnostics (
1107
+ tempDiagOpts.get (), tempDiagClient,
1108
+ /* owned*/ true );
1109
+
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));
1116
+
1117
+ if (!CI)
1118
+ return std::nullopt;
1132
1119
1133
1120
// FIXME: clang fails to generate a module if there is a `-fmodule-map-file`
1134
1121
// argument pointing to a missing file.
@@ -1146,7 +1133,12 @@ std::unique_ptr<clang::CompilerInvocation> ClangImporter::createClangInvocation(
1146
1133
1147
1134
std::vector<std::string> FilteredModuleMapFiles;
1148
1135
for (auto ModuleMapFile : CI->getFrontendOpts ().ModuleMapFiles ) {
1149
- if (TempVFS->exists (ModuleMapFile)) {
1136
+ if (ctx.ClangImporterOpts .UseClangIncludeTree ) {
1137
+ // There is no need to add any module map file here. Issue a warning and
1138
+ // drop the option.
1139
+ importer->Impl .diagnose (SourceLoc (), diag::module_map_ignored,
1140
+ ModuleMapFile);
1141
+ } else if (TempVFS->exists (ModuleMapFile)) {
1150
1142
FilteredModuleMapFiles.push_back (ModuleMapFile);
1151
1143
} else {
1152
1144
importer->Impl .diagnose (SourceLoc (), diag::module_map_not_found,
@@ -1155,6 +1147,35 @@ std::unique_ptr<clang::CompilerInvocation> ClangImporter::createClangInvocation(
1155
1147
}
1156
1148
CI->getFrontendOpts ().ModuleMapFiles = FilteredModuleMapFiles;
1157
1149
1150
+ return CI->getCC1CommandLine ();
1151
+ }
1152
+
1153
+ std::unique_ptr<clang::CompilerInvocation> ClangImporter::createClangInvocation (
1154
+ ClangImporter *importer, const ClangImporterOptions &importerOpts,
1155
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
1156
+ std::vector<std::string> &CC1Args) {
1157
+ std::vector<const char *> invocationArgs;
1158
+ invocationArgs.reserve (CC1Args.size ());
1159
+ llvm::for_each (CC1Args, [&](const std::string &Arg) {
1160
+ invocationArgs.push_back (Arg.c_str ());
1161
+ });
1162
+
1163
+ // Create a diagnostics engine for creating clang compiler invocation. The
1164
+ // option here is either generated by dependency scanner or just round tripped
1165
+ // from `getClangCC1Arguments` so we don't expect it to fail. Use a simple
1166
+ // printing diagnostics consumer for debugging any unexpected error.
1167
+ auto diagOpts = llvm::makeIntrusiveRefCnt<clang::DiagnosticOptions>();
1168
+ clang::DiagnosticsEngine clangDiags (
1169
+ new clang::DiagnosticIDs (), diagOpts,
1170
+ new clang::TextDiagnosticPrinter (llvm::errs (), diagOpts.get ()));
1171
+
1172
+ // Finally, use the CC1 command-line and the diagnostic engine
1173
+ // to instantiate our Invocation.
1174
+ auto CI = std::make_unique<clang::CompilerInvocation>();
1175
+ if (!clang::CompilerInvocation::CreateFromArgs (
1176
+ *CI, invocationArgs, clangDiags, importerOpts.clangPath .c_str ()))
1177
+ return nullptr ;
1178
+
1158
1179
return CI;
1159
1180
}
1160
1181
@@ -1204,21 +1225,24 @@ ClangImporter::create(ASTContext &ctx,
1204
1225
1205
1226
// Create a new Clang compiler invocation.
1206
1227
{
1207
- importer->Impl .ClangArgs = getClangArguments (ctx);
1208
- if (fileMapping.requiresBuiltinHeadersInSystemModules ) {
1209
- importer->Impl .ClangArgs .push_back (" -Xclang" );
1228
+ if (auto ClangArgs = getClangCC1Arguments (importer.get (), ctx, VFS))
1229
+ importer->Impl .ClangArgs = *ClangArgs;
1230
+ else
1231
+ return nullptr ;
1232
+
1233
+ if (fileMapping.requiresBuiltinHeadersInSystemModules )
1210
1234
importer->Impl .ClangArgs .push_back (" -fbuiltin-headers-in-system-modules" );
1211
- }
1235
+
1212
1236
ArrayRef<std::string> invocationArgStrs = importer->Impl .ClangArgs ;
1213
1237
if (importerOpts.DumpClangDiagnostics ) {
1214
- llvm::errs () << " '" ;
1238
+ llvm::errs () << " clang importer cc1 args: '" ;
1215
1239
llvm::interleave (
1216
1240
invocationArgStrs, [](StringRef arg) { llvm::errs () << arg; },
1217
1241
[] { llvm::errs () << " ' '" ; });
1218
1242
llvm::errs () << " '\n " ;
1219
1243
}
1220
1244
importer->Impl .Invocation = createClangInvocation (
1221
- importer.get (), importerOpts, VFS, invocationArgStrs );
1245
+ importer.get (), importerOpts, VFS, importer-> Impl . ClangArgs );
1222
1246
if (!importer->Impl .Invocation )
1223
1247
return nullptr ;
1224
1248
}
@@ -1296,10 +1320,12 @@ ClangImporter::create(ASTContext &ctx,
1296
1320
if (ctx.LangOpts .ClangTarget .has_value ()) {
1297
1321
// If '-clang-target' is set, create a mock invocation with the Swift triple
1298
1322
// to configure CodeGen and Target options for Swift compilation.
1299
- auto swiftTargetClangArgs = getClangArguments (ctx, true );
1300
- ArrayRef<std::string> invocationArgStrs = swiftTargetClangArgs;
1323
+ auto swiftTargetClangArgs =
1324
+ getClangCC1Arguments (importer.get (), ctx, VFS, true );
1325
+ if (!swiftTargetClangArgs)
1326
+ return nullptr ;
1301
1327
auto swiftTargetClangInvocation = createClangInvocation (
1302
- importer.get (), importerOpts, VFS, invocationArgStrs );
1328
+ importer.get (), importerOpts, VFS, *swiftTargetClangArgs );
1303
1329
if (!swiftTargetClangInvocation)
1304
1330
return nullptr ;
1305
1331
importer->Impl .setSwiftTargetInfo (clang::TargetInfo::CreateTargetInfo (
0 commit comments