@@ -191,13 +191,14 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
191
191
DiagnosticsEngine &Diags, std::string Title,
192
192
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
193
193
: Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode),
194
- SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None),
195
- ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
196
- DriverTitle(Title), CCCPrintBindings(false ), CCPrintOptions(false ),
197
- CCPrintHeaders(false ), CCLogDiagnostics(false ), CCGenDiagnostics(false ),
198
- CCPrintProcessStats(false ), TargetTriple(TargetTriple), Saver(Alloc),
199
- CheckInputsExist(true ), GenReproducer(false ),
200
- SuppressMissingInputWarning(false ) {
194
+ SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone),
195
+ CXX20HeaderType(HeaderMode_None), ModulesModeCXX20(false ),
196
+ LTOMode(LTOK_None), ClangExecutable(ClangExecutable),
197
+ SysRoot(DEFAULT_SYSROOT), DriverTitle(Title), CCCPrintBindings(false ),
198
+ CCPrintOptions(false ), CCPrintHeaders(false ), CCLogDiagnostics(false ),
199
+ CCGenDiagnostics(false ), CCPrintProcessStats(false ),
200
+ TargetTriple(TargetTriple), Saver(Alloc), CheckInputsExist(true ),
201
+ GenReproducer(false ), SuppressMissingInputWarning(false ) {
201
202
// Provide a sane fallback if no VFS is specified.
202
203
if (!this ->VFS )
203
204
this ->VFS = llvm::vfs::getRealFileSystem ();
@@ -337,9 +338,13 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
337
338
CCGenDiagnostics) {
338
339
FinalPhase = phases::Preprocess;
339
340
340
- // --precompile only runs up to precompilation.
341
+ // --precompile only runs up to precompilation.
342
+ // Options that cause the output of C++20 compiled module interfaces or
343
+ // header units have the same effect.
341
344
} else if ((PhaseArg = DAL.getLastArg (options::OPT__precompile)) ||
342
- (PhaseArg = DAL.getLastArg (options::OPT_extract_api))) {
345
+ (PhaseArg = DAL.getLastArg (options::OPT_extract_api)) ||
346
+ (PhaseArg = DAL.getLastArg (options::OPT_fmodule_header,
347
+ options::OPT_fmodule_header_EQ))) {
343
348
FinalPhase = phases::Precompile;
344
349
// -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
345
350
} else if ((PhaseArg = DAL.getLastArg (options::OPT_fsyntax_only)) ||
@@ -1251,6 +1256,37 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
1251
1256
BitcodeEmbed = static_cast <BitcodeEmbedMode>(Model);
1252
1257
}
1253
1258
1259
+ // Setting up the jobs for some precompile cases depends on whether we are
1260
+ // treating them as PCH, implicit modules or C++20 ones.
1261
+ // TODO: inferring the mode like this seems fragile (it meets the objective
1262
+ // of not requiring anything new for operation, however).
1263
+ const Arg *Std = Args.getLastArg (options::OPT_std_EQ);
1264
+ ModulesModeCXX20 =
1265
+ !Args.hasArg (options::OPT_fmodules) && Std &&
1266
+ (Std->containsValue (" c++20" ) || Std->containsValue (" c++2b" ) ||
1267
+ Std->containsValue (" c++2a" ) || Std->containsValue (" c++latest" ));
1268
+
1269
+ // Process -fmodule-header{=} flags.
1270
+ if (Arg *A = Args.getLastArg (options::OPT_fmodule_header_EQ,
1271
+ options::OPT_fmodule_header)) {
1272
+ // These flags force C++20 handling of headers.
1273
+ ModulesModeCXX20 = true ;
1274
+ if (A->getOption ().matches (options::OPT_fmodule_header))
1275
+ CXX20HeaderType = HeaderMode_Default;
1276
+ else {
1277
+ StringRef ArgName = A->getValue ();
1278
+ unsigned Kind = llvm::StringSwitch<unsigned >(ArgName)
1279
+ .Case (" user" , HeaderMode_User)
1280
+ .Case (" system" , HeaderMode_System)
1281
+ .Default (~0U );
1282
+ if (Kind == ~0U ) {
1283
+ Diags.Report (diag::err_drv_invalid_value)
1284
+ << A->getAsString (Args) << ArgName;
1285
+ } else
1286
+ CXX20HeaderType = static_cast <ModuleHeaderMode>(Kind);
1287
+ }
1288
+ }
1289
+
1254
1290
std::unique_ptr<llvm::opt::InputArgList> UArgs =
1255
1291
std::make_unique<InputArgList>(std::move (Args));
1256
1292
@@ -2220,8 +2256,11 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
2220
2256
return true ;
2221
2257
2222
2258
// If it's a header to be found in the system or user search path, then defer
2223
- // complaints about its absence until those searches can be done.
2224
- if (Ty == types::TY_CXXSHeader || Ty == types::TY_CXXUHeader)
2259
+ // complaints about its absence until those searches can be done. When we
2260
+ // are definitely processing headers for C++20 header units, extend this to
2261
+ // allow the user to put "-fmodule-header -xc++-header vector" for example.
2262
+ if (Ty == types::TY_CXXSHeader || Ty == types::TY_CXXUHeader ||
2263
+ (ModulesModeCXX20 && Ty == types::TY_CXXHeader))
2225
2264
return true ;
2226
2265
2227
2266
if (getVFS ().exists (Value))
@@ -2287,6 +2326,21 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
2287
2326
return false ;
2288
2327
}
2289
2328
2329
+ // Get the C++20 Header Unit type corresponding to the input type.
2330
+ static types::ID CXXHeaderUnitType (ModuleHeaderMode HM) {
2331
+ switch (HM) {
2332
+ case HeaderMode_User:
2333
+ return types::TY_CXXUHeader;
2334
+ case HeaderMode_System:
2335
+ return types::TY_CXXSHeader;
2336
+ case HeaderMode_Default:
2337
+ break ;
2338
+ case HeaderMode_None:
2339
+ llvm_unreachable (" should not be called in this case" );
2340
+ }
2341
+ return types::TY_CXXHUHeader;
2342
+ }
2343
+
2290
2344
// Construct a the list of inputs and their types.
2291
2345
void Driver::BuildInputs (const ToolChain &TC, DerivedArgList &Args,
2292
2346
InputList &Inputs) const {
@@ -2406,6 +2460,11 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
2406
2460
else if (Args.hasArg (options::OPT_ObjCXX))
2407
2461
Ty = types::TY_ObjCXX;
2408
2462
}
2463
+
2464
+ // Disambiguate headers that are meant to be header units from those
2465
+ // intended to be PCH.
2466
+ if (Ty == types::TY_CXXHeader && hasHeaderMode ())
2467
+ Ty = CXXHeaderUnitType (CXX20HeaderType);
2409
2468
} else {
2410
2469
assert (InputTypeArg && " InputType set w/o InputTypeArg" );
2411
2470
if (!InputTypeArg->getOption ().matches (options::OPT_x)) {
@@ -2457,6 +2516,11 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
2457
2516
Diag (clang::diag::err_drv_unknown_language) << A->getValue ();
2458
2517
InputType = types::TY_Object;
2459
2518
}
2519
+
2520
+ // If the user has put -fmodule-header{,=} then we treat C++ headers as
2521
+ // header unit inputs. So we 'promote' -xc++-header appropriately.
2522
+ if (InputType == types::TY_CXXHeader && hasHeaderMode ())
2523
+ InputType = CXXHeaderUnitType (CXX20HeaderType);
2460
2524
} else if (A->getOption ().getID () == options::OPT_U) {
2461
2525
assert (A->getNumValues () == 1 && " The /U option has one value." );
2462
2526
StringRef Val = A->getValue (0 );
0 commit comments