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" 
@@ -4285,6 +4286,13 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
42854286    YcArg = nullptr ;
42864287  }
42874288
4289+   if  (Args.hasArgNoClaim (options::OPT_fmodules_driver))
4290+     //  TODO: Check against all incompatible -fmodules-driver arguments
4291+     if  (!ModulesModeCXX20) {
4292+       Diag (diag::warn_modules_driver_unsupported_standard);
4293+       Args.eraseArg (options::OPT_fmodules_driver);
4294+     }
4295+ 
42884296  Arg *FinalPhaseArg;
42894297  phases::ID FinalPhase = getFinalPhase (Args, &FinalPhaseArg);
42904298
@@ -4403,6 +4411,177 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
44034411  }
44044412}
44054413
4414+ namespace  {
4415+ static  void  skipWhitespace (const  char  *&Ptr) {
4416+   while  (isWhitespace (*Ptr))
4417+     ++Ptr;
4418+ }
4419+ 
4420+ //  Returns the length of EOL, either 0 (no end-of-line), 1 (\n) or 2 (\r\n).
4421+ static  unsigned  isEOL (const  char  *Ptr) {
4422+   if  (*Ptr == ' \0 '  )
4423+     return  0 ;
4424+   if  (*(Ptr + 1 ) != ' \0 '   && isVerticalWhitespace (Ptr[0 ]) &&
4425+       isVerticalWhitespace (Ptr[1 ]) && Ptr[0 ] != Ptr[1 ])
4426+     return  2 ;
4427+   return  !!isVerticalWhitespace (Ptr[0 ]);
4428+ }
4429+ 
4430+ static  void  skipLine (const  char  *&Ptr) {
4431+   for  (;;) {
4432+     char  LastNonWhitespace = '  '  ;
4433+     while  (!isVerticalWhitespace (*Ptr) && *Ptr != ' \0 '  ) {
4434+       if  (!isHorizontalWhitespace (*Ptr))
4435+         LastNonWhitespace = *Ptr;
4436+       ++Ptr;
4437+     }
4438+ 
4439+     const  unsigned  Len = isEOL (Ptr);
4440+     if  (!Len)
4441+       return ;
4442+ 
4443+     Ptr += Len;
4444+     if  (LastNonWhitespace != ' \\ '  )
4445+       break ;
4446+   }
4447+ }
4448+ 
4449+ //  Returns the length of a line splice sequence (including trailing
4450+ //  whitespace), or 0 if no line splice is found.
4451+ static  unsigned  isLineSplice (const  char  *Start) {
4452+   if  (*Start != ' \\ '  )
4453+     return  0 ;
4454+ 
4455+   const  char  *Ptr = Start + 1 ;
4456+   while  (isHorizontalWhitespace (*Ptr))
4457+     ++Ptr;
4458+ 
4459+   if  (unsigned  Len = isEOL (Ptr))
4460+     return  Ptr - Start + Len;
4461+   return  0 ;
4462+ }
4463+ 
4464+ static  bool  trySkipLineSplice (const  char  *&Ptr) {
4465+   if  (unsigned  Len = isLineSplice (Ptr); Len) {
4466+     Ptr += Len;
4467+     return  true ;
4468+   }
4469+   return  false ;
4470+ }
4471+ 
4472+ static  bool  trySkipDirective (const  char  *&Ptr) {
4473+   if  (*Ptr != ' #'  )
4474+     return  false ;
4475+ 
4476+   ++Ptr;
4477+   skipLine (Ptr);
4478+   return  true ;
4479+ }
4480+ 
4481+ static  bool  trySkipLineComment (const  char  *&Ptr) {
4482+   if  (Ptr[0 ] != ' /'   || Ptr[1 ] != ' /'  )
4483+     return  false ;
4484+ 
4485+   Ptr += 2 ;
4486+   skipLine (Ptr);
4487+   return  true ;
4488+ }
4489+ 
4490+ static  bool  trySkipBlockComment (const  char  *&Ptr) {
4491+   if  (Ptr[0 ] != ' /'   || Ptr[1 ] != ' *'  )
4492+     return  false ;
4493+ 
4494+   Ptr += 2 ;
4495+   while  (*Ptr != ' \0 '  ) {
4496+     if  (Ptr[0 ] == ' *'   && Ptr[1 ] == ' /'  ) {
4497+       Ptr += 2 ; //  '*/'
4498+       return  true ;
4499+     }
4500+     ++Ptr;
4501+   }
4502+   return  true ;
4503+ }
4504+ 
4505+ static  bool  trySkipComment (const  char  *&Ptr) {
4506+   return  trySkipLineComment (Ptr) || trySkipBlockComment (Ptr);
4507+ }
4508+ 
4509+ //  Skipps over comments and (non-module) directives
4510+ static  void  skipToRelevantCXXModuleText (const  char  *&Ptr) {
4511+   while  (*Ptr != ' \0 '  ) {
4512+     skipWhitespace (Ptr);
4513+     if  (trySkipComment (Ptr) || trySkipDirective (Ptr) || trySkipLineSplice (Ptr))
4514+       continue ;
4515+     break ; //  Found relevant text!
4516+   }
4517+ }
4518+ 
4519+ static  bool  scanBufferForCXXModuleUsage (const  llvm::MemoryBuffer &Buffer) {
4520+   const  char  *Ptr = Buffer.getBufferStart ();
4521+   skipToRelevantCXXModuleText (Ptr);
4522+ 
4523+   //  Check if buffer has enough bytes left to check for the module-related
4524+   //  declaration fragment we want to check without making potentially
4525+   //  memory-mapped buffer load unnecessary pages.
4526+   constexpr  int  MinKeywordLength = 6 ;
4527+   const  char  *Begin = Ptr;
4528+   for  (int  i = 0 ; i < MinKeywordLength; ++i) {
4529+     if  (*Ptr == ' \0 '  )
4530+       return  false ;
4531+     ++Ptr;
4532+   }
4533+   StringRef Text (Begin, MinKeywordLength);
4534+ 
4535+   const  bool  IsGlobalModule = Text.starts_with (" module"  );
4536+   if  (!IsGlobalModule && !Text.starts_with (" import"  ) &&
4537+       !Text.starts_with (" export"  ))
4538+     return  false ;
4539+ 
4540+   //  Ensure the keyword has a proper ending and isn't part of a identifier
4541+   //  or namespace. For this we might have to skip comments and line
4542+   //  continuations.
4543+   while  (*Ptr != ' \0 '  ) {
4544+     if  (isWhitespace (*Ptr) || (IsGlobalModule && *Ptr == ' ;'  ))
4545+       return  true ;
4546+     if  (trySkipBlockComment (Ptr) || trySkipLineSplice (Ptr))
4547+       continue ;
4548+     return  false ;
4549+   }
4550+ 
4551+   return  false ;
4552+ }
4553+ 
4554+ static  bool  hasCXXModuleInputType (const  Driver::InputList &Inputs) {
4555+   const  auto  IsTypeCXXModule = [](const  auto  &Input) -> bool  {
4556+     const  auto  TypeID = Input.first ;
4557+     return  (TypeID == types::TY_CXXModule);
4558+   };
4559+   return  llvm::any_of (Inputs, IsTypeCXXModule);
4560+ }
4561+ 
4562+ } //  anonymous namespace
4563+ 
4564+ llvm::ErrorOr<bool >
4565+ Driver::ScanInputsForCXXModuleUsage (const  InputList &Inputs) const  {
4566+   const  auto  CXXInputs = llvm::make_filter_range (
4567+       Inputs, [](const  auto  &Input) { return  types::isCXX (Input.first ); });
4568+ 
4569+   for  (const  auto  &Input : CXXInputs) {
4570+     StringRef Filename = Input.second ->getSpelling ();
4571+     auto  ErrOrBuffer = VFS->getBufferForFile (Filename);
4572+     if  (!ErrOrBuffer)
4573+       return  ErrOrBuffer.getError ();
4574+     const  auto  Buffer = std::move (*ErrOrBuffer);
4575+ 
4576+     if  (scanBufferForCXXModuleUsage (*Buffer)) {
4577+       Diags.Report (diag::remark_found_cxx20_module_usage) << Filename;
4578+       return  true ;
4579+     }
4580+   }
4581+ 
4582+   return  false ;
4583+ }
4584+ 
44064585void  Driver::BuildActions (Compilation &C, DerivedArgList &Args,
44074586                          const  InputList &Inputs, ActionList &Actions) const  {
44084587  llvm::PrettyStackTraceString CrashInfo (" Building compilation actions"  );
@@ -4414,6 +4593,34 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
44144593
44154594  handleArguments (C, Args, Inputs, Actions);
44164595
4596+   if  (Args.hasFlag (options::OPT_fmodules_driver,
4597+                    options::OPT_fno_modules_driver, false )) {
4598+     Diags.Report (diag::remark_fmodules_driver_enabled);
4599+     //  TODO: Move the logic for implicitly enabling explicit-module-builds out
4600+     //  of -fmodules-driver once it is no longer experimental.
4601+     //  Currently, this serves diagnostic purposes only.
4602+     bool  UsesCXXModules = hasCXXModuleInputType (Inputs);
4603+     if  (!UsesCXXModules) {
4604+       const  auto  ErrOrScanResult = ScanInputsForCXXModuleUsage (Inputs);
4605+       if  (!ErrOrScanResult) {
4606+         Diags.Report (diag::err_cannot_open_file)
4607+             << ErrOrScanResult.getError ().message ();
4608+         return ;
4609+       }
4610+       UsesCXXModules = *ErrOrScanResult;
4611+     }
4612+     if  (UsesCXXModules)
4613+       BuildExplicitModuleBuildActions (C, Args, Inputs, Actions);
4614+     return ;
4615+   }
4616+ 
4617+   Driver::BuildDefaultActions (C, Args, Inputs, Actions);
4618+ }
4619+ 
4620+ void  Driver::BuildDefaultActions (Compilation &C, DerivedArgList &Args,
4621+                                  const  InputList &Inputs,
4622+                                  ActionList &Actions) const  {
4623+ 
44174624  bool  UseNewOffloadingDriver =
44184625      C.isOffloadingHostKind (Action::OFK_OpenMP) ||
44194626      C.isOffloadingHostKind (Action::OFK_SYCL) ||
@@ -4693,6 +4900,14 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
46934900  Args.ClaimAllArgs (options::OPT_cl_ignored_Group);
46944901}
46954902
4903+ void  Driver::BuildExplicitModuleBuildActions (Compilation &C,
4904+                                              llvm::opt::DerivedArgList &Args,
4905+                                              const  InputList &Inputs,
4906+                                              ActionList &Actions) const  {
4907+   Diags.Report (diag::remark_performing_explicit_module_build);
4908+   return ;
4909+ }
4910+ 
46964911// / Returns the canonical name for the offloading architecture when using a HIP
46974912// / or CUDA architecture.
46984913static  StringRef getCanonicalArchString (Compilation &C,
0 commit comments