53
53
#include " ToolChains/WebAssembly.h"
54
54
#include " ToolChains/XCore.h"
55
55
#include " ToolChains/ZOS.h"
56
+ #include " clang/Basic/CharInfo.h"
56
57
#include " clang/Basic/DiagnosticDriver.h"
57
58
#include " clang/Basic/TargetID.h"
58
59
#include " clang/Basic/Version.h"
@@ -4291,6 +4292,13 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
4291
4292
YcArg = nullptr ;
4292
4293
}
4293
4294
4295
+ if (Args.hasArgNoClaim (options::OPT_fmodules_driver))
4296
+ // TODO: Check against all incompatible -fmodules-driver arguments
4297
+ if (!ModulesModeCXX20) {
4298
+ Diag (diag::warn_modules_driver_unsupported_standard);
4299
+ Args.eraseArg (options::OPT_fmodules_driver);
4300
+ }
4301
+
4294
4302
Arg *FinalPhaseArg;
4295
4303
phases::ID FinalPhase = getFinalPhase (Args, &FinalPhaseArg);
4296
4304
@@ -4417,6 +4425,174 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
4417
4425
}
4418
4426
}
4419
4427
4428
+ static void skipWhitespace (const char *&Ptr) {
4429
+ while (isWhitespace (*Ptr))
4430
+ ++Ptr;
4431
+ }
4432
+
4433
+ // Returns the length of EOL, either 0 (no end-of-line), 1 (\n) or 2 (\r\n).
4434
+ static unsigned isEOL (const char *Ptr) {
4435
+ if (*Ptr == ' \0 ' )
4436
+ return 0 ;
4437
+ if (*(Ptr + 1 ) != ' \0 ' && isVerticalWhitespace (Ptr[0 ]) &&
4438
+ isVerticalWhitespace (Ptr[1 ]) && Ptr[0 ] != Ptr[1 ])
4439
+ return 2 ;
4440
+ return !!isVerticalWhitespace (Ptr[0 ]);
4441
+ }
4442
+
4443
+ static void skipLine (const char *&Ptr) {
4444
+ for (;;) {
4445
+ char LastNonWhitespace = ' ' ;
4446
+ while (!isVerticalWhitespace (*Ptr) && *Ptr != ' \0 ' ) {
4447
+ if (!isHorizontalWhitespace (*Ptr))
4448
+ LastNonWhitespace = *Ptr;
4449
+ ++Ptr;
4450
+ }
4451
+
4452
+ const unsigned Len = isEOL (Ptr);
4453
+ if (!Len)
4454
+ return ;
4455
+
4456
+ Ptr += Len;
4457
+ if (LastNonWhitespace != ' \\ ' )
4458
+ break ;
4459
+ }
4460
+ }
4461
+
4462
+ // Returns the length of a line splice sequence (including trailing
4463
+ // whitespace), or 0 if no line splice is found.
4464
+ static unsigned isLineSplice (const char *Start) {
4465
+ if (*Start != ' \\ ' )
4466
+ return 0 ;
4467
+
4468
+ const char *Ptr = Start + 1 ;
4469
+ while (isHorizontalWhitespace (*Ptr))
4470
+ ++Ptr;
4471
+
4472
+ if (unsigned Len = isEOL (Ptr))
4473
+ return Ptr - Start + Len;
4474
+ return 0 ;
4475
+ }
4476
+
4477
+ static bool trySkipLineSplice (const char *&Ptr) {
4478
+ if (unsigned Len = isLineSplice (Ptr); Len) {
4479
+ Ptr += Len;
4480
+ return true ;
4481
+ }
4482
+ return false ;
4483
+ }
4484
+
4485
+ static bool trySkipDirective (const char *&Ptr) {
4486
+ if (*Ptr != ' #' )
4487
+ return false ;
4488
+
4489
+ ++Ptr;
4490
+ skipLine (Ptr);
4491
+ return true ;
4492
+ }
4493
+
4494
+ static bool trySkipLineComment (const char *&Ptr) {
4495
+ if (Ptr[0 ] != ' /' || Ptr[1 ] != ' /' )
4496
+ return false ;
4497
+
4498
+ Ptr += 2 ;
4499
+ skipLine (Ptr);
4500
+ return true ;
4501
+ }
4502
+
4503
+ static bool trySkipBlockComment (const char *&Ptr) {
4504
+ if (Ptr[0 ] != ' /' || Ptr[1 ] != ' *' )
4505
+ return false ;
4506
+
4507
+ Ptr += 2 ;
4508
+ while (*Ptr != ' \0 ' ) {
4509
+ if (Ptr[0 ] == ' *' && Ptr[1 ] == ' /' ) {
4510
+ Ptr += 2 ; // '*/'
4511
+ return true ;
4512
+ }
4513
+ ++Ptr;
4514
+ }
4515
+ return true ;
4516
+ }
4517
+
4518
+ static bool trySkipComment (const char *&Ptr) {
4519
+ return trySkipLineComment (Ptr) || trySkipBlockComment (Ptr);
4520
+ }
4521
+
4522
+ // Skipps over comments and (non-module) directives
4523
+ static void skipToRelevantCXXModuleText (const char *&Ptr) {
4524
+ while (*Ptr != ' \0 ' ) {
4525
+ skipWhitespace (Ptr);
4526
+ if (trySkipComment (Ptr) || trySkipDirective (Ptr) || trySkipLineSplice (Ptr))
4527
+ continue ;
4528
+ break ; // Found relevant text!
4529
+ }
4530
+ }
4531
+
4532
+ static bool scanBufferForCXXModuleUsage (const llvm::MemoryBuffer &Buffer) {
4533
+ const char *Ptr = Buffer.getBufferStart ();
4534
+ skipToRelevantCXXModuleText (Ptr);
4535
+
4536
+ // Check if the buffer has enough remaining bytes left for any of the
4537
+ // module-related declaration fragments we are checking for, without making
4538
+ // the potentially memory-mapped buffer load unnecessary pages.
4539
+ constexpr int MinKeywordLength = 6 ;
4540
+ const char *Begin = Ptr;
4541
+ for (int i = 0 ; i < MinKeywordLength; ++i) {
4542
+ if (*Ptr == ' \0 ' )
4543
+ return false ;
4544
+ ++Ptr;
4545
+ }
4546
+ StringRef Text (Begin, MinKeywordLength);
4547
+
4548
+ const bool IsGlobalModule = Text.starts_with (" module" );
4549
+ if (!IsGlobalModule && !Text.starts_with (" import" ) &&
4550
+ !Text.starts_with (" export" ))
4551
+ return false ;
4552
+
4553
+ // Ensure the keyword has a proper ending and isn't part of a identifier
4554
+ // or namespace. For this we might have to skip comments and line
4555
+ // continuations.
4556
+ while (*Ptr != ' \0 ' ) {
4557
+ if (isWhitespace (*Ptr) || (IsGlobalModule && *Ptr == ' ;' ))
4558
+ return true ;
4559
+ if (trySkipBlockComment (Ptr) || trySkipLineSplice (Ptr))
4560
+ continue ;
4561
+ return false ;
4562
+ }
4563
+
4564
+ return false ;
4565
+ }
4566
+
4567
+ static bool hasCXXModuleInputType (const Driver::InputList &Inputs) {
4568
+ const auto IsTypeCXXModule = [](const auto &Input) -> bool {
4569
+ const auto TypeID = Input.first ;
4570
+ return (TypeID == types::TY_CXXModule);
4571
+ };
4572
+ return llvm::any_of (Inputs, IsTypeCXXModule);
4573
+ }
4574
+
4575
+ llvm::ErrorOr<bool >
4576
+ Driver::ScanInputsForCXXModuleUsage (const InputList &Inputs) const {
4577
+ const auto CXXInputs = llvm::make_filter_range (
4578
+ Inputs, [](const auto &Input) { return types::isCXX (Input.first ); });
4579
+
4580
+ for (const auto &Input : CXXInputs) {
4581
+ StringRef Filename = Input.second ->getSpelling ();
4582
+ auto ErrOrBuffer = VFS->getBufferForFile (Filename);
4583
+ if (!ErrOrBuffer)
4584
+ return ErrOrBuffer.getError ();
4585
+ const auto Buffer = std::move (*ErrOrBuffer);
4586
+
4587
+ if (scanBufferForCXXModuleUsage (*Buffer)) {
4588
+ Diags.Report (diag::remark_found_cxx20_module_usage) << Filename;
4589
+ return true ;
4590
+ }
4591
+ }
4592
+
4593
+ return false ;
4594
+ }
4595
+
4420
4596
void Driver::BuildActions (Compilation &C, DerivedArgList &Args,
4421
4597
const InputList &Inputs, ActionList &Actions) const {
4422
4598
llvm::PrettyStackTraceString CrashInfo (" Building compilation actions" );
@@ -4428,6 +4604,33 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
4428
4604
4429
4605
handleArguments (C, Args, Inputs, Actions);
4430
4606
4607
+ if (Args.hasFlag (options::OPT_fmodules_driver,
4608
+ options::OPT_fno_modules_driver, false )) {
4609
+ // TODO: Move the logic for implicitly enabling explicit-module-builds out
4610
+ // of -fmodules-driver once it is no longer experimental.
4611
+ // Currently, this serves diagnostic purposes only.
4612
+ bool UsesCXXModules = hasCXXModuleInputType (Inputs);
4613
+ if (!UsesCXXModules) {
4614
+ const auto ErrOrScanResult = ScanInputsForCXXModuleUsage (Inputs);
4615
+ if (!ErrOrScanResult) {
4616
+ Diags.Report (diag::err_cannot_open_file)
4617
+ << ErrOrScanResult.getError ().message ();
4618
+ return ;
4619
+ }
4620
+ UsesCXXModules = *ErrOrScanResult;
4621
+ }
4622
+ if (UsesCXXModules)
4623
+ BuildDriverManagedModuleBuildActions (C, Args, Inputs, Actions);
4624
+ return ;
4625
+ }
4626
+
4627
+ BuildDefaultActions (C, Args, Inputs, Actions);
4628
+ }
4629
+
4630
+ void Driver::BuildDefaultActions (Compilation &C, DerivedArgList &Args,
4631
+ const InputList &Inputs,
4632
+ ActionList &Actions) const {
4633
+
4431
4634
bool UseNewOffloadingDriver =
4432
4635
C.isOffloadingHostKind (Action::OFK_OpenMP) ||
4433
4636
C.isOffloadingHostKind (Action::OFK_SYCL) ||
@@ -4711,6 +4914,13 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
4711
4914
Args.ClaimAllArgs (options::OPT_cl_ignored_Group);
4712
4915
}
4713
4916
4917
+ void Driver::BuildDriverManagedModuleBuildActions (
4918
+ Compilation &C, llvm::opt::DerivedArgList &Args, const InputList &Inputs,
4919
+ ActionList &Actions) const {
4920
+ Diags.Report (diag::remark_performing_driver_managed_module_build);
4921
+ return ;
4922
+ }
4923
+
4714
4924
// / Returns the canonical name for the offloading architecture when using a HIP
4715
4925
// / or CUDA architecture.
4716
4926
static StringRef getCanonicalArchString (Compilation &C,
0 commit comments