<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On 29 June 2016 at 22:48, Zachary Turner via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Author: zturner<br>
Date: Wed Jun 29 16:48:26 2016<br>
New Revision: 274171<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=274171&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=274171&view=rev</a><br>
Log:<br>
Resubmit "Update llvm command line parser to support subcommands."<br>
<br>
This fixes an issue where occurrence counts would be unexpectedly<br>
reset when parsing different parts of a command line multiple<br>
times.<br>
<br>
**ORIGINAL COMMIT MESSAGE**<br>
<br>
This allows command line tools to use syntaxes like the following:<br>
<br>
      llvm-foo.exe command1 -o1 -o2<br>
      llvm-foo.exe command2 -p1 -p2<br>
<br>
Where command1 and command2 contain completely different sets of<br>
valid options.  This is backwards compatible with previous uses<br>
of llvm cl which did not support subcommands, as any option<br>
which specifies no optional subcommand (e.g. all existing<br>
code) goes into a special "top level" subcommand that expects<br>
dashed options to appear immediately after the program name.<br>
For example, code which is subcommand unaware would generate<br>
a command line such as the following, where no subcommand<br>
is specified:<br>
<br>
      llvm-foo.exe -q1 -q2<br>
<br>
The top level subcommand can co-exist with actual subcommands,<br>
as it is implemented as an actual subcommand which is searched<br>
if no explicit subcommand is specified.  So llvm-foo.exe as<br>
specified above could be written so as to support all three<br>
aforementioned command lines simultaneously.<br>
<br>
There is one additional "special" subcommand called AllSubCommands,<br>
which can be used to inject an option into every subcommand.<br>
This is useful to support things like help, so that commands<br>
such as:<br>
<br>
      llvm-foo.exe --help<br>
      llvm-foo.exe command1 --help<br>
      llvm-foo.exe command2 --help<br>
<br>
All work and display the help for the selected subcommand<br>
without having to explicitly go and write code to handle each<br>
one separately.<br>
<br>
This patch is submitted without an example of anything actually<br>
using subcommands, but a followup patch will convert the<br>
llvm-pdbdump tool to use subcommands.<br>
<br>
Reviewed By: beanz<br>
<br>
Modified:<br>
    llvm/trunk/include/llvm/<wbr>Support/CommandLine.h<br>
    llvm/trunk/lib/Support/<wbr>CommandLine.cpp<br>
    llvm/trunk/unittests/Support/<wbr>CommandLineTest.cpp<br>
    llvm/trunk/unittests/Support/<wbr>ProgramTest.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/<wbr>Support/CommandLine.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/CommandLine.h?rev=274171&r1=274170&r2=274171&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/include/<wbr>llvm/Support/CommandLine.h?<wbr>rev=274171&r1=274170&r2=<wbr>274171&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/include/llvm/<wbr>Support/CommandLine.h (original)<br>
+++ llvm/trunk/include/llvm/<wbr>Support/CommandLine.h Wed Jun 29 16:48:26 2016<br>
@@ -21,10 +21,12 @@<br>
 #define LLVM_SUPPORT_COMMANDLINE_H<br>
<br>
 #include "llvm/ADT/ArrayRef.h"<br>
+#include "llvm/ADT/SmallPtrSet.h"<br>
 #include "llvm/ADT/SmallVector.h"<br>
 #include "llvm/ADT/StringMap.h"<br>
 #include "llvm/ADT/Twine.h"<br>
 #include "llvm/Support/Compiler.h"<br>
+#include "llvm/Support/ManagedStatic.h"<br>
 #include <cassert><br>
 #include <climits><br>
 #include <cstdarg><br>
@@ -43,8 +45,9 @@ namespace cl {<br>
 //===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
 // ParseCommandLineOptions - Command line option processing entry point.<br>
 //<br>
-void ParseCommandLineOptions(int argc, const char *const *argv,<br>
-                             const char *Overview = nullptr);<br>
+bool ParseCommandLineOptions(int argc, const char *const *argv,<br>
+                             const char *Overview = nullptr,<br>
+                             bool IgnoreErrors = false);<br>
<br>
 //===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
 // ParseEnvironmentOptions - Environment variable option processing alternate<br>
@@ -171,6 +174,45 @@ public:<br>
 extern OptionCategory GeneralCategory;<br>
<br>
 //===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
+// SubCommand class<br>
+//<br>
+class SubCommand {<br>
+private:<br>
+  const char *const Name = nullptr;<br>
+  const char *const Description = nullptr;<br>
+<br>
+protected:<br>
+  void registerSubCommand();<br>
+  void unregisterSubCommand();<br>
+<br>
+public:<br>
+  SubCommand(const char *const Name, const char *const Description = nullptr)<br>
+      : Name(Name), Description(Description) {<br>
+    registerSubCommand();<br>
+  }<br>
+  SubCommand() {}<br>
+<br>
+  void reset();<br>
+<br>
+  operator bool() const;<br>
+<br>
+  const char *getName() const { return Name; }<br>
+  const char *getDescription() const { return Description; }<br>
+<br>
+  SmallVector<Option *, 4> PositionalOpts;<br>
+  SmallVector<Option *, 4> SinkOpts;<br>
+  StringMap<Option *> OptionsMap;<br>
+<br>
+  Option *ConsumeAfterOpt = nullptr; // The ConsumeAfter option if it exists.<br>
+};<br>
+<br>
+// A special subcommand representing no subcommand<br>
+extern ManagedStatic<SubCommand> TopLevelSubCommand;<br>
+<br>
+// A special subcommand that can be used to put an option into all subcommands.<br>
+extern ManagedStatic<SubCommand> AllSubCommands;<br>
+<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
 // Option Base class<br>
 //<br>
 class alias;<br>
@@ -209,6 +251,7 @@ public:<br>
   StringRef HelpStr;  // The descriptive text message for -help<br>
   StringRef ValueStr; // String describing what the value of this option is<br>
   OptionCategory *Category; // The Category this option belongs to<br>
+  SmallPtrSet<SubCommand *, 4> Subs; // The subcommands this option belongs to.<br>
   bool FullyInitialized;    // Has addArguemnt been called?<br>
<br>
   inline enum NumOccurrencesFlag getNumOccurrencesFlag() const {<br>
@@ -229,6 +272,16 @@ public:<br>
<br>
   // hasArgStr - Return true if the argstr != ""<br>
   bool hasArgStr() const { return !ArgStr.empty(); }<br>
+  bool isPositional() const { return getFormattingFlag() == cl::Positional; }<br>
+  bool isSink() const { return getMiscFlags() & cl::Sink; }<br>
+  bool isConsumeAfter() const {<br>
+    return getNumOccurrencesFlag() == cl::ConsumeAfter;<br>
+  }<br>
+  bool isInAllSubCommands() const {<br>
+    return std::any_of(Subs.begin(), Subs.end(), [](const SubCommand *SC) {<br>
+      return SC == &*AllSubCommands;<br>
+    });<br>
+  }<br>
<br>
   //----------------------------<wbr>------------------------------<wbr>---------------===<br>
   // Accessor functions set by OptionModifiers<br>
@@ -243,6 +296,7 @@ public:<br>
   void setMiscFlag(enum MiscFlags M) { Misc |= M; }<br>
   void setPosition(unsigned pos) { Position = pos; }<br>
   void setCategory(OptionCategory &C) { Category = &C; }<br>
+  void addSubCommand(SubCommand &S) { Subs.insert(&S); }<br>
<br>
 protected:<br>
   explicit Option(enum NumOccurrencesFlag OccurrencesFlag,<br>
@@ -287,6 +341,7 @@ public:<br>
<br>
 public:<br>
   inline int getNumOccurrences() const { return NumOccurrences; }<br>
+  inline void reset() { NumOccurrences = 0; }<br>
   virtual ~Option() {}<br>
 };<br>
<br>
@@ -349,6 +404,14 @@ struct cat {<br>
   template <class Opt> void apply(Opt &O) const { O.setCategory(Category); }<br>
 };<br>
<br>
+// sub - Specify the subcommand that this option belongs to.<br>
+struct sub {<br>
+  SubCommand &Sub;<br>
+  sub(SubCommand &S) : Sub(S) {}<br>
+<br>
+  template <class Opt> void apply(Opt &O) const { O.addSubCommand(Sub); }<br>
+};<br>
+<br>
 //===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
 // OptionValue class<br>
<br>
@@ -1589,6 +1652,7 @@ class alias : public Option {<br>
       error("cl::alias must have argument name specified!");<br>
     if (!AliasFor)<br>
       error("cl::alias must have an cl::aliasopt(option) specified!");<br>
+    Subs = AliasFor->Subs;<br>
     addArgument();<br>
   }<br>
<br>
@@ -1669,7 +1733,7 @@ void PrintHelpMessage(bool Hidden = fals<br>
 /// Hopefully this API can be depricated soon. Any situation where options need<br>
 /// to be modified by tools or libraries should be handled by sane APIs rather<br>
 /// than just handing around a global list.<br>
-StringMap<Option *> &getRegisteredOptions();<br>
+StringMap<Option *> &getRegisteredOptions(<wbr>SubCommand &Sub);<br>
<br>
 //===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
 // Standalone command line processing utilities.<br>
@@ -1737,7 +1801,8 @@ bool ExpandResponseFiles(<wbr>StringSaver &Sa<br>
 /// Some tools (like clang-format) like to be able to hide all options that are<br>
 /// not specific to the tool. This function allows a tool to specify a single<br>
 /// option category to display in the -help output.<br>
-void HideUnrelatedOptions(cl::<wbr>OptionCategory &Category);<br>
+void HideUnrelatedOptions(cl::<wbr>OptionCategory &Category,<br>
+                          SubCommand &Sub = *TopLevelSubCommand);<br>
<br>
 /// \brief Mark all options not part of the categories as cl::ReallyHidden.<br>
 ///<br>
@@ -1746,7 +1811,19 @@ void HideUnrelatedOptions(cl::<wbr>OptionCate<br>
 /// Some tools (like clang-format) like to be able to hide all options that are<br>
 /// not specific to the tool. This function allows a tool to specify a single<br>
 /// option category to display in the -help output.<br>
-void HideUnrelatedOptions(ArrayRef<<wbr>const cl::OptionCategory *> Categories);<br>
+void HideUnrelatedOptions(ArrayRef<<wbr>const cl::OptionCategory *> Categories,<br>
+                          SubCommand &Sub = *TopLevelSubCommand);<br>
+<br>
+/// \brief Reset all command line options to a state that looks as if they have<br>
+/// never appeared on the command line.  This is useful for being able to parse<br>
+/// a command line multiple times (especially useful for writing tests).<br>
+void ResetAllOptionOccurrences();<br>
+<br>
+/// \brief Reset the command line parser back to its initial state.  This<br>
+/// removes<br>
+/// all options, categories, and subcommands and returns the parser to a state<br>
+/// where no options are supported.<br>
+void ResetCommandLineParser();<br>
<br>
 } // End namespace cl<br>
<br>
<br>
Modified: llvm/trunk/lib/Support/<wbr>CommandLine.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CommandLine.cpp?rev=274171&r1=274170&r2=274171&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/lib/<wbr>Support/CommandLine.cpp?rev=<wbr>274171&r1=274170&r2=274171&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Support/<wbr>CommandLine.cpp (original)<br>
+++ llvm/trunk/lib/Support/<wbr>CommandLine.cpp Wed Jun 29 16:48:26 2016<br>
@@ -19,6 +19,7 @@<br>
 #include "llvm/Support/CommandLine.h"<br>
 #include "llvm-c/Support.h"<br>
 #include "llvm/ADT/ArrayRef.h"<br>
+#include "llvm/ADT/DenseMap.h"<br>
 #include "llvm/ADT/STLExtras.h"<br>
 #include "llvm/ADT/SmallPtrSet.h"<br>
 #include "llvm/ADT/SmallString.h"<br>
@@ -94,35 +95,56 @@ public:<br>
   // This collects additional help to be printed.<br>
   std::vector<const char *> MoreHelp;<br>
<br>
-  SmallVector<Option *, 4> PositionalOpts;<br>
-  SmallVector<Option *, 4> SinkOpts;<br>
-  StringMap<Option *> OptionsMap;<br>
-<br>
-  Option *ConsumeAfterOpt; // The ConsumeAfter option if it exists.<br>
-<br>
   // This collects the different option categories that have been registered.<br>
   SmallPtrSet<OptionCategory *, 16> RegisteredOptionCategories;<br>
<br>
-  CommandLineParser() : ProgramOverview(nullptr), ConsumeAfterOpt(nullptr) {}<br>
+  // This collects the different subcommands that have been registered.<br>
+  SmallPtrSet<SubCommand *, 4> RegisteredSubCommands;<br>
<br>
-  void ParseCommandLineOptions(int argc, const char *const *argv,<br>
-                               const char *Overview);<br>
+  CommandLineParser() : ProgramOverview(nullptr), ActiveSubCommand(nullptr) {<br>
+    registerSubCommand(&*<wbr>TopLevelSubCommand);<br>
+    registerSubCommand(&*<wbr>AllSubCommands);<br>
+  }<br>
<br>
-  void addLiteralOption(Option &Opt, const char *Name) {<br>
-    if (!Opt.hasArgStr()) {<br>
-      if (!OptionsMap.insert(std::make_<wbr>pair(Name, &Opt)).second) {<br>
-        errs() << ProgramName << ": CommandLine Error: Option '" << Name<br>
-               << "' registered more than once!\n";<br>
-        report_fatal_error("<wbr>inconsistency in registered CommandLine options");<br>
+  void ResetAllOptionOccurrences();<br>
+<br>
+  bool ParseCommandLineOptions(int argc, const char *const *argv,<br>
+                               const char *Overview, bool IgnoreErrors);<br>
+<br>
+  void addLiteralOption(Option &Opt, SubCommand *SC, const char *Name) {<br>
+    if (Opt.hasArgStr())<br>
+      return;<br>
+    if (!SC->OptionsMap.insert(std::<wbr>make_pair(Name, &Opt)).second) {<br>
+      errs() << ProgramName << ": CommandLine Error: Option '" << Name<br>
+             << "' registered more than once!\n";<br>
+      report_fatal_error("<wbr>inconsistency in registered CommandLine options");<br>
+    }<br>
+<br>
+    // If we're adding this to all sub-commands, add it to the ones that have<br>
+    // already been registered.<br>
+    if (SC == &*AllSubCommands) {<br>
+      for (const auto &Sub : RegisteredSubCommands) {<br>
+        if (SC == Sub)<br>
+          continue;<br>
+        addLiteralOption(Opt, Sub, Name);<br>
       }<br>
     }<br>
   }<br>
<br>
-  void addOption(Option *O) {<br>
+  void addLiteralOption(Option &Opt, const char *Name) {<br>
+    if (Opt.Subs.empty())<br>
+      addLiteralOption(Opt, &*TopLevelSubCommand, Name);<br>
+    else {<br>
+      for (auto SC : Opt.Subs)<br>
+        addLiteralOption(Opt, SC, Name);<br>
+    }<br>
+  }<br>
+<br>
+  void addOption(Option *O, SubCommand *SC) {<br>
     bool HadErrors = false;<br>
     if (O->hasArgStr()) {<br>
       // Add argument to the argument map!<br>
-      if (!OptionsMap.insert(std::make_<wbr>pair(O->ArgStr, O)).second) {<br>
+      if (!SC->OptionsMap.insert(std::<wbr>make_pair(O->ArgStr, O)).second) {<br>
         errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr<br>
                << "' registered more than once!\n";<br>
         HadErrors = true;<br>
@@ -131,15 +153,15 @@ public:<br>
<br>
     // Remember information about positional options.<br>
     if (O->getFormattingFlag() == cl::Positional)<br>
-      PositionalOpts.push_back(O);<br>
+      SC->PositionalOpts.push_back(<wbr>O);<br>
     else if (O->getMiscFlags() & cl::Sink) // Remember sink options<br>
-      SinkOpts.push_back(O);<br>
+      SC->SinkOpts.push_back(O);<br>
     else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) {<br>
-      if (ConsumeAfterOpt) {<br>
+      if (SC->ConsumeAfterOpt) {<br>
         O->error("Cannot specify more than one option with cl::ConsumeAfter!");<br>
         HadErrors = true;<br>
       }<br>
-      ConsumeAfterOpt = O;<br>
+      SC->ConsumeAfterOpt = O;<br>
     }<br>
<br>
     // Fail hard if there were errors. These are strictly unrecoverable and<br>
@@ -148,47 +170,102 @@ public:<br>
     // linked LLVM distribution.<br>
     if (HadErrors)<br>
       report_fatal_error("<wbr>inconsistency in registered CommandLine options");<br>
+<br>
+    // If we're adding this to all sub-commands, add it to the ones that have<br>
+    // already been registered.<br>
+    if (SC == &*AllSubCommands) {<br>
+      for (const auto &Sub : RegisteredSubCommands) {<br>
+        if (SC == Sub)<br>
+          continue;<br>
+        addOption(O, Sub);<br>
+      }<br>
+    }<br>
   }<br>
<br>
-  void removeOption(Option *O) {<br>
+  void addOption(Option *O) {<br>
+    if (O->Subs.empty()) {<br>
+      addOption(O, &*TopLevelSubCommand);<br>
+    } else {<br>
+      for (auto SC : O->Subs)<br>
+        addOption(O, SC);<br>
+    }<br>
+  }<br>
+<br>
+  void removeOption(Option *O, SubCommand *SC) {<br>
     SmallVector<StringRef, 16> OptionNames;<br>
     O->getExtraOptionNames(<wbr>OptionNames);<br>
     if (O->hasArgStr())<br>
       OptionNames.push_back(O-><wbr>ArgStr);<br>
+<br>
+    SubCommand &Sub = *SC;<br>
     for (auto Name : OptionNames)<br>
-      OptionsMap.erase(Name);<br>
+      Sub.OptionsMap.erase(Name);<br>
<br>
     if (O->getFormattingFlag() == cl::Positional)<br>
-      for (auto Opt = PositionalOpts.begin(); Opt != PositionalOpts.end();<br>
-           ++Opt) {<br>
+      for (auto Opt = Sub.PositionalOpts.begin();<br>
+           Opt != Sub.PositionalOpts.end(); ++Opt) {<br>
         if (*Opt == O) {<br>
-          PositionalOpts.erase(Opt);<br>
+          Sub.PositionalOpts.erase(Opt);<br>
           break;<br>
         }<br>
       }<br>
     else if (O->getMiscFlags() & cl::Sink)<br>
-      for (auto Opt = SinkOpts.begin(); Opt != SinkOpts.end(); ++Opt) {<br>
+      for (auto Opt = Sub.SinkOpts.begin(); Opt != Sub.SinkOpts.end(); ++Opt) {<br>
         if (*Opt == O) {<br>
-          SinkOpts.erase(Opt);<br>
+          Sub.SinkOpts.erase(Opt);<br>
           break;<br>
         }<br>
       }<br>
-    else if (O == ConsumeAfterOpt)<br>
-      ConsumeAfterOpt = nullptr;<br>
+    else if (O == Sub.ConsumeAfterOpt)<br>
+      Sub.ConsumeAfterOpt = nullptr;<br>
   }<br>
<br>
-  bool hasOptions() {<br>
-    return (!OptionsMap.empty() || !PositionalOpts.empty() ||<br>
-            nullptr != ConsumeAfterOpt);<br>
+  void removeOption(Option *O) {<br>
+    if (O->Subs.empty())<br>
+      removeOption(O, &*TopLevelSubCommand);<br>
+    else {<br>
+      if (O->isInAllSubCommands()) {<br>
+        for (auto SC : RegisteredSubCommands)<br>
+          removeOption(O, SC);<br>
+      } else {<br>
+        for (auto SC : O->Subs)<br>
+          removeOption(O, SC);<br>
+      }<br>
+    }<br>
   }<br>
<br>
-  void updateArgStr(Option *O, StringRef NewName) {<br>
-    if (!OptionsMap.insert(std::make_<wbr>pair(NewName, O)).second) {<br>
+  bool hasOptions(const SubCommand &Sub) const {<br>
+    return (!Sub.OptionsMap.empty() || !Sub.PositionalOpts.empty() ||<br>
+            nullptr != Sub.ConsumeAfterOpt);<br>
+  }<br>
+<br>
+  bool hasOptions() const {<br>
+    for (const auto &S : RegisteredSubCommands) {<br>
+      if (hasOptions(*S))<br>
+        return true;<br>
+    }<br>
+    return false;<br>
+  }<br>
+<br>
+  SubCommand *getActiveSubCommand() { return ActiveSubCommand; }<br>
+<br>
+  void updateArgStr(Option *O, StringRef NewName, SubCommand *SC) {<br>
+    SubCommand &Sub = *SC;<br>
+    if (!Sub.OptionsMap.insert(std::<wbr>make_pair(NewName, O)).second) {<br>
       errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr<br>
              << "' registered more than once!\n";<br>
       report_fatal_error("<wbr>inconsistency in registered CommandLine options");<br>
     }<br>
-    OptionsMap.erase(O->ArgStr);<br>
+    Sub.OptionsMap.erase(O-><wbr>ArgStr);<br>
+  }<br>
+<br>
+  void updateArgStr(Option *O, StringRef NewName) {<br>
+    if (O->Subs.empty())<br>
+      updateArgStr(O, NewName, &*TopLevelSubCommand);<br>
+    else {<br>
+      for (auto SC : O->Subs)<br>
+        updateArgStr(O, NewName, SC);<br>
+    }<br>
   }<br>
<br>
   void printOptionValues();<br>
@@ -203,8 +280,55 @@ public:<br>
     RegisteredOptionCategories.<wbr>insert(cat);<br>
   }<br>
<br>
+  void registerSubCommand(SubCommand *sub) {<br>
+    assert(count_if(<wbr>RegisteredSubCommands,<br>
+                    [sub](const SubCommand *Sub) {<br>
+                      return (sub->getName() != nullptr) &&<br>
+                             (Sub->getName() == sub->getName());<br>
+                    }) == 0 &&<br>
+           "Duplicate subcommands");<br>
+    RegisteredSubCommands.insert(<wbr>sub);<br>
+<br>
+    // For all options that have been registered for all subcommands, add the<br>
+    // option to this subcommand now.<br>
+    if (sub != &*AllSubCommands) {<br>
+      for (auto &E : AllSubCommands->OptionsMap) {<br>
+        Option *O = E.second;<br>
+        if ((O->isPositional() || O->isSink() || O->isConsumeAfter()) ||<br>
+            O->hasArgStr())<br>
+          addOption(O, sub);<br>
+        else<br>
+          addLiteralOption(*O, sub, E.first().str().c_str());<br>
+      }<br>
+    }<br>
+  }<br>
+<br>
+  void unregisterSubCommand(<wbr>SubCommand *sub) {<br>
+    RegisteredSubCommands.erase(<wbr>sub);<br>
+  }<br>
+<br>
+  void reset() {<br>
+    ActiveSubCommand = nullptr;<br>
+    ProgramName.clear();<br>
+    ProgramOverview = nullptr;<br>
+<br>
+    MoreHelp.clear();<br>
+    RegisteredOptionCategories.<wbr>clear();<br>
+<br>
+    ResetAllOptionOccurrences();<br>
+    RegisteredSubCommands.clear();<br>
+<br>
+    TopLevelSubCommand->reset();<br>
+    AllSubCommands->reset();<br>
+    registerSubCommand(&*<wbr>TopLevelSubCommand);<br>
+    registerSubCommand(&*<wbr>AllSubCommands);<br>
+  }<br>
+<br>
 private:<br>
-  Option *LookupOption(StringRef &Arg, StringRef &Value);<br>
+  SubCommand *ActiveSubCommand;<br>
+<br>
+  Option *LookupOption(SubCommand &Sub, StringRef &Arg, StringRef &Value);<br>
+  SubCommand *LookupSubCommand(const char *Name);<br>
 };<br>
<br>
 } // namespace<br>
@@ -239,6 +363,32 @@ void OptionCategory::<wbr>registerCategory()<br>
   GlobalParser-><wbr>registerCategory(this);<br>
 }<br>
<br>
+// A special subcommand representing no subcommand<br>
+ManagedStatic<SubCommand> llvm::cl::TopLevelSubCommand;<br>
+<br>
+// A special subcommand that can be used to put an option into all subcommands.<br>
+ManagedStatic<SubCommand> llvm::cl::AllSubCommands;<br>
+<br>
+void SubCommand::<wbr>registerSubCommand() {<br>
+  GlobalParser-><wbr>registerSubCommand(this);<br>
+}<br>
+<br>
+void SubCommand::<wbr>unregisterSubCommand() {<br>
+  GlobalParser-><wbr>unregisterSubCommand(this);<br>
+}<br>
+<br>
+void SubCommand::reset() {<br>
+  PositionalOpts.clear();<br>
+  SinkOpts.clear();<br>
+  OptionsMap.clear();<br>
+<br>
+  ConsumeAfterOpt = nullptr;<br>
+}<br>
+<br>
+SubCommand::operator bool() const {<br>
+  return (GlobalParser-><wbr>getActiveSubCommand() == this);<br>
+}<br>
+<br>
 //===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
 // Basic, shared command line option processing machinery.<br>
 //<br>
@@ -246,25 +396,29 @@ void OptionCategory::<wbr>registerCategory()<br>
 /// LookupOption - Lookup the option specified by the specified option on the<br>
 /// command line.  If there is a value specified (after an equal sign) return<br>
 /// that as well.  This assumes that leading dashes have already been stripped.<br>
-Option *CommandLineParser::<wbr>LookupOption(StringRef &Arg, StringRef &Value) {<br>
+Option *CommandLineParser::<wbr>LookupOption(SubCommand &Sub, StringRef &Arg,<br>
+                                        StringRef &Value) {<br>
   // Reject all dashes.<br>
   if (Arg.empty())<br>
     return nullptr;<br>
+  assert(&Sub != &*AllSubCommands);<br>
<br>
   size_t EqualPos = Arg.find('=');<br>
<br>
   // If we have an equals sign, remember the value.<br>
   if (EqualPos == StringRef::npos) {<br>
     // Look up the option.<br>
-    StringMap<Option *>::const_iterator I = OptionsMap.find(Arg);<br>
-    return I != OptionsMap.end() ? I->second : nullptr;<br>
+    auto I = Sub.OptionsMap.find(Arg);<br>
+    if (I == Sub.OptionsMap.end())<br>
+      return nullptr;<br>
+<br>
+    return I != Sub.OptionsMap.end() ? I->second : nullptr;<br>
   }<br>
<br>
   // If the argument before the = is a valid option name, we match.  If not,<br>
   // return Arg unmolested.<br>
-  StringMap<Option *>::const_iterator I =<br>
-      OptionsMap.find(Arg.substr(0, EqualPos));<br>
-  if (I == OptionsMap.end())<br>
+  auto I = Sub.OptionsMap.find(Arg.<wbr>substr(0, EqualPos));<br>
+  if (I == Sub.OptionsMap.end())<br>
     return nullptr;<br>
<br>
   Value = Arg.substr(EqualPos + 1);<br>
@@ -272,6 +426,21 @@ Option *CommandLineParser::<wbr>LookupOption(<br>
   return I->second;<br>
 }<br>
<br>
+SubCommand *CommandLineParser::<wbr>LookupSubCommand(const char *Name) {<br>
+  if (Name == nullptr)<br>
+    return &*TopLevelSubCommand;<br>
+  for (auto S : RegisteredSubCommands) {<br>
+    if (S == &*AllSubCommands)<br>
+      continue;<br>
+    if (S->getName() == nullptr)<br>
+      continue;<br>
+<br>
+    if (StringRef(S->getName()) == StringRef(Name))<br>
+      return S;<br>
+  }<br>
+  return &*TopLevelSubCommand;<br>
+}<br>
+<br>
 /// LookupNearestOption - Lookup the closest match to the option specified by<br>
 /// the specified option on the command line.  If there is a value specified<br>
 /// (after an equal sign) return that as well.  This assumes that leading dashes<br>
@@ -820,14 +989,25 @@ void cl::ParseEnvironmentOptions(<wbr>const c<br>
   ParseCommandLineOptions(<wbr>newArgc, &newArgv[0], Overview);<br>
 }<br>
<br>
-void cl::ParseCommandLineOptions(<wbr>int argc, const char *const *argv,<br>
-                                 const char *Overview) {<br>
-  GlobalParser-><wbr>ParseCommandLineOptions(argc, argv, Overview);<br>
+bool cl::ParseCommandLineOptions(<wbr>int argc, const char *const *argv,<br>
+                                 const char *Overview, bool IgnoreErrors) {<br>
+  return GlobalParser-><wbr>ParseCommandLineOptions(argc, argv, Overview,<br>
+                                               IgnoreErrors);<br>
 }<br>
<br>
-void CommandLineParser::<wbr>ParseCommandLineOptions(int argc,<br>
+void CommandLineParser::<wbr>ResetAllOptionOccurrences() {<br>
+  // So that we can parse different command lines multiple times in succession<br>
+  // we reset all option values to look like they have never been seen before.<br>
+  for (auto SC : RegisteredSubCommands) {<br>
+    for (auto &O : SC->OptionsMap)<br>
+      O.second->reset();<br>
+  }<br>
+}<br>
+<br>
+bool CommandLineParser::<wbr>ParseCommandLineOptions(int argc,<br>
                                                 const char *const *argv,<br>
-                                                const char *Overview) {<br>
+                                                const char *Overview,<br>
+                                                bool IgnoreErrors) {<br>
   assert(hasOptions() && "No options specified!");<br>
<br>
   // Expand response files.<br>
@@ -850,6 +1030,23 @@ void CommandLineParser::<wbr>ParseCommandLine<br>
   // Determine whether or not there are an unlimited number of positionals<br>
   bool HasUnlimitedPositionals = false;<br>
<br>
+  int FirstArg = 1;<br>
+  SubCommand *ChosenSubCommand = &*TopLevelSubCommand;<br>
+  if (argc >= 2 && argv[FirstArg][0] != '-') {<br>
+    // If the first argument specifies a valid subcommand, start processing<br>
+    // options from the second argument.<br>
+    ChosenSubCommand = LookupSubCommand(argv[<wbr>FirstArg]);<br>
+    if (ChosenSubCommand != &*TopLevelSubCommand)<br>
+      FirstArg = 2;<br>
+  }<br>
+  GlobalParser->ActiveSubCommand = ChosenSubCommand;<br>
+<br>
+  assert(ChosenSubCommand);<br>
+  auto &ConsumeAfterOpt = ChosenSubCommand-><wbr>ConsumeAfterOpt;<br>
+  auto &PositionalOpts = ChosenSubCommand-><wbr>PositionalOpts;<br>
+  auto &SinkOpts = ChosenSubCommand->SinkOpts;<br>
+  auto &OptionsMap = ChosenSubCommand->OptionsMap;<br>
+<br>
   if (ConsumeAfterOpt) {<br>
     assert(PositionalOpts.size() > 0 &&<br>
            "Cannot specify cl::ConsumeAfter without a positional argument!");<br>
@@ -865,23 +1062,28 @@ void CommandLineParser::<wbr>ParseCommandLine<br>
       else if (ConsumeAfterOpt) {<br>
         // ConsumeAfter cannot be combined with "optional" positional options<br>
         // unless there is only one positional argument...<br>
-        if (PositionalOpts.size() > 1)<br>
-          ErrorParsing |= Opt->error(<br>
-              "error - this positional option will never be matched, "<br>
-              "because it does not Require a value, and a "<br>
-              "cl::ConsumeAfter option is active!");<br>
+        if (PositionalOpts.size() > 1) {<br>
+          if (!IgnoreErrors)<br>
+            Opt->error("error - this positional option will never be matched, "<br>
+                       "because it does not Require a value, and a "<br>
+                       "cl::ConsumeAfter option is active!");<br>
+          ErrorParsing = true;<br>
+        }<br>
       } else if (UnboundedFound && !Opt->hasArgStr()) {<br>
         // This option does not "require" a value...  Make sure this option is<br>
         // not specified after an option that eats all extra arguments, or this<br>
         // one will never get any!<br>
         //<br>
-        ErrorParsing |= Opt->error("error - option can never match, because "<br>
-                                   "another positional argument will match an "<br>
-                                   "unbounded number of values, and this option"<br>
-                                   " does not require a value!");<br>
-        errs() << ProgramName << ": CommandLine Error: Option '" << Opt->ArgStr<br>
-               << "' is all messed up!\n";<br>
-        errs() << PositionalOpts.size();<br>
+        if (!IgnoreErrors) {<br>
+          Opt->error("error - option can never match, because "<br>
+                     "another positional argument will match an "<br>
+                     "unbounded number of values, and this option"<br>
+                     " does not require a value!");<br>
+          errs() << ProgramName << ": CommandLine Error: Option '"<br>
+                 << Opt->ArgStr << "' is all messed up!\n";<br>
+          errs() << PositionalOpts.size();<br>
+        }<br>
+        ErrorParsing = true;<br>
       }<br>
       UnboundedFound |= EatsUnboundedNumberOfValues(<wbr>Opt);<br>
     }<br>
@@ -900,7 +1102,7 @@ void CommandLineParser::<wbr>ParseCommandLine<br>
<br>
   // Loop over all of the arguments... processing them.<br>
   bool DashDashFound = false; // Have we read '--'?<br>
-  for (int i = 1; i < argc; ++i) {<br>
+  for (int i = FirstArg; i < argc; ++i) {<br>
     Option *Handler = nullptr;<br>
     Option *NearestHandler = nullptr;<br>
     std::string NearestHandlerString;<br>
@@ -947,7 +1149,7 @@ void CommandLineParser::<wbr>ParseCommandLine<br>
       while (!ArgName.empty() && ArgName[0] == '-')<br>
         ArgName = ArgName.substr(1);<br>
<br>
-      Handler = LookupOption(ArgName, Value);<br>
+      Handler = LookupOption(*<wbr>ChosenSubCommand, ArgName, Value);<br>
       if (!Handler || Handler->getFormattingFlag() != cl::Positional) {<br>
         ProvidePositionalOption(<wbr>ActivePositionalArg, argv[i], i);<br>
         continue; // We are done!<br>
@@ -959,7 +1161,7 @@ void CommandLineParser::<wbr>ParseCommandLine<br>
       while (!ArgName.empty() && ArgName[0] == '-')<br>
         ArgName = ArgName.substr(1);<br>
<br>
-      Handler = LookupOption(ArgName, Value);<br>
+      Handler = LookupOption(*<wbr>ChosenSubCommand, ArgName, Value);<br>
<br>
       // Check to see if this "option" is really a prefixed or grouped argument.<br>
       if (!Handler)<br>
@@ -975,13 +1177,15 @@ void CommandLineParser::<wbr>ParseCommandLine<br>
<br>
     if (!Handler) {<br>
       if (SinkOpts.empty()) {<br>
-        errs() << ProgramName << ": Unknown command line argument '" << argv[i]<br>
-               << "'.  Try: '" << argv[0] << " -help'\n";<br>
-<br>
-        if (NearestHandler) {<br>
-          // If we know a near match, report it as well.<br>
-          errs() << ProgramName << ": Did you mean '-" << NearestHandlerString<br>
-                 << "'?\n";<br>
+        if (!IgnoreErrors) {<br>
+          errs() << ProgramName << ": Unknown command line argument '"<br>
+                 << argv[i] << "'.  Try: '" << argv[0] << " -help'\n";<br>
+<br>
+          if (NearestHandler) {<br>
+            // If we know a near match, report it as well.<br>
+            errs() << ProgramName << ": Did you mean '-" << NearestHandlerString<br>
+                   << "'?\n";<br>
+          }<br>
         }<br>
<br>
         ErrorParsing = true;<br>
@@ -1004,17 +1208,21 @@ void CommandLineParser::<wbr>ParseCommandLine<br>
<br>
   // Check and handle positional arguments now...<br>
   if (NumPositionalRequired > PositionalVals.size()) {<br>
-    errs() << ProgramName<br>
-           << ": Not enough positional command line arguments specified!\n"<br>
-           << "Must specify at least " << NumPositionalRequired<br>
-           << " positional arguments: See: " << argv[0] << " -help\n";<br>
+    if (!IgnoreErrors) {<br>
+      errs() << ProgramName<br>
+             << ": Not enough positional command line arguments specified!\n"<br>
+             << "Must specify at least " << NumPositionalRequired<br>
+             << " positional arguments: See: " << argv[0] << " -help\n";<br>
+    }<br>
<br>
     ErrorParsing = true;<br>
   } else if (!HasUnlimitedPositionals &&<br>
              PositionalVals.size() > PositionalOpts.size()) {<br>
-    errs() << ProgramName << ": Too many positional arguments specified!\n"<br>
-           << "Can specify at most " << PositionalOpts.size()<br>
-           << " positional arguments: See: " << argv[0] << " -help\n";<br>
+    if (!IgnoreErrors) {<br>
+      errs() << ProgramName << ": Too many positional arguments specified!\n"<br>
+             << "Can specify at most " << PositionalOpts.size()<br>
+             << " positional arguments: See: " << argv[0] << " -help\n";<br>
+    }<br>
     ErrorParsing = true;<br>
<br>
   } else if (!ConsumeAfterOpt) {<br>
@@ -1109,8 +1317,12 @@ void CommandLineParser::<wbr>ParseCommandLine<br>
   MoreHelp.clear();<br>
<br>
   // If we had an error processing our arguments, don't let the program execute<br>
-  if (ErrorParsing)<br>
-    exit(1);<br>
+  if (ErrorParsing) {<br>
+    if (!IgnoreErrors)<br>
+      exit(1);<br>
+    return false;<br>
+  }<br>
+  return true;<br>
 }<br>
<br>
 //===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
@@ -1460,6 +1672,11 @@ static int OptNameCompare(const std::pai<br>
   return strcmp(LHS->first, RHS->first);<br>
 }<br>
<br>
+static int SubNameCompare(const std::pair<const char *, SubCommand *> *LHS,<br>
+                          const std::pair<const char *, SubCommand *> *RHS) {<br>
+  return strcmp(LHS->first, RHS->first);<br>
+}<br>
+<br>
 // Copy Options into a vector so we can sort them as we like.<br>
 static void sortOpts(StringMap<Option *> &OptMap,<br>
                      SmallVectorImpl<std::pair<<wbr>const char *, Option *>> &Opts,<br>
@@ -1488,6 +1705,17 @@ static void sortOpts(StringMap<Option *><br>
   array_pod_sort(Opts.begin(), Opts.end(), OptNameCompare);<br>
 }<br>
<br>
+static void<br>
+sortSubCommands(const SmallPtrSetImpl<SubCommand *> &SubMap,<br>
+                SmallVectorImpl<std::pair<<wbr>const char *, SubCommand *>> &Subs) {<br>
+  for (const auto &S : SubMap) {<br>
+    if (S->getName() == nullptr)<br>
+      continue;<br>
+    Subs.push_back(std::make_pair(<wbr>S->getName(), S));<br>
+  }<br>
+  array_pod_sort(Subs.begin(), Subs.end(), SubNameCompare);<br>
+}<br>
+<br>
 namespace {<br>
<br>
 class HelpPrinter {<br>
@@ -1495,12 +1723,25 @@ protected:<br>
   const bool ShowHidden;<br>
   typedef SmallVector<std::pair<const char *, Option *>, 128><br>
       StrOptionPairVector;<br>
+  typedef SmallVector<std::pair<const char *, SubCommand *>, 128><br>
+      StrSubCommandPairVector;<br>
   // Print the options. Opts is assumed to be alphabetically sorted.<br>
   virtual void printOptions(<wbr>StrOptionPairVector &Opts, size_t MaxArgLen) {<br>
     for (size_t i = 0, e = Opts.size(); i != e; ++i)<br>
       Opts[i].second-><wbr>printOptionInfo(MaxArgLen);<br>
   }<br>
<br>
+  void printSubCommands(<wbr>StrSubCommandPairVector &Subs, size_t MaxSubLen) {<br>
+    for (const auto &S : Subs) {<br>
+      outs() << "  " << S.first;<br>
+      if (S.second->getDescription()) {<br>
+        outs().indent(MaxSubLen - strlen(S.first));<br>
+        outs() << " - " << S.second->getDescription();<br>
+      }<br>
+      outs() << "\n";<br>
+    }<br>
+  }<br>
+<br>
 public:<br>
   explicit HelpPrinter(bool showHidden) : ShowHidden(showHidden) {}<br>
   virtual ~HelpPrinter() {}<br>
@@ -1510,23 +1751,56 @@ public:<br>
     if (!Value)<br>
       return;<br>
<br>
+    SubCommand *Sub = GlobalParser-><wbr>getActiveSubCommand();<br>
+    auto &OptionsMap = Sub->OptionsMap;<br>
+    auto &PositionalOpts = Sub->PositionalOpts;<br>
+    auto &ConsumeAfterOpt = Sub->ConsumeAfterOpt;<br>
+<br>
     StrOptionPairVector Opts;<br>
-    sortOpts(GlobalParser-><wbr>OptionsMap, Opts, ShowHidden);<br>
+    sortOpts(OptionsMap, Opts, ShowHidden);<br>
+<br>
+    StrSubCommandPairVector Subs;<br>
+    sortSubCommands(GlobalParser-><wbr>RegisteredSubCommands, Subs);<br>
<br>
     if (GlobalParser-><wbr>ProgramOverview)<br>
       outs() << "OVERVIEW: " << GlobalParser->ProgramOverview << "\n";<br>
<br>
-    outs() << "USAGE: " << GlobalParser->ProgramName << " [options]";<br>
+    if (Sub == &*TopLevelSubCommand)<br>
+      outs() << "USAGE: " << GlobalParser->ProgramName<br>
+             << " [subcommand] [options]";<br>
+    else {<br>
+      if (Sub->getDescription() != nullptr) {<br>
+        outs() << "SUBCOMMAND '" << Sub->getName()<br>
+               << "': " << Sub->getDescription() << "\n\n";<br>
+      }<br>
+      outs() << "USAGE: " << GlobalParser->ProgramName << " " << Sub->getName()<br>
+             << " [options]";<br>
+    }<br>
<br>
-    for (auto Opt : GlobalParser->PositionalOpts) {<br>
+    for (auto Opt : PositionalOpts) {<br>
       if (Opt->hasArgStr())<br>
         outs() << " --" << Opt->ArgStr;<br>
       outs() << " " << Opt->HelpStr;<br>
     }<br>
<br>
     // Print the consume after option info if it exists...<br>
-    if (GlobalParser-><wbr>ConsumeAfterOpt)<br>
-      outs() << " " << GlobalParser->ConsumeAfterOpt-<wbr>>HelpStr;<br>
+    if (ConsumeAfterOpt)<br>
+      outs() << " " << ConsumeAfterOpt->HelpStr;<br>
+<br>
+    if (Sub == &*TopLevelSubCommand && Subs.size() > 2) {<br></blockquote><div><br></div><div>I'm sorry if I missed something, but I looked at the review for this commit, and couldn't find an answer to one question that I have, so I hope that you can help me:<br></div><div><br></div><div>Is the > 2 intentional here? I think because of this check subcommands don't show up in help unless there are 3 of them. It seems like a bug to me, since it's valid to have a tool with just 2 subcommands.</div><div><br></div><div>Thanks,</div><div>Alex</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
+      // Compute the maximum subcommand length...<br>
+      size_t MaxSubLen = 0;<br>
+      for (size_t i = 0, e = Subs.size(); i != e; ++i)<br>
+        MaxSubLen = std::max(MaxSubLen, strlen(Subs[i].first));<br>
+<br>
+      outs() << "\n\n";<br>
+      outs() << "SUBCOMMANDS:\n\n";<br>
+      printSubCommands(Subs, MaxSubLen);<br>
+      outs() << "\n";<br>
+      outs() << "  Type \"" << GlobalParser->ProgramName<br>
+             << " <subcommand> -help\" to get more help on a specific "<br>
+                "subcommand";<br>
+    }<br>
<br>
     outs() << "\n\n";<br>
<br>
@@ -1675,12 +1949,13 @@ static cl::opt<HelpPrinter, true, parser<br>
     "help-list",<br>
     cl::desc("Display list of available options (-help-list-hidden for more)"),<br>
     cl::location(<wbr>UncategorizedNormalPrinter), cl::Hidden, cl::ValueDisallowed,<br>
-    cl::cat(GenericCategory));<br>
+    cl::cat(GenericCategory), cl::sub(*AllSubCommands));<br>
<br>
 static cl::opt<HelpPrinter, true, parser<bool>><br>
     HLHOp("help-list-hidden", cl::desc("Display list of all available options"),<br>
           cl::location(<wbr>UncategorizedHiddenPrinter), cl::Hidden,<br>
-          cl::ValueDisallowed, cl::cat(GenericCategory));<br>
+          cl::ValueDisallowed, cl::cat(GenericCategory),<br>
+          cl::sub(*AllSubCommands));<br>
<br>
 // Define uncategorized/categorized help printers. These printers change their<br>
 // behaviour at runtime depending on whether one or more Option categories have<br>
@@ -1688,22 +1963,23 @@ static cl::opt<HelpPrinter, true, parser<br>
 static cl::opt<HelpPrinterWrapper, true, parser<bool>><br>
     HOp("help", cl::desc("Display available options (-help-hidden for more)"),<br>
         cl::location(<wbr>WrappedNormalPrinter), cl::ValueDisallowed,<br>
-        cl::cat(GenericCategory));<br>
+        cl::cat(GenericCategory), cl::sub(*AllSubCommands));<br>
<br>
 static cl::opt<HelpPrinterWrapper, true, parser<bool>><br>
     HHOp("help-hidden", cl::desc("Display all available options"),<br>
          cl::location(<wbr>WrappedHiddenPrinter), cl::Hidden, cl::ValueDisallowed,<br>
-         cl::cat(GenericCategory));<br>
+         cl::cat(GenericCategory), cl::sub(*AllSubCommands));<br>
<br>
 static cl::opt<bool> PrintOptions(<br>
     "print-options",<br>
     cl::desc("Print non-default options after command line parsing"),<br>
-    cl::Hidden, cl::init(false), cl::cat(GenericCategory));<br>
+    cl::Hidden, cl::init(false), cl::cat(GenericCategory),<br>
+    cl::sub(*AllSubCommands));<br>
<br>
 static cl::opt<bool> PrintAllOptions(<br>
     "print-all-options",<br>
     cl::desc("Print all option values after command line parsing"), cl::Hidden,<br>
-    cl::init(false), cl::cat(GenericCategory));<br>
+    cl::init(false), cl::cat(GenericCategory), cl::sub(*AllSubCommands));<br>
<br>
 void HelpPrinterWrapper::operator=(<wbr>bool Value) {<br>
   if (!Value)<br>
@@ -1730,7 +2006,7 @@ void CommandLineParser::<wbr>printOptionValue<br>
     return;<br>
<br>
   SmallVector<std::pair<const char *, Option *>, 128> Opts;<br>
-  sortOpts(OptionsMap, Opts, /*ShowHidden*/ true);<br>
+  sortOpts(ActiveSubCommand-><wbr>OptionsMap, Opts, /*ShowHidden*/ true);<br>
<br>
   // Compute the maximum argument length...<br>
   size_t MaxArgLen = 0;<br>
@@ -1839,22 +2115,26 @@ void cl::AddExtraVersionPrinter(<wbr>void (*f<br>
   ExtraVersionPrinters->push_<wbr>back(func);<br>
 }<br>
<br>
-StringMap<Option *> &cl::getRegisteredOptions() {<br>
-  return GlobalParser->OptionsMap;<br>
+StringMap<Option *> &cl::getRegisteredOptions(<wbr>SubCommand &Sub) {<br>
+  auto &Subs = GlobalParser-><wbr>RegisteredSubCommands;<br>
+  (void)Subs;<br>
+  assert(std::find(Subs.begin(), Subs.end(), &Sub) != Subs.end());<br>
+  return Sub.OptionsMap;<br>
 }<br>
<br>
-void cl::HideUnrelatedOptions(cl::<wbr>OptionCategory &Category) {<br>
-  for (auto &I : GlobalParser->OptionsMap) {<br>
+void cl::HideUnrelatedOptions(cl::<wbr>OptionCategory &Category, SubCommand &Sub) {<br>
+  for (auto &I : Sub.OptionsMap) {<br>
     if (I.second->Category != &Category &&<br>
         I.second->Category != &GenericCategory)<br>
       I.second->setHiddenFlag(cl::<wbr>ReallyHidden);<br>
   }<br>
 }<br>
<br>
-void cl::HideUnrelatedOptions(<wbr>ArrayRef<const cl::OptionCategory *> Categories) {<br>
+void cl::HideUnrelatedOptions(<wbr>ArrayRef<const cl::OptionCategory *> Categories,<br>
+                              SubCommand &Sub) {<br>
   auto CategoriesBegin = Categories.begin();<br>
   auto CategoriesEnd = Categories.end();<br>
-  for (auto &I : GlobalParser->OptionsMap) {<br>
+  for (auto &I : Sub.OptionsMap) {<br>
     if (std::find(CategoriesBegin, CategoriesEnd, I.second->Category) ==<br>
             CategoriesEnd &&<br>
         I.second->Category != &GenericCategory)<br>
@@ -1862,7 +2142,12 @@ void cl::HideUnrelatedOptions(<wbr>ArrayRef<c<br>
   }<br>
 }<br>
<br>
+void cl::ResetCommandLineParser() { GlobalParser->reset(); }<br>
+void cl::ResetAllOptionOccurrences(<wbr>) {<br>
+  GlobalParser-><wbr>ResetAllOptionOccurrences();<br>
+}<br>
+<br>
 void LLVMParseCommandLineOptions(<wbr>int argc, const char *const *argv,<br>
                                  const char *Overview) {<br>
-  llvm::cl::<wbr>ParseCommandLineOptions(argc, argv, Overview);<br>
+  llvm::cl::<wbr>ParseCommandLineOptions(argc, argv, Overview, true);<br>
 }<br>
<br>
Modified: llvm/trunk/unittests/Support/<wbr>CommandLineTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/CommandLineTest.cpp?rev=274171&r1=274170&r2=274171&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/unittests/<wbr>Support/CommandLineTest.cpp?<wbr>rev=274171&r1=274170&r2=<wbr>274171&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/unittests/Support/<wbr>CommandLineTest.cpp (original)<br>
+++ llvm/trunk/unittests/Support/<wbr>CommandLineTest.cpp Wed Jun 29 16:48:26 2016<br>
@@ -67,6 +67,22 @@ public:<br>
     : Base(M0, M1, M2, M3) {}<br>
<br>
   ~StackOption() override { this->removeArgument(); }<br>
+<br>
+  template <class DT> StackOption<T> &operator=(const DT &V) {<br>
+    this->setValue(V);<br>
+    return *this;<br>
+  }<br>
+};<br>
+<br>
+class StackSubCommand : public cl::SubCommand {<br>
+public:<br>
+  StackSubCommand(const char *const Name,<br>
+                  const char *const Description = nullptr)<br>
+      : SubCommand(Name, Description) {}<br>
+<br>
+  StackSubCommand() : SubCommand() {}<br>
+<br>
+  ~StackSubCommand() { unregisterSubCommand(); }<br>
 };<br>
<br>
<br>
@@ -78,7 +94,8 @@ TEST(CommandLineTest, ModifyExisitingOpt<br>
   const char ArgString[] = "new-test-option";<br>
   const char ValueString[] = "Integer";<br>
<br>
-  StringMap<cl::Option *> &Map = cl::getRegisteredOptions();<br>
+  StringMap<cl::Option *> &Map =<br>
+      cl::getRegisteredOptions(*cl::<wbr>TopLevelSubCommand);<br>
<br>
   ASSERT_TRUE(Map.count("test-<wbr>option") == 1) <<<br>
     "Could not find option in map.";<br>
@@ -237,7 +254,8 @@ TEST(CommandLineTest, HideUnrelatedOptio<br>
   ASSERT_EQ(cl::NotHidden, TestOption2.<wbr>getOptionHiddenFlag())<br>
       << "Hid extra option that should be visable.";<br>
<br>
-  StringMap<cl::Option *> &Map = cl::getRegisteredOptions();<br>
+  StringMap<cl::Option *> &Map =<br>
+      cl::getRegisteredOptions(*cl::<wbr>TopLevelSubCommand);<br>
   ASSERT_EQ(cl::NotHidden, Map["help"]-><wbr>getOptionHiddenFlag())<br>
       << "Hid default option that should be visable.";<br>
 }<br>
@@ -261,9 +279,201 @@ TEST(CommandLineTest, HideUnrelatedOptio<br>
   ASSERT_EQ(cl::NotHidden, TestOption3.<wbr>getOptionHiddenFlag())<br>
       << "Hid extra option that should be visable.";<br>
<br>
-  StringMap<cl::Option *> &Map = cl::getRegisteredOptions();<br>
+  StringMap<cl::Option *> &Map =<br>
+      cl::getRegisteredOptions(*cl::<wbr>TopLevelSubCommand);<br>
   ASSERT_EQ(cl::NotHidden, Map["help"]-><wbr>getOptionHiddenFlag())<br>
       << "Hid default option that should be visable.";<br>
 }<br>
<br>
+TEST(CommandLineTest, SetValueInSubcategories) {<br>
+  cl::ResetCommandLineParser();<br>
+<br>
+  StackSubCommand SC1("sc1", "First subcommand");<br>
+  StackSubCommand SC2("sc2", "Second subcommand");<br>
+<br>
+  StackOption<bool> TopLevelOpt("top-level", cl::init(false));<br>
+  StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false));<br>
+  StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));<br>
+<br>
+  EXPECT_FALSE(TopLevelOpt);<br>
+  EXPECT_FALSE(SC1Opt);<br>
+  EXPECT_FALSE(SC2Opt);<br>
+  const char *args[] = {"prog", "-top-level"};<br>
+  EXPECT_TRUE(cl::<wbr>ParseCommandLineOptions(2, args, nullptr, true));<br>
+  EXPECT_TRUE(TopLevelOpt);<br>
+  EXPECT_FALSE(SC1Opt);<br>
+  EXPECT_FALSE(SC2Opt);<br>
+<br>
+  TopLevelOpt = false;<br>
+<br>
+  cl::ResetAllOptionOccurrences(<wbr>);<br>
+  EXPECT_FALSE(TopLevelOpt);<br>
+  EXPECT_FALSE(SC1Opt);<br>
+  EXPECT_FALSE(SC2Opt);<br>
+  const char *args2[] = {"prog", "sc1", "-sc1"};<br>
+  EXPECT_TRUE(cl::<wbr>ParseCommandLineOptions(3, args2, nullptr, true));<br>
+  EXPECT_FALSE(TopLevelOpt);<br>
+  EXPECT_TRUE(SC1Opt);<br>
+  EXPECT_FALSE(SC2Opt);<br>
+<br>
+  SC1Opt = false;<br>
+<br>
+  cl::ResetAllOptionOccurrences(<wbr>);<br>
+  EXPECT_FALSE(TopLevelOpt);<br>
+  EXPECT_FALSE(SC1Opt);<br>
+  EXPECT_FALSE(SC2Opt);<br>
+  const char *args3[] = {"prog", "sc2", "-sc2"};<br>
+  EXPECT_TRUE(cl::<wbr>ParseCommandLineOptions(3, args3, nullptr, true));<br>
+  EXPECT_FALSE(TopLevelOpt);<br>
+  EXPECT_FALSE(SC1Opt);<br>
+  EXPECT_TRUE(SC2Opt);<br>
+}<br>
+<br>
+TEST(CommandLineTest, LookupFailsInWrongSubCommand) {<br>
+  cl::ResetCommandLineParser();<br>
+<br>
+  StackSubCommand SC1("sc1", "First subcommand");<br>
+  StackSubCommand SC2("sc2", "Second subcommand");<br>
+<br>
+  StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false));<br>
+  StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));<br>
+<br>
+  const char *args[] = {"prog", "sc1", "-sc2"};<br>
+  EXPECT_FALSE(cl::<wbr>ParseCommandLineOptions(3, args, nullptr, true));<br>
+}<br>
+<br>
+TEST(CommandLineTest, AddToAllSubCommands) {<br>
+  cl::ResetCommandLineParser();<br>
+<br>
+  StackSubCommand SC1("sc1", "First subcommand");<br>
+  StackOption<bool> AllOpt("everywhere", cl::sub(*cl::AllSubCommands),<br>
+                           cl::init(false));<br>
+  StackSubCommand SC2("sc2", "Second subcommand");<br>
+<br>
+  const char *args[] = {"prog", "-everywhere"};<br>
+  const char *args2[] = {"prog", "sc1", "-everywhere"};<br>
+  const char *args3[] = {"prog", "sc2", "-everywhere"};<br>
+<br>
+  EXPECT_FALSE(AllOpt);<br>
+  EXPECT_TRUE(cl::<wbr>ParseCommandLineOptions(2, args, nullptr, true));<br>
+  EXPECT_TRUE(AllOpt);<br>
+<br>
+  AllOpt = false;<br>
+<br>
+  cl::ResetAllOptionOccurrences(<wbr>);<br>
+  EXPECT_FALSE(AllOpt);<br>
+  EXPECT_TRUE(cl::<wbr>ParseCommandLineOptions(3, args2, nullptr, true));<br>
+  EXPECT_TRUE(AllOpt);<br>
+<br>
+  AllOpt = false;<br>
+<br>
+  cl::ResetAllOptionOccurrences(<wbr>);<br>
+  EXPECT_FALSE(AllOpt);<br>
+  EXPECT_TRUE(cl::<wbr>ParseCommandLineOptions(3, args3, nullptr, true));<br>
+  EXPECT_TRUE(AllOpt);<br>
+}<br>
+<br>
+TEST(CommandLineTest, ReparseCommandLineOptions) {<br>
+  cl::ResetCommandLineParser();<br>
+<br>
+  StackOption<bool> TopLevelOpt("top-level", cl::sub(*cl::<wbr>TopLevelSubCommand),<br>
+                                cl::init(false));<br>
+<br>
+  const char *args[] = {"prog", "-top-level"};<br>
+<br>
+  EXPECT_FALSE(TopLevelOpt);<br>
+  EXPECT_TRUE(cl::<wbr>ParseCommandLineOptions(2, args, nullptr, true));<br>
+  EXPECT_TRUE(TopLevelOpt);<br>
+<br>
+  TopLevelOpt = false;<br>
+<br>
+  cl::ResetAllOptionOccurrences(<wbr>);<br>
+  EXPECT_FALSE(TopLevelOpt);<br>
+  EXPECT_TRUE(cl::<wbr>ParseCommandLineOptions(2, args, nullptr, true));<br>
+  EXPECT_TRUE(TopLevelOpt);<br>
+}<br>
+<br>
+TEST(CommandLineTest, RemoveFromRegularSubCommand) {<br>
+  cl::ResetCommandLineParser();<br>
+<br>
+  StackSubCommand SC("sc", "Subcommand");<br>
+  StackOption<bool> RemoveOption("remove-option", cl::sub(SC), cl::init(false));<br>
+  StackOption<bool> KeepOption("keep-option", cl::sub(SC), cl::init(false));<br>
+<br>
+  const char *args[] = {"prog", "sc", "-remove-option"};<br>
+<br>
+  EXPECT_FALSE(RemoveOption);<br>
+  EXPECT_TRUE(cl::<wbr>ParseCommandLineOptions(3, args, nullptr, true));<br>
+  EXPECT_TRUE(RemoveOption);<br>
+<br>
+  RemoveOption.removeArgument();<br>
+<br>
+  cl::ResetAllOptionOccurrences(<wbr>);<br>
+  EXPECT_FALSE(cl::<wbr>ParseCommandLineOptions(3, args, nullptr, true));<br>
+}<br>
+<br>
+TEST(CommandLineTest, RemoveFromTopLevelSubCommand) {<br>
+  cl::ResetCommandLineParser();<br>
+<br>
+  StackOption<bool> TopLevelRemove(<br>
+      "top-level-remove", cl::sub(*cl::<wbr>TopLevelSubCommand), cl::init(false));<br>
+  StackOption<bool> TopLevelKeep(<br>
+      "top-level-keep", cl::sub(*cl::<wbr>TopLevelSubCommand), cl::init(false));<br>
+<br>
+  const char *args[] = {"prog", "-top-level-remove"};<br>
+<br>
+  EXPECT_FALSE(TopLevelRemove);<br>
+  EXPECT_TRUE(cl::<wbr>ParseCommandLineOptions(2, args, nullptr, true));<br>
+  EXPECT_TRUE(TopLevelRemove);<br>
+<br>
+  TopLevelRemove.removeArgument(<wbr>);<br>
+<br>
+  cl::ResetAllOptionOccurrences(<wbr>);<br>
+  EXPECT_FALSE(cl::<wbr>ParseCommandLineOptions(2, args, nullptr, true));<br>
+}<br>
+<br>
+TEST(CommandLineTest, RemoveFromAllSubCommands) {<br>
+  cl::ResetCommandLineParser();<br>
+<br>
+  StackSubCommand SC1("sc1", "First Subcommand");<br>
+  StackSubCommand SC2("sc2", "Second Subcommand");<br>
+  StackOption<bool> RemoveOption("remove-option", cl::sub(*cl::AllSubCommands),<br>
+                                 cl::init(false));<br>
+  StackOption<bool> KeepOption("keep-option", cl::sub(*cl::AllSubCommands),<br>
+                               cl::init(false));<br>
+<br>
+  const char *args0[] = {"prog", "-remove-option"};<br>
+  const char *args1[] = {"prog", "sc1", "-remove-option"};<br>
+  const char *args2[] = {"prog", "sc2", "-remove-option"};<br>
+<br>
+  // It should work for all subcommands including the top-level.<br>
+  EXPECT_FALSE(RemoveOption);<br>
+  EXPECT_TRUE(cl::<wbr>ParseCommandLineOptions(2, args0, nullptr, true));<br>
+  EXPECT_TRUE(RemoveOption);<br>
+<br>
+  RemoveOption = false;<br>
+<br>
+  cl::ResetAllOptionOccurrences(<wbr>);<br>
+  EXPECT_FALSE(RemoveOption);<br>
+  EXPECT_TRUE(cl::<wbr>ParseCommandLineOptions(3, args1, nullptr, true));<br>
+  EXPECT_TRUE(RemoveOption);<br>
+<br>
+  RemoveOption = false;<br>
+<br>
+  cl::ResetAllOptionOccurrences(<wbr>);<br>
+  EXPECT_FALSE(RemoveOption);<br>
+  EXPECT_TRUE(cl::<wbr>ParseCommandLineOptions(3, args2, nullptr, true));<br>
+  EXPECT_TRUE(RemoveOption);<br>
+<br>
+  RemoveOption.removeArgument();<br>
+<br>
+  // It should not work for any subcommands including the top-level.<br>
+  cl::ResetAllOptionOccurrences(<wbr>);<br>
+  EXPECT_FALSE(cl::<wbr>ParseCommandLineOptions(2, args0, nullptr, true));<br>
+  cl::ResetAllOptionOccurrences(<wbr>);<br>
+  EXPECT_FALSE(cl::<wbr>ParseCommandLineOptions(3, args1, nullptr, true));<br>
+  cl::ResetAllOptionOccurrences(<wbr>);<br>
+  EXPECT_FALSE(cl::<wbr>ParseCommandLineOptions(3, args2, nullptr, true));<br>
+}<br>
+<br>
 }  // anonymous namespace<br>
<br>
Modified: llvm/trunk/unittests/Support/<wbr>ProgramTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ProgramTest.cpp?rev=274171&r1=274170&r2=274171&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/unittests/<wbr>Support/ProgramTest.cpp?rev=<wbr>274171&r1=274170&r2=274171&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/unittests/Support/<wbr>ProgramTest.cpp (original)<br>
+++ llvm/trunk/unittests/Support/<wbr>ProgramTest.cpp Wed Jun 29 16:48:26 2016<br>
@@ -231,7 +231,7 @@ TEST_F(ProgramEnvTest, TestExecuteNoWait<br>
   // LoopCount should only be incremented once.<br>
   while (true) {<br>
     ++LoopCount;<br>
-    ProcessInfo WaitResult = Wait(PI1, 0, true, &Error);<br>
+    ProcessInfo WaitResult = llvm::sys::Wait(PI1, 0, true, &Error);<br>
     ASSERT_TRUE(Error.empty());<br>
     if (WaitResult.Pid == PI1.Pid)<br>
       break;<br>
@@ -248,7 +248,7 @@ TEST_F(ProgramEnvTest, TestExecuteNoWait<br>
   // cse, LoopCount should be greater than 1 (more than one increment occurs).<br>
   while (true) {<br>
     ++LoopCount;<br>
-    ProcessInfo WaitResult = Wait(PI2, 0, false, &Error);<br>
+    ProcessInfo WaitResult = llvm::sys::Wait(PI2, 0, false, &Error);<br>
     ASSERT_TRUE(Error.empty());<br>
     if (WaitResult.Pid == PI2.Pid)<br>
       break;<br>
<br>
<br>
______________________________<wbr>_________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>