[llvm] Enable parsing of optional strings (PR #154364)
Jacques Pienaar via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 19 08:40:25 PDT 2025
https://github.com/jpienaar created https://github.com/llvm/llvm-project/pull/154364
Previously a "opt<std::optional<std::string>>>" would fail to parse/would attempt to parse option value as argument.
>From 583f1c784a5def4ae754acfad172076554e5de39 Mon Sep 17 00:00:00 2001
From: Jacques Pienaar <jacques+gh at japienaar.info>
Date: Tue, 19 Aug 2025 15:11:57 +0000
Subject: [PATCH] Enable parsing of optional strings
Previously a "opt<std::optional<std::string>>>" would fail to
parse/would attempt to parse option value as argument.
---
llvm/include/llvm/Support/CommandLine.h | 25 ++++++++++++++++++++++
llvm/lib/Support/CommandLine.cpp | 17 +++++++++++++++
llvm/unittests/Support/CommandLineTest.cpp | 16 ++++++++++++++
3 files changed, 58 insertions(+)
diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h
index ca725b8ac8712..7d14943a77d92 100644
--- a/llvm/include/llvm/Support/CommandLine.h
+++ b/llvm/include/llvm/Support/CommandLine.h
@@ -1192,6 +1192,31 @@ class LLVM_ABI parser<std::string> : public basic_parser<std::string> {
//--------------------------------------------------
+template <>
+class LLVM_ABI parser<std::optional<std::string>>
+ : public basic_parser<std::optional<std::string>> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ // Return true on error.
+ bool parse(Option &, StringRef, StringRef Arg,
+ std::optional<std::string> &Value) {
+ Value = Arg.str();
+ return false;
+ }
+
+ // Overload in subclass to provide a better default value.
+ StringRef getValueName() const override { return "optional string"; }
+
+ void printOptionDiff(const Option &O, std::optional<StringRef> V,
+ const OptVal &Default, size_t GlobalWidth) const;
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override;
+};
+
+//--------------------------------------------------
+
extern template class LLVM_TEMPLATE_ABI basic_parser<char>;
template <> class LLVM_ABI parser<char> : public basic_parser<char> {
diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp
index 8491633df97e8..db5fa096d3601 100644
--- a/llvm/lib/Support/CommandLine.cpp
+++ b/llvm/lib/Support/CommandLine.cpp
@@ -101,6 +101,7 @@ void parser<unsigned long long>::anchor() {}
void parser<double>::anchor() {}
void parser<float>::anchor() {}
void parser<std::string>::anchor() {}
+void parser<std::optional<std::string>>::anchor() {}
void parser<char>::anchor() {}
// These anchor functions instantiate opt<T> and reference its virtual
@@ -2259,6 +2260,22 @@ void parser<std::string>::printOptionDiff(const Option &O, StringRef V,
outs() << ")\n";
}
+void parser<std::optional<std::string>>::printOptionDiff(
+ const Option &O, std::optional<StringRef> V,
+ const OptionValue<std::optional<std::string>> &D,
+ size_t GlobalWidth) const {
+ printOptionName(O, GlobalWidth);
+ outs() << "= " << V;
+ size_t VSize = V.has_value() ? V.value().size() : 0;
+ size_t NumSpaces = MaxOptWidth > VSize ? MaxOptWidth - VSize : 0;
+ outs().indent(NumSpaces) << " (default: ";
+ if (D.hasValue() && D.getValue().has_value())
+ outs() << D.getValue();
+ else
+ outs() << "*no value*";
+ outs() << ")\n";
+}
+
// Print a placeholder for options that don't yet support printOptionDiff().
void basic_parser_impl::printOptionNoValue(const Option &O,
size_t GlobalWidth) const {
diff --git a/llvm/unittests/Support/CommandLineTest.cpp b/llvm/unittests/Support/CommandLineTest.cpp
index ad06ca91c226e..66eae7a837e9e 100644
--- a/llvm/unittests/Support/CommandLineTest.cpp
+++ b/llvm/unittests/Support/CommandLineTest.cpp
@@ -2117,6 +2117,22 @@ TEST(CommandLineTest, ConsumeAfterTwoPositionals) {
EXPECT_TRUE(Errs.empty());
}
+TEST(CommandLineTest, ConsumeOptionalString) {
+ cl::ResetCommandLineParser();
+
+ StackOption<std::optional<std::string>, cl::opt<std::optional<std::string>>>
+ Input("input");
+
+ const char *Args[] = {"prog", "--input=\"value\""};
+
+ std::string Errs;
+ raw_string_ostream OS(Errs);
+ ASSERT_TRUE(cl::ParseCommandLineOptions(2, Args, StringRef(), &OS));
+ ASSERT_TRUE(Input.has_value());
+ EXPECT_EQ("\"value\"", *Input);
+ EXPECT_TRUE(Errs.empty());
+}
+
TEST(CommandLineTest, ResetAllOptionOccurrences) {
cl::ResetCommandLineParser();
More information about the llvm-commits
mailing list