5353#include  " ToolChains/WebAssembly.h" 
5454#include  " ToolChains/XCore.h" 
5555#include  " ToolChains/ZOS.h" 
56+ #include  " clang/Basic/CharInfo.h" 
5657#include  " clang/Basic/DiagnosticDriver.h" 
5758#include  " clang/Basic/TargetID.h" 
5859#include  " clang/Basic/Version.h" 
@@ -4291,6 +4292,13 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
42914292    YcArg = nullptr ;
42924293  }
42934294
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+ 
42944302  Arg *FinalPhaseArg;
42954303  phases::ID FinalPhase = getFinalPhase (Args, &FinalPhaseArg);
42964304
@@ -4417,6 +4425,174 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
44174425  }
44184426}
44194427
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+ 
44204596void  Driver::BuildActions (Compilation &C, DerivedArgList &Args,
44214597                          const  InputList &Inputs, ActionList &Actions) const  {
44224598  llvm::PrettyStackTraceString CrashInfo (" Building compilation actions"  );
@@ -4428,6 +4604,33 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
44284604
44294605  handleArguments (C, Args, Inputs, Actions);
44304606
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+ 
44314634  bool  UseNewOffloadingDriver =
44324635      C.isOffloadingHostKind (Action::OFK_OpenMP) ||
44334636      C.isOffloadingHostKind (Action::OFK_SYCL) ||
@@ -4711,6 +4914,13 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
47114914  Args.ClaimAllArgs (options::OPT_cl_ignored_Group);
47124915}
47134916
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+ 
47144924// / Returns the canonical name for the offloading architecture when using a HIP
47154925// / or CUDA architecture.
47164926static  StringRef getCanonicalArchString (Compilation &C,
0 commit comments