[llvm] b9123f7 - [Support] Remove cl::Grouping (#224958)

via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 24 19:50:54 PDT 2026


Author: Fangrui Song
Date: 2026-09-24T19:50:45-07:00
New Revision: b9123f788eb3e62c5cf18fd7d7b093dd3206b60d

URL: https://github.com/llvm/llvm-project/commit/b9123f788eb3e62c5cf18fd7d7b093dd3206b60d
DIFF: https://github.com/llvm/llvm-project/commit/b9123f788eb3e62c5cf18fd7d7b093dd3206b60d.diff

LOG: [Support] Remove cl::Grouping (#224958)

This feature emulates POSIX's grouped short options in a non-perfect
way. https://reviews.llvm.org/D61270 made every single-character
cl::option implicitly group, leading to weird error message for `opt
-foo=bar`: `opt: for the -o option: may not occur within a group!`

Every tool (primarily binutils-style tools) has since migrated to
OptTable,
with llvm-cov gcov the last (#224955).

Delete this feature, which would block TableGen based representation.

LLM-aided

Added: 
    

Modified: 
    llvm/docs/CommandLine.md
    llvm/include/llvm/Support/CommandLine.h
    llvm/lib/Support/CommandLine.cpp
    llvm/unittests/Support/CommandLineTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandLine.md b/llvm/docs/CommandLine.md
index 3dd499e2a2f6c..fb3bccd242382 100644
--- a/llvm/docs/CommandLine.md
+++ b/llvm/docs/CommandLine.md
@@ -58,8 +58,7 @@ CommandLine library to have the following features:
 
 1. Capable: The CommandLine library can handle lots of 
diff erent forms of
    options often found in real programs.  For example, {ref}`positional <positional>` arguments,
-   `ls` style {ref}`grouping <grouping>` options (to allow processing '`ls -lad`'
-   naturally), `ld` style {ref}`prefix <prefix>` options (to parse '`-lmalloc
+   `ld` style {ref}`prefix <prefix>` options (to parse '`-lmalloc
    -L/usr/lib`'), and interpreter style options.
 
 This document will hopefully let you jump in and start using CommandLine in your
@@ -1155,55 +1154,6 @@ As usual, you can only specify one of these arguments at most.
   **cl::Prefix** options must not have the **cl::ValueDisallowed** modifier
   specified.
 
-(grouping)=
-(cl::Grouping)=
-
-#### Controlling options grouping
-
-The **cl::Grouping** modifier can be combined with any formatting types except
-for {ref}`cl::Positional <cl::Positional>`.  It is used to implement Unix-style tools (like `ls`)
-that have lots of single letter arguments, but only require a single dash.
-For example, the '`ls -labF`' command actually enables four 
diff erent options,
-all of which are single letters.
-
-Note that **cl::Grouping** options can have values only if they are used
-separately or at the end of the groups.  For {ref}`cl::ValueRequired <cl::ValueRequired>`, it is
-a runtime error if such an option is used elsewhere in the group.
-
-The CommandLine library does not restrict how you use the **cl::Prefix** or
-**cl::Grouping** modifiers, but it is possible to specify ambiguous argument
-settings.  Thus, it is possible to have multiple letter options that are prefix
-or grouping options, and they will still work as designed.
-
-To do this, the CommandLine library uses a greedy algorithm to parse the input
-option into (potentially multiple) prefix and grouping options.  The strategy
-basically looks like this:
-
-```
-parse(string OrigInput) {
-
-1. string Input = OrigInput;
-2. if (isOption(Input)) return getOption(Input).parse();  // Normal option
-3. while (!Input.empty() && !isOption(Input)) Input.pop_back();  // Remove the last letter
-4. while (!Input.empty()) {
-     string MaybeValue = OrigInput.substr(Input.length())
-     if (getOption(Input).isPrefix())
-       return getOption(Input).parse(MaybeValue)
-     if (!MaybeValue.empty() && MaybeValue[0] == '=')
-       return getOption(Input).parse(MaybeValue.substr(1))
-     if (!getOption(Input).isGrouping())
-       return error()
-     getOption(Input).parse()
-     Input = OrigInput = MaybeValue
-     while (!Input.empty() && !isOption(Input)) Input.pop_back();
-     if (!Input.empty() && !getOption(Input).isGrouping())
-       return error()
-   }
-5. if (!OrigInput.empty()) error();
-
-}
-```
-
 #### Miscellaneous option modifiers
 
 The miscellaneous option modifiers are the only flags where you can specify more

diff  --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h
index 15fbb8c56a0b0..7537d4c74f212 100644
--- a/llvm/include/llvm/Support/CommandLine.h
+++ b/llvm/include/llvm/Support/CommandLine.h
@@ -161,12 +161,6 @@ enum FormattingFlags {
 enum MiscFlags {             // Miscellaneous flags to adjust argument
   CommaSeparated = 0x01,     // Should this cl::list split between commas?
   PositionalEatsArgs = 0x02, // Should this positional cl::list eat -args?
-
-  // Can this option group with other options?
-  // If this is enabled, multiple letter options are allowed to bunch together
-  // with only a single hyphen for the whole group.  This allows emulation
-  // of the behavior that ls uses for example: ls -la === ls -l -a
-  Grouping = 0x08,
 };
 
 //===----------------------------------------------------------------------===//
@@ -1331,11 +1325,7 @@ template <> struct applicator<FormattingFlags> {
 };
 
 template <> struct applicator<MiscFlags> {
-  static void opt(MiscFlags MF, Option &O) {
-    assert((MF != Grouping || O.ArgStr.size() == 1) &&
-           "cl::Grouping can only apply to single character Options.");
-    O.setMiscFlag(MF);
-  }
+  static void opt(MiscFlags MF, Option &O) { O.setMiscFlag(MF); }
 };
 
 // Apply modifiers to an option in a type safe way.

diff  --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp
index 70eca48ee6635..b19984a0eeb03 100644
--- a/llvm/lib/Support/CommandLine.cpp
+++ b/llvm/lib/Support/CommandLine.cpp
@@ -140,15 +140,6 @@ static SmallString<8> argPrefix(StringRef ArgName, size_t Pad = DefaultPad) {
   return Prefix;
 }
 
-// Option predicates...
-static inline bool isGrouping(const Option *O) {
-  return O->getMiscFlags() & cl::Grouping;
-}
-static inline bool isPrefixedOrGrouping(const Option *O) {
-  return isGrouping(O) || O->getFormattingFlag() == cl::Prefix ||
-         O->getFormattingFlag() == cl::AlwaysPrefix;
-}
-
 using OptionsMapTy = DenseMap<StringRef, Option *>;
 
 namespace {
@@ -393,7 +384,8 @@ class CommandLineParser {
   Option *LookupLongOption(SubCommand &Sub, StringRef &Arg, StringRef &Value,
                            bool LongOptionsUseDoubleDash, bool HaveDoubleDash) {
     Option *Opt = LookupOption(Sub, Arg, Value);
-    if (Opt && LongOptionsUseDoubleDash && !HaveDoubleDash && !isGrouping(Opt))
+    if (Opt && LongOptionsUseDoubleDash && !HaveDoubleDash &&
+        Opt->ArgStr.size() != 1)
       return nullptr;
     return Opt;
   }
@@ -456,8 +448,6 @@ void Option::setArgStr(StringRef S) {
     globalParser().updateArgStr(this, S);
   assert(!S.starts_with("-") && "Option can't start with '-");
   ArgStr = S;
-  if (ArgStr.size() == 1)
-    setMiscFlag(Grouping);
 }
 
 void Option::addCategory(OptionCategory &C) {
@@ -688,92 +678,44 @@ bool llvm::cl::ProvidePositionalOption(Option *Handler, StringRef Arg, int i) {
   return ProvideOption(Handler, Handler->ArgStr, Arg, 0, nullptr, Dummy);
 }
 
-// getOptionPred - Check to see if there are any options that satisfy the
-// specified predicate with names that are the prefixes in Name.  This is
-// checked by progressively stripping characters off of the name, checking to
-// see if there options that satisfy the predicate.  If we find one, return it,
-// otherwise return null.
-//
-static Option *getOptionPred(StringRef Name, size_t &Length,
-                             bool (*Pred)(const Option *),
-                             const OptionsMapTy &OptionsMap) {
-  auto OMI = OptionsMap.find(Name);
-  if (OMI != OptionsMap.end() && !Pred(OMI->second))
-    OMI = OptionsMap.end();
-
-  // Loop while we haven't found an option and Name still has at least two
-  // characters in it (so that the next iteration will not be the empty
-  // string.
-  while (OMI == OptionsMap.end() && Name.size() > 1) {
-    Name = Name.drop_back();
-    OMI = OptionsMap.find(Name);
-    if (OMI != OptionsMap.end() && !Pred(OMI->second))
-      OMI = OptionsMap.end();
-  }
-
-  if (OMI != OptionsMap.end() && Pred(OMI->second)) {
-    Length = Name.size();
-    return OMI->second; // Found one!
-  }
-  return nullptr; // No option found!
-}
-
-/// HandlePrefixedOrGroupedOption - The specified argument string (which started
-/// with at least one '-') does not fully match an available option.  Check to
-/// see if this is a prefix or grouped option.  If so, split arg into output an
-/// Arg/Value pair and return the Option to parse it with.
-static Option *HandlePrefixedOrGroupedOption(StringRef &Arg, StringRef &Value,
-                                             bool &ErrorParsing,
-                                             const OptionsMapTy &OptionsMap) {
+// Find the cl::Prefix or cl::AlwaysPrefix option whose name is the longest
+// prefix of Name.
+static Option *findPrefixOption(StringRef Name, size_t &Length,
+                                const OptionsMapTy &OptionsMap) {
+  for (; !Name.empty(); Name = Name.drop_back()) {
+    Option *O = OptionsMap.lookup(Name);
+    if (O && (O->getFormattingFlag() == cl::Prefix ||
+              O->getFormattingFlag() == cl::AlwaysPrefix)) {
+      Length = Name.size();
+      return O;
+    }
+  }
+  return nullptr;
+}
+
+/// The specified argument string (which started with at least one '-') does not
+/// fully match an available option.  Check to see if this is a prefix option.
+/// If so, split arg into output an Arg/Value pair and return the Option to
+/// parse it with.
+static Option *HandlePrefixedOption(StringRef &Arg, StringRef &Value,
+                                    const OptionsMapTy &OptionsMap) {
   if (Arg.size() == 1)
     return nullptr;
 
-  // Do the lookup!
   size_t Length = 0;
-  Option *PGOpt = getOptionPred(Arg, Length, isPrefixedOrGrouping, OptionsMap);
-  if (!PGOpt)
+  Option *POpt = findPrefixOption(Arg, Length, OptionsMap);
+  if (!POpt)
     return nullptr;
 
-  do {
-    StringRef MaybeValue =
-        (Length < Arg.size()) ? Arg.substr(Length) : StringRef();
-    Arg = Arg.substr(0, Length);
-    assert(OptionsMap.count(Arg) && OptionsMap.find(Arg)->second == PGOpt);
-
-    // cl::Prefix options do not preserve '=' when used separately.
-    // The behavior for them with grouped options should be the same.
-    if (MaybeValue.empty() || PGOpt->getFormattingFlag() == cl::AlwaysPrefix ||
-        (PGOpt->getFormattingFlag() == cl::Prefix && MaybeValue[0] != '=')) {
-      Value = MaybeValue;
-      return PGOpt;
-    }
-
-    if (MaybeValue[0] == '=') {
-      Value = MaybeValue.substr(1);
-      return PGOpt;
-    }
-
-    // This must be a grouped option.
-    assert(isGrouping(PGOpt) && "Broken getOptionPred!");
-
-    // Grouping options inside a group can't have values.
-    if (PGOpt->getValueExpectedFlag() == cl::ValueRequired) {
-      ErrorParsing |= PGOpt->error("may not occur within a group!");
-      return nullptr;
-    }
-
-    // Because the value for the option is not required, we don't need to pass
-    // argc/argv in.
-    int Dummy = 0;
-    ErrorParsing |= ProvideOption(PGOpt, Arg, StringRef(), 0, nullptr, Dummy);
+  StringRef MaybeValue =
+      (Length < Arg.size()) ? Arg.substr(Length) : StringRef();
+  Arg = Arg.substr(0, Length);
 
-    // Get the next grouping option.
-    Arg = MaybeValue;
-    PGOpt = getOptionPred(Arg, Length, isGrouping, OptionsMap);
-  } while (PGOpt);
-
-  // We could not find a grouping option in the remainder of Arg.
-  return nullptr;
+  // cl::Prefix options do not preserve '=' when used separately.
+  if (POpt->getFormattingFlag() == cl::Prefix && MaybeValue.starts_with("="))
+    MaybeValue = MaybeValue.drop_front();
+  Value = MaybeValue;
+  return POpt;
 }
 
 static bool RequiresValue(const Option *O) {
@@ -1651,10 +1593,9 @@ bool CommandLineParser::ParseCommandLineOptions(
         Handler = LookupLongOption(SubCommand::getTopLevel(), ArgName, Value,
                                    LongOptionsUseDoubleDash, HaveDoubleDash);
 
-      // Check to see if this "option" is really a prefixed or grouped argument.
+      // Check to see if this "option" is really a prefixed argument.
       if (!Handler && !(LongOptionsUseDoubleDash && HaveDoubleDash))
-        Handler = HandlePrefixedOrGroupedOption(ArgName, Value, ErrorParsing,
-                                                OptionsMap);
+        Handler = HandlePrefixedOption(ArgName, Value, OptionsMap);
 
       // Otherwise, look for the closest available option to report to the user
       // in the upcoming error.

diff  --git a/llvm/unittests/Support/CommandLineTest.cpp b/llvm/unittests/Support/CommandLineTest.cpp
index 6af5ec7ccc774..d354d3ccf6d9b 100644
--- a/llvm/unittests/Support/CommandLineTest.cpp
+++ b/llvm/unittests/Support/CommandLineTest.cpp
@@ -1707,197 +1707,22 @@ TEST(CommandLineTest, PrefixOptions) {
   EXPECT_EQ(MacroDefs.front().compare("HAVE_FOO"), 0);
 }
 
-TEST(CommandLineTest, GroupingWithValue) {
+TEST(CommandLineTest, NoGrouping) {
   cl::ResetCommandLineParser();
 
-  StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag"));
-  StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag"));
-  StackOption<bool> OptD("d", cl::Grouping, cl::ValueDisallowed,
-                         cl::desc("ValueDisallowed option"));
-  StackOption<std::string> OptV("v", cl::Grouping,
-                                cl::desc("ValueRequired option"));
-  StackOption<std::string> OptO("o", cl::Grouping, cl::ValueOptional,
-                                cl::desc("ValueOptional option"));
-
-  // Should be possible to use an option which requires a value
-  // at the end of a group.
-  const char *args1[] = {"prog", "-fv", "val1"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
-  EXPECT_TRUE(OptF);
-  EXPECT_STREQ("val1", OptV.c_str());
-  OptV.clear();
-  cl::ResetAllOptionOccurrences();
-
-  // Should not crash if it is accidentally used elsewhere in the group.
-  const char *args2[] = {"prog", "-vf", "val2"};
-  EXPECT_FALSE(
-      cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
-  OptV.clear();
-  cl::ResetAllOptionOccurrences();
-
-  // Should allow the "opt=value" form at the end of the group
-  const char *args3[] = {"prog", "-fv=val3"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
-  EXPECT_TRUE(OptF);
-  EXPECT_STREQ("val3", OptV.c_str());
-  OptV.clear();
-  cl::ResetAllOptionOccurrences();
-
-  // Should allow assigning a value for a ValueOptional option
-  // at the end of the group
-  const char *args4[] = {"prog", "-fo=val4"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
-  EXPECT_TRUE(OptF);
-  EXPECT_STREQ("val4", OptO.c_str());
-  OptO.clear();
-  cl::ResetAllOptionOccurrences();
-
-  // Should assign an empty value if a ValueOptional option is used elsewhere
-  // in the group.
-  const char *args5[] = {"prog", "-fob"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(2, args5, StringRef(), &llvm::nulls()));
-  EXPECT_TRUE(OptF);
-  EXPECT_EQ(1, OptO.getNumOccurrences());
-  EXPECT_EQ(1, OptB.getNumOccurrences());
-  EXPECT_TRUE(OptO.empty());
-  cl::ResetAllOptionOccurrences();
-
-  // Should not allow an assignment for a ValueDisallowed option.
-  const char *args6[] = {"prog", "-fd=false"};
-  EXPECT_FALSE(
-      cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
-}
-
-TEST(CommandLineTest, GroupingAndPrefix) {
-  cl::ResetCommandLineParser();
-
-  StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag"));
-  StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag"));
-  StackOption<std::string> OptP("p", cl::Prefix, cl::Grouping,
-                                cl::desc("Prefix and Grouping"));
-  StackOption<std::string> OptA("a", cl::AlwaysPrefix, cl::Grouping,
-                                cl::desc("AlwaysPrefix and Grouping"));
-
-  // Should be possible to use a cl::Prefix option without grouping.
-  const char *args1[] = {"prog", "-pval1"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls()));
-  EXPECT_STREQ("val1", OptP.c_str());
-  OptP.clear();
-  cl::ResetAllOptionOccurrences();
-
-  // Should be possible to pass a value in a separate argument.
-  const char *args2[] = {"prog", "-p", "val2"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
-  EXPECT_STREQ("val2", OptP.c_str());
-  OptP.clear();
-  cl::ResetAllOptionOccurrences();
-
-  // The "-opt=value" form should work, too.
-  const char *args3[] = {"prog", "-p=val3"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
-  EXPECT_STREQ("val3", OptP.c_str());
-  OptP.clear();
-  cl::ResetAllOptionOccurrences();
-
-  // All three previous cases should work the same way if an option with both
-  // cl::Prefix and cl::Grouping modifiers is used at the end of a group.
-  const char *args4[] = {"prog", "-fpval4"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
-  EXPECT_TRUE(OptF);
-  EXPECT_STREQ("val4", OptP.c_str());
-  OptP.clear();
-  cl::ResetAllOptionOccurrences();
-
-  const char *args5[] = {"prog", "-fp", "val5"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls()));
-  EXPECT_TRUE(OptF);
-  EXPECT_STREQ("val5", OptP.c_str());
-  OptP.clear();
-  cl::ResetAllOptionOccurrences();
+  StackOption<bool> OptF("f", cl::desc("Some flag"));
+  StackOption<bool> OptB("b", cl::desc("Another flag"));
 
-  const char *args6[] = {"prog", "-fp=val6"};
+  const char *args1[] = {"prog", "-f", "-b"};
   EXPECT_TRUE(
-      cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
-  EXPECT_TRUE(OptF);
-  EXPECT_STREQ("val6", OptP.c_str());
-  OptP.clear();
-  cl::ResetAllOptionOccurrences();
-
-  // Should assign a value even if the part after a cl::Prefix option is equal
-  // to the name of another option.
-  const char *args7[] = {"prog", "-fpb"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(2, args7, StringRef(), &llvm::nulls()));
-  EXPECT_TRUE(OptF);
-  EXPECT_STREQ("b", OptP.c_str());
-  EXPECT_FALSE(OptB);
-  OptP.clear();
-  cl::ResetAllOptionOccurrences();
-
-  // Should be possible to use a cl::AlwaysPrefix option without grouping.
-  const char *args8[] = {"prog", "-aval8"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(2, args8, StringRef(), &llvm::nulls()));
-  EXPECT_STREQ("val8", OptA.c_str());
-  OptA.clear();
-  cl::ResetAllOptionOccurrences();
-
-  // Should not be possible to pass a value in a separate argument.
-  const char *args9[] = {"prog", "-a", "val9"};
-  EXPECT_FALSE(
-      cl::ParseCommandLineOptions(3, args9, StringRef(), &llvm::nulls()));
-  cl::ResetAllOptionOccurrences();
-
-  // With the "-opt=value" form, the "=" symbol should be preserved.
-  const char *args10[] = {"prog", "-a=val10"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(2, args10, StringRef(), &llvm::nulls()));
-  EXPECT_STREQ("=val10", OptA.c_str());
-  OptA.clear();
-  cl::ResetAllOptionOccurrences();
-
-  // All three previous cases should work the same way if an option with both
-  // cl::AlwaysPrefix and cl::Grouping modifiers is used at the end of a group.
-  const char *args11[] = {"prog", "-faval11"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(2, args11, StringRef(), &llvm::nulls()));
+      cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
   EXPECT_TRUE(OptF);
-  EXPECT_STREQ("val11", OptA.c_str());
-  OptA.clear();
+  EXPECT_TRUE(OptB);
   cl::ResetAllOptionOccurrences();
 
-  const char *args12[] = {"prog", "-fa", "val12"};
+  const char *args2[] = {"prog", "-fb"};
   EXPECT_FALSE(
-      cl::ParseCommandLineOptions(3, args12, StringRef(), &llvm::nulls()));
-  cl::ResetAllOptionOccurrences();
-
-  const char *args13[] = {"prog", "-fa=val13"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(2, args13, StringRef(), &llvm::nulls()));
-  EXPECT_TRUE(OptF);
-  EXPECT_STREQ("=val13", OptA.c_str());
-  OptA.clear();
-  cl::ResetAllOptionOccurrences();
-
-  // Should assign a value even if the part after a cl::AlwaysPrefix option
-  // is equal to the name of another option.
-  const char *args14[] = {"prog", "-fab"};
-  EXPECT_TRUE(
-      cl::ParseCommandLineOptions(2, args14, StringRef(), &llvm::nulls()));
-  EXPECT_TRUE(OptF);
-  EXPECT_STREQ("b", OptA.c_str());
-  EXPECT_FALSE(OptB);
-  OptA.clear();
-  cl::ResetAllOptionOccurrences();
+      cl::ParseCommandLineOptions(2, args2, StringRef(), &llvm::nulls()));
 }
 
 TEST(CommandLineTest, LongOptions) {
@@ -1937,8 +1762,7 @@ TEST(CommandLineTest, LongOptions) {
   EXPECT_TRUE(Errs.empty()); Errs.clear();
   cl::ResetAllOptionOccurrences();
 
-  // Fails because `-ab` and `--ab` are treated the same and appear more than
-  // once.  Also, `val1` is unexpected.
+  // Fails because `val1` is unexpected.
   EXPECT_FALSE(
       cl::ParseCommandLineOptions(4, args3, StringRef(), &OS));
   outs()<< Errs << "\n";
@@ -1950,8 +1774,8 @@ TEST(CommandLineTest, LongOptions) {
   // `--` for long options.
   //
 
-  // Fails because `-ab` is treated as `-a -b`, so `-a` is seen twice, and
-  // `val1` is unexpected.
+  // Fails because `-ab` is neither a short option nor `--ab`, and `val1` is
+  // unexpected.
   EXPECT_FALSE(cl::ParseCommandLineOptions(4, args1, StringRef(), &OS, nullptr,
                                            nullptr, true));
   EXPECT_FALSE(Errs.empty()); Errs.clear();
@@ -1963,13 +1787,11 @@ TEST(CommandLineTest, LongOptions) {
   EXPECT_TRUE(Errs.empty()); Errs.clear();
   cl::ResetAllOptionOccurrences();
 
-  // Works because `-ab` is treated as `-a -b`, and `--ab` is a long option.
-  EXPECT_TRUE(cl::ParseCommandLineOptions(4, args3, StringRef(), &OS, nullptr,
-                                          nullptr, true));
-  EXPECT_TRUE(OptA);
-  EXPECT_TRUE(OptBLong);
-  EXPECT_STREQ("val1", OptAB.c_str());
-  EXPECT_TRUE(Errs.empty()); Errs.clear();
+  // Fails because `-ab` is not `--ab`.
+  EXPECT_FALSE(cl::ParseCommandLineOptions(4, args3, StringRef(), &OS, nullptr,
+                                           nullptr, true));
+  EXPECT_FALSE(Errs.empty());
+  Errs.clear();
   cl::ResetAllOptionOccurrences();
 }
 


        


More information about the llvm-commits mailing list