diff --git a/llvm/include/llvm/Option/OptTable.h b/llvm/include/llvm/Option/OptTable.h --- a/llvm/include/llvm/Option/OptTable.h +++ b/llvm/include/llvm/Option/OptTable.h @@ -62,6 +62,7 @@ ArrayRef OptionInfos; bool IgnoreCase; bool GroupedShortOptions = false; + bool DashDashParsing = false; const char *EnvVar = nullptr; unsigned InputOptionID = 0; @@ -139,6 +140,10 @@ /// Support grouped short options. e.g. -ab represents -a -b. void setGroupedShortOptions(bool Value) { GroupedShortOptions = Value; } + /// Set whether "--" stops option parsing and treats all subsequent arguments + /// as positional. E.g. -- -a -b gives two positional inputs. + void setDashDashParsing(bool Value) { DashDashParsing = Value; } + /// Find possible value for given flags. This is used for shell /// autocompletion. /// diff --git a/llvm/lib/Option/OptTable.cpp b/llvm/lib/Option/OptTable.cpp --- a/llvm/lib/Option/OptTable.cpp +++ b/llvm/lib/Option/OptTable.cpp @@ -468,6 +468,16 @@ continue; } + // In DashDashParsing mode, the first "--" stops option scanning and treats + // all subsequent arguments as positional. + if (DashDashParsing && Str == "--") { + while (++Index < End) { + Args.append(new Arg(getOption(InputOptionID), Str, Index, + Args.getArgString(Index))); + } + break; + } + unsigned Prev = Index; std::unique_ptr A = GroupedShortOptions ? parseOneArgGrouped(Args, Index) diff --git a/llvm/test/tools/llvm-strings/dash-filename.test b/llvm/test/tools/llvm-strings/dash-filename.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-strings/dash-filename.test @@ -0,0 +1,6 @@ +## Show that -- stops option scanning. + +RUN: rm -rf %t && mkdir %t && cd %t +RUN: echo abcd > -a +RUN: llvm-strings -f -- -a | FileCheck %s +CHECK: -a: abcd diff --git a/llvm/tools/llvm-strings/llvm-strings.cpp b/llvm/tools/llvm-strings/llvm-strings.cpp --- a/llvm/tools/llvm-strings/llvm-strings.cpp +++ b/llvm/tools/llvm-strings/llvm-strings.cpp @@ -62,6 +62,7 @@ public: StringsOptTable() : GenericOptTable(InfoTable) { setGroupedShortOptions(true); + setDashDashParsing(true); } }; } // namespace diff --git a/llvm/unittests/Option/OptionParsingTest.cpp b/llvm/unittests/Option/OptionParsingTest.cpp --- a/llvm/unittests/Option/OptionParsingTest.cpp +++ b/llvm/unittests/Option/OptionParsingTest.cpp @@ -391,6 +391,39 @@ EXPECT_TRUE(AL3.hasArg(OPT_Blorp)); } +TYPED_TEST(OptTableTest, ParseDashDash) { + TypeParam T; + T.setDashDashParsing(true); + unsigned MAI, MAC; + + const char *Args1[] = {"-A", "--"}; + InputArgList AL = T.ParseArgs(Args1, MAI, MAC); + EXPECT_TRUE(AL.hasArg(OPT_A)); + EXPECT_EQ(size_t(0), AL.getAllArgValues(OPT_INPUT).size()); + EXPECT_EQ(size_t(0), AL.getAllArgValues(OPT_UNKNOWN).size()); + + const char *Args2[] = {"-A", "--", "-A", "--", "-B"}; + AL = T.ParseArgs(Args2, MAI, MAC); + EXPECT_TRUE(AL.hasArg(OPT_A)); + EXPECT_FALSE(AL.hasArg(OPT_B)); + const std::vector Input = AL.getAllArgValues(OPT_INPUT); + ASSERT_EQ(size_t(3), Input.size()); + EXPECT_EQ("-A", Input[0]); + EXPECT_EQ("--", Input[1]); + EXPECT_EQ("-B", Input[2]); + EXPECT_EQ(size_t(0), AL.getAllArgValues(OPT_UNKNOWN).size()); + + T.setDashDashParsing(false); + AL = T.ParseArgs(Args2, MAI, MAC); + EXPECT_TRUE(AL.hasArg(OPT_A)); + EXPECT_TRUE(AL.hasArg(OPT_B)); + EXPECT_EQ(size_t(0), AL.getAllArgValues(OPT_INPUT).size()); + const std::vector Unknown = AL.getAllArgValues(OPT_UNKNOWN); + ASSERT_EQ(size_t(2), Unknown.size()); + EXPECT_EQ("--", Unknown[0]); + EXPECT_EQ("--", Unknown[1]); +} + TYPED_TEST(OptTableTest, UnknownOptions) { TypeParam T; unsigned MAI, MAC; diff --git a/llvm/unittests/Option/Opts.td b/llvm/unittests/Option/Opts.td --- a/llvm/unittests/Option/Opts.td +++ b/llvm/unittests/Option/Opts.td @@ -43,8 +43,6 @@ def Blurmpq : Flag<["--"], "blurmp">; def Blurmpq_eq : Flag<["--"], "blurmp=">; -def DashDash : Option<["--"], "", KIND_REMAINING_ARGS>; - class XOpts : KeyPathAndMacro<"X->", base> {} def marshalled_flag_d : Flag<["-"], "marshalled-flag-d">,