PR51018: Disallow explicit construction of StringRef from SmallString due to ambiguit...
authorDavid Blaikie <dblaikie@gmail.com>
Thu, 8 Jul 2021 20:26:40 +0000 (13:26 -0700)
committerDavid Blaikie <dblaikie@gmail.com>
Thu, 8 Jul 2021 20:37:57 +0000 (13:37 -0700)
See bug for full details, but basically there's an upcoming ambiguity in
the conversion in `StringRef(SomeSmallString)` - either the implicit
conversion operator (SmallString::operator StringRef) could be used, or
the std::string_view range-based ctor (& then `StringRef(std::string_view)`
would be used)

To address this, make such a conversion invalid up-front - most uses are
more tersely written as `SomeSmallString.str()` anyway, or more clearly
written as `StringRef x = y;` rather than `StringRef x(y);` - so if you
hit this in out-of-tree code, please update in one of those ways.
Hopefully I've fixed everything in tree prior to this patch landing.

llvm/include/llvm/ADT/SmallString.h

index 56b0639..4f83a60 100644 (file)
 
 namespace llvm {
 
+namespace impl {
+template <typename T> struct SmallStringConversionHelper1 {
+  operator StringRef() const { return static_cast<const T *>(this)->str(); }
+};
+struct SmallStringConversionHelper2 {
+  explicit operator StringRef() const = delete;
+};
+} // namespace impl
+
 /// SmallString - A SmallString is just a SmallVector with methods and accessors
 /// that make it work better as a string (e.g. operator+ etc).
-template<unsigned InternalLen>
-class SmallString : public SmallVector<char, InternalLen> {
+template <unsigned InternalLen>
+class SmallString
+    : public SmallVector<char, InternalLen>,
+      public impl::SmallStringConversionHelper1<SmallString<InternalLen>>,
+      public impl::SmallStringConversionHelper2 {
 public:
   /// Default ctor - Initialize to empty.
   SmallString() = default;
@@ -266,7 +278,6 @@ public:
   }
 
   /// Implicit conversion to StringRef.
-  operator StringRef() const { return str(); }
 
   explicit operator std::string() const {
     return std::string(this->data(), this->size());