Skip to content

RFC: [llvm] specialize cl::opt_storage for std::string #149172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

andrurogerz
Copy link
Contributor

Purpose

Specialize llvm::cl::opt_storage for data type std::string so that it no longer inherits from std::string. With this patch in place, explicitly instantiated cl::opt<std::string> can be safely exported from an LLVM Windows DLL.

Overview

  • Add fully-specified implementation of cl::opt_storage for data type std::string. It does NOT inherit from std::string as it did previously when data type std::string matched the partially specified template cl::opt_storage<DataType, false, true>
  • Implement implicit conversions to std::string, llvm::StringRef, and llvm::Twine so that instances can be used in many places where std::string is used.
  • Implement a number of std::string methods so that instances of the class are mostly interoperable with std::string.
  • Add a new explicit constructor to Triple so it properly constructs from cl::opt_storage<std::string>. This change avoids having to modify clients that construct Triples from cl::opt<std::string> instances.

Background

This patch is in support of annotating LLVM's public symbols for Windows DLL export., tracked in #109483. Additional context is provided in this discourse.

This change is needed because, without it, we cannot export opt<std::string> from an LLVM Windows DLL. This is because MSVC exports all ancestor classes when exporting an instantiated template class. Since one of opt's ancestor classes is its type argument (via opt_storage), it is an ancestor of std::string. Therefore, if we export opt<std::string> from the LLVM DLL, MSVC forces std::basic_string to also be exported. This leads to duplicate symbol errors and generally seems like a bad idea. Compiling with clang-cl does not exhibit this behavior.

Validation

  • Built llvm-project on Windows with MSVC cl and clang-cl.
  • Built llvm-project on Fedora with clang and gcc.

Copy link

github-actions bot commented Jul 16, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff HEAD~1 HEAD --extensions h -- llvm/include/llvm/Support/CommandLine.h llvm/include/llvm/TargetParser/Triple.h
View the diff from clang-format here.
diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h
index 823e31a80..7c041fbff 100644
--- a/llvm/include/llvm/Support/CommandLine.h
+++ b/llvm/include/llvm/Support/CommandLine.h
@@ -1417,23 +1417,23 @@ public:
   const OptionValue<std::string> &getDefault() const { return Default; }
 
   // Support implicit conversions to std::string and LLVM string-like types.
-  //operator std::string() const { return Value; }
-  operator std::string&() { return Value; }
-  operator const std::string&() const { return Value; }
+  // operator std::string() const { return Value; }
+  operator std::string &() { return Value; }
+  operator const std::string &() const { return Value; }
   operator llvm::StringRef() const { return llvm::StringRef(Value); }
   operator llvm::Twine() const { return llvm::Twine(llvm::StringRef(Value)); }
 
   // If the datatype is a pointer, support -> on it.
   std::string operator->() const { return Value; }
 
-  Self& operator=(const Self& rhs) = default;
+  Self &operator=(const Self &rhs) = default;
 
-  Self& operator=(const std::string& rhs) {
+  Self &operator=(const std::string &rhs) {
     Value = rhs;
     return *this;
   }
 
-  Self& operator=(const char* rhs) {
+  Self &operator=(const char *rhs) {
     Value = rhs;
     return *this;
   }
@@ -1491,43 +1491,39 @@ public:
 
   char operator[](size_t pos) const { return Value.at(pos); }
 
-  Self& assign(const std::string& rhs) {
+  Self &assign(const std::string &rhs) {
     Value.assign(rhs);
     return *this;
   }
 
-  Self& assign(const char* rhs) {
+  Self &assign(const char *rhs) {
     Value.assign(rhs);
     return *this;
   }
 
-  Self& operator+=(const std::string& rhs) {
+  Self &operator+=(const std::string &rhs) {
     Value += rhs;
     return *this;
   }
 
-  Self& operator+=(const char* rhs) {
+  Self &operator+=(const char *rhs) {
     Value += rhs;
     return *this;
   }
 
-  friend std::string
-  operator+(Self const& lhs, std::string const& rhs) {
+  friend std::string operator+(Self const &lhs, std::string const &rhs) {
     return lhs.Value + rhs;
   }
 
-  friend std::string
-  operator+(std::string const& lhs, Self const& rhs) {
+  friend std::string operator+(std::string const &lhs, Self const &rhs) {
     return lhs + rhs.Value;
   }
 
-  friend std::string
-  operator+(Self const& lhs, char const* rhs) {
+  friend std::string operator+(Self const &lhs, char const *rhs) {
     return lhs.Value + rhs;
   }
 
-  friend std::string
-  operator+(char const* lhs, Self const& rhs) {
+  friend std::string operator+(char const *lhs, Self const &rhs) {
     return lhs + rhs.Value;
   }
 

@andrurogerz andrurogerz changed the title [llvm] specialize cl::opt_storage for std::string RFC: [llvm] specialize cl::opt_storage for std::string Jul 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant