jansvoboda11 updated this revision to Diff 317003.
jansvoboda11 added a comment.
Herald added subscribers: llvm-commits, hiraditya.
Herald added a project: LLVM.

Add (improved) round-trip mechanism


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D94472/new/

https://reviews.llvm.org/D94472

Files:
  clang/include/clang/Frontend/CompilerInvocation.h
  clang/lib/Frontend/CompilerInvocation.cpp
  llvm/include/llvm/Option/ArgList.h
  llvm/lib/Option/ArgList.cpp

Index: llvm/lib/Option/ArgList.cpp
===================================================================
--- llvm/lib/Option/ArgList.cpp
+++ llvm/lib/Option/ArgList.cpp
@@ -90,11 +90,22 @@
 }
 
 std::vector<std::string> ArgList::getAllArgValues(OptSpecifier Id) const {
+  recordQueriedOpts(Id);
   SmallVector<const char *, 16> Values;
   AddAllArgValues(Values, Id);
   return std::vector<std::string>(Values.begin(), Values.end());
 }
 
+void ArgList::AddAllArgsExcept(ArgStringList &Output,
+                               const DenseSet<unsigned> &ExcludeIds) const {
+  for (const Arg *Arg : *this) {
+    if (!ExcludeIds.contains(Arg->getOption().getID())) {
+      Arg->claim();
+      Arg->render(*this, Output);
+    }
+  }
+}
+
 void ArgList::AddAllArgsExcept(ArgStringList &Output,
                                ArrayRef<OptSpecifier> Ids,
                                ArrayRef<OptSpecifier> ExcludeIds) const {
Index: llvm/include/llvm/Option/ArgList.h
===================================================================
--- llvm/include/llvm/Option/ArgList.h
+++ llvm/include/llvm/Option/ArgList.h
@@ -137,6 +137,16 @@
   /// The first and last index of each different OptSpecifier ID.
   DenseMap<unsigned, OptRange> OptRanges;
 
+  /// The OptSpecifiers that were queried from this argument list.
+  mutable DenseSet<unsigned> QueriedOpts;
+
+  /// Record the queried OptSpecifiers.
+  template <typename... OptSpecifiers>
+  void recordQueriedOpts(OptSpecifiers... Ids) const {
+    SmallVector<unsigned, 4> OptsSpecifiers({toOptSpecifier(Ids).getID()...});
+    QueriedOpts.insert(OptsSpecifiers.begin(), OptsSpecifiers.end());
+  }
+
   /// Get the range of indexes in which options with the specified IDs might
   /// reside, or (0, 0) if there are no such options.
   OptRange getRange(std::initializer_list<OptSpecifier> Ids) const;
@@ -203,6 +213,7 @@
   template<typename ...OptSpecifiers>
   iterator_range<filtered_iterator<sizeof...(OptSpecifiers)>>
   filtered(OptSpecifiers ...Ids) const {
+    recordQueriedOpts(Ids...);
     OptRange Range = getRange({toOptSpecifier(Ids)...});
     auto B = Args.begin() + Range.first;
     auto E = Args.begin() + Range.second;
@@ -214,6 +225,7 @@
   template<typename ...OptSpecifiers>
   iterator_range<filtered_reverse_iterator<sizeof...(OptSpecifiers)>>
   filtered_reverse(OptSpecifiers ...Ids) const {
+    recordQueriedOpts(Ids...);
     OptRange Range = getRange({toOptSpecifier(Ids)...});
     auto B = Args.rend() - Range.second;
     auto E = Args.rend() - Range.first;
@@ -308,6 +320,10 @@
       A->render(*this, Output);
   }
 
+  /// AddAllArgsExcept - Render all arguments not matching any of the excluded
+  /// ids.
+  void AddAllArgsExcept(ArgStringList &Output,
+                        const DenseSet<unsigned> &ExcludeIds) const;
   /// AddAllArgsExcept - Render all arguments matching any of the given ids
   /// and not matching any of the excluded ids.
   void AddAllArgsExcept(ArgStringList &Output, ArrayRef<OptSpecifier> Ids,
@@ -342,6 +358,9 @@
   ///
   void ClaimAllArgs() const;
 
+  /// Return the OptSpecifiers queried from this argument list.
+  const DenseSet<unsigned> &getQueriedOpts() const { return QueriedOpts; }
+
   /// @}
   /// @name Arg Synthesis
   /// @{
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -48,10 +48,12 @@
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/CachedHashString.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/FloatingPointMode.h"
 #include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SetOperations.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
@@ -1812,9 +1814,9 @@
   return Driver::GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR);
 }
 
-static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
-                                     SmallVectorImpl<const char *> &Args,
-                                     CompilerInvocation::StringAllocator SA) {
+void CompilerInvocation::GenerateHeaderSearchArgs(
+    const HeaderSearchOptions &Opts, SmallVectorImpl<const char *> &Args,
+    CompilerInvocation::StringAllocator SA) {
   const HeaderSearchOptions *HeaderSearchOpts = &Opts;
 #define HEADER_SEARCH_OPTION_WITH_MARSHALLING(                                 \
     PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,        \
@@ -1826,6 +1828,118 @@
       IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
 #include "clang/Driver/Options.inc"
 #undef HEADER_SEARCH_OPTION_WITH_MARSHALLING
+
+  const OptTable &OptTable = getDriverOptTable();
+
+  std::string Dash("-");
+  std::string OptName;
+
+  if (Opts.UseLibcxx) {
+    OptName = Dash + OptTable.getOptionName(OPT_stdlib_EQ);
+    Args.emplace_back(SA(OptName + "libc++"));
+  }
+
+  if (!Opts.ModuleCachePath.empty()) {
+    OptName = Dash + OptTable.getOptionName(OPT_fmodules_cache_path);
+    Args.emplace_back(SA(OptName + Opts.ModuleCachePath));
+  }
+
+  OptName = Dash + OptTable.getOptionName(OPT_fmodule_file);
+  for (const auto &File : Opts.PrebuiltModuleFiles)
+    Args.emplace_back(SA(OptName + File.first + "=" + File.second));
+
+  OptName = Dash + OptTable.getOptionName(OPT_fprebuilt_module_path);
+  for (const auto &Path : Opts.PrebuiltModulePaths)
+    Args.emplace_back(SA(OptName + Path));
+
+  OptName = Dash + OptTable.getOptionName(OPT_fmodules_ignore_macro);
+  for (const auto &Macro : Opts.ModulesIgnoreMacros)
+    Args.emplace_back(SA(OptName + Macro.val()));
+
+  auto matches = [](const HeaderSearchOptions::Entry &Entry,
+                    frontend::IncludeDirGroup Group, bool IsFramework,
+                    bool IgnoreSysRoot) {
+    return Entry.Group == Group && Entry.IsFramework == IsFramework &&
+           Entry.IgnoreSysRoot == IgnoreSysRoot;
+  };
+
+  for (const HeaderSearchOptions::Entry &E : Opts.UserEntries) {
+    Optional<OptSpecifier> Opt;
+
+    // Add -I..., -F..., and -index-header-map options in order.
+
+    if (E.Group == frontend::IndexHeaderMap) {
+      OptName = OptTable.getOptionName(OPT_index_header_map);
+      Args.emplace_back(SA(OptName));
+    }
+
+    if (matches(E, frontend::IndexHeaderMap, true, true))
+      Opt = OPT_F;
+    else if (matches(E, frontend::IndexHeaderMap, false, true))
+      Opt = OPT_I;
+    else if (matches(E, frontend::Angled, true, true))
+      Opt = OPT_F;
+    else if (matches(E, frontend::Angled, false, true))
+      // Also handles [-iprefix=xx] -iwithprefixbefore=yy as -I[xx]yy.
+      Opt = OPT_I;
+
+    if (Opt) {
+      OptName = Dash + OptTable.getOptionName(*Opt);
+      Args.emplace_back(SA(OptName + E.Path));
+      continue;
+    }
+
+    if (matches(E, frontend::After, false, true))
+      // Also handles [-iprefix=xx] -iwithprefix=yy as -idirafter=[xx]yy.
+      Opt = OPT_idirafter;
+    else if (matches(E, frontend::Quoted, false, true))
+      Opt = OPT_iquote;
+    else if (matches(E, frontend::System, false, true))
+      Opt = OPT_isystem;
+    else if (matches(E, frontend::System, false, false))
+      Opt = OPT_iwithsysroot;
+    else if (matches(E, frontend::System, true, true))
+      Opt = OPT_iframework;
+    else if (matches(E, frontend::System, true, false))
+      Opt = OPT_iframeworkwithsysroot;
+
+    else if (matches(E, frontend::CSystem, false, true))
+      // Add the paths for the various language specific isystem flags.
+      Opt = OPT_c_isystem;
+    else if (matches(E, frontend::CXXSystem, false, true))
+      Opt = OPT_cxx_isystem;
+    else if (matches(E, frontend::ObjCSystem, false, true))
+      Opt = OPT_objc_isystem;
+    else if (matches(E, frontend::ObjCXXSystem, false, true))
+      Opt = OPT_objcxx_isystem;
+
+    else if (matches(E, frontend::System, false, true))
+      // Add the internal paths from a driver that detects standard include
+      // paths.
+      Opt = OPT_internal_isystem;
+    else if (matches(E, frontend::ExternCSystem, false, true))
+      Opt = OPT_internal_externc_isystem;
+    else
+      llvm_unreachable("Tried to marshall invalid HeaderSearchOptions::Entry");
+
+    OptName = Dash + OptTable.getOptionName(*Opt);
+    Args.emplace_back(SA(OptName));
+    Args.emplace_back(SA(E.Path));
+  }
+
+  // Add the path prefixes which are implicitly treated as being system headers.
+  for (const auto &P : Opts.SystemHeaderPrefixes) {
+    OptSpecifier Opt = P.IsSystemHeader ? OPT_system_header_prefix
+                                        : OPT_no_system_header_prefix;
+    OptName = Dash + Dash + OptTable.getOptionName(Opt);
+    Args.emplace_back(SA(OptName + P.Prefix));
+  }
+
+  for (const std::string &F : Opts.VFSOverlayFiles) {
+    OptName = Dash + OptTable.getOptionName(OPT_ivfsoverlay);
+    Args.emplace_back(SA(OptName));
+    Args.emplace_back(SA(F));
+  }
 }
 
 static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
@@ -2992,6 +3106,48 @@
   }
 }
 
+template <typename ParseFn, typename GenerateFn, typename ResetFn>
+void RoundTrip(ParseFn &&Parse, GenerateFn &&Generate, ResetFn &&Reset,
+               CompilerInvocation &Res, InputArgList &OriginalArgs) {
+  // Set up the string allocator for generating command line arguments.
+  SmallVector<std::string, 32> GeneratedArgsStorage;
+  auto SA = [&GeneratedArgsStorage](const Twine &Arg) -> const char * {
+    return GeneratedArgsStorage.emplace_back(Arg.str()).c_str();
+  };
+
+  // Parse the original arguments and records which options the parser queried.
+  llvm::DenseSet<unsigned> QueriedBefore = OriginalArgs.getQueriedOpts();
+  Parse(Res, OriginalArgs);
+  llvm::DenseSet<unsigned> QueriedAfter = OriginalArgs.getQueriedOpts();
+  llvm::DenseSet<unsigned> QueriedDuring =
+      llvm::set_difference(QueriedAfter, QueriedBefore);
+
+  // Create an empty string list.
+  ArgStringList GeneratedArgStringList;
+  // Add all original arguments that were not queried by the parser.
+  OriginalArgs.AddAllArgsExcept(GeneratedArgStringList, QueriedDuring);
+  // Invoke the generator. If implemented correctly, it should complete the
+  // string list with arguments the parser queried, and have the same
+  // semantics as the original arguments.
+  Generate(Res, GeneratedArgStringList, SA);
+
+  // Construct InputArgList instance from the generated string list.
+  const OptTable &Opts = getDriverOptTable();
+  unsigned MissingArgIndex, MissingArgCount;
+  InputArgList GeneratedArgs =
+      Opts.ParseArgs(GeneratedArgStringList, MissingArgIndex, MissingArgCount,
+                     options::CC1Option);
+
+  // Reset the part of CompilerInvocation that the parser set up.
+  Reset(Res);
+
+  // Run the parser again. If the generated arguments have the same semantics
+  // as the original arguments, this should set up the CompilerInvocation part
+  // in the same way the first parser call did. Let's verify that by using this
+  // for the rest of the compilation process.
+  Parse(Res, GeneratedArgs);
+}
+
 bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
                                         ArrayRef<const char *> CommandLineArgs,
                                         DiagnosticsEngine &Diags,
@@ -3042,8 +3198,22 @@
                                       LangOpts.IsHeaderFile);
   ParseTargetArgs(Res.getTargetOpts(), Args, Diags);
   llvm::Triple T(Res.getTargetOpts().Triple);
-  ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Diags,
-                        Res.getFileSystemOpts().WorkingDir);
+
+  auto ParseHS = [&Diags](CompilerInvocation &Res, InputArgList &Args) {
+    ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Diags,
+                          Res.getFileSystemOpts().WorkingDir);
+  };
+  auto GenerateHS = [](CompilerInvocation &Res,
+                       SmallVectorImpl<const char *> &Args,
+                       StringAllocator SA) {
+    GenerateHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, SA);
+  };
+  auto ResetHS = [](CompilerInvocation &Res) {
+    auto EmptyHeaderSearchOpts = std::make_shared<HeaderSearchOptions>();
+    Res.HeaderSearchOpts.swap(EmptyHeaderSearchOpts);
+  };
+
+  RoundTrip(ParseHS, GenerateHS, ResetHS, Res, Args);
   if (DashX.getFormat() == InputKind::Precompiled ||
       DashX.getLanguage() == Language::LLVM_IR) {
     // ObjCAAutoRefCount and Sanitize LangOpts are used to setup the
Index: clang/include/clang/Frontend/CompilerInvocation.h
===================================================================
--- clang/include/clang/Frontend/CompilerInvocation.h
+++ clang/include/clang/Frontend/CompilerInvocation.h
@@ -260,6 +260,10 @@
                                const llvm::Triple &T,
                                const std::string &OutputFile,
                                const LangOptions &LangOptsRef);
+
+  static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
+                                       SmallVectorImpl<const char *> &Args,
+                                       CompilerInvocation::StringAllocator SA);
 };
 
 IntrusiveRefCntPtr<llvm::vfs::FileSystem>
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D94472: [c... Jan Svoboda via Phabricator via cfe-commits
    • [PATCH] D9447... Duncan P. N. Exon Smith via Phabricator via cfe-commits
    • [PATCH] D9447... Jan Svoboda via Phabricator via cfe-commits

Reply via email to