diff --git a/llvm/include/llvm/ADT/Twine.h b/llvm/include/llvm/ADT/Twine.h --- a/llvm/include/llvm/ADT/Twine.h +++ b/llvm/include/llvm/ADT/Twine.h @@ -102,6 +102,10 @@ /// because they are not trivally constructible. PtrAndLengthKind, + /// A pointer and length representation that's also null-terminated. + /// Guaranteed to be constructed from a compile-time string literal. + StringLiteralKind, + /// A pointer to a formatv_object_base instance. FormatvObjectKind, @@ -303,6 +307,14 @@ assert(isValid() && "Invalid twine!"); } + /// Construct from a StringLiteral. + /*implicit*/ Twine(const StringLiteral &Str) + : LHSKind(StringLiteralKind) { + LHS.ptrAndLength.ptr = Str.data(); + LHS.ptrAndLength.length = Str.size(); + assert(isValid() && "Invalid twine!"); + } + /// Construct from a SmallString. /*implicit*/ Twine(const SmallVectorImpl &Str) : LHSKind(PtrAndLengthKind) { @@ -418,6 +430,11 @@ return isNullary(); } + /// Check if this twine is guaranteed to refer to single string literal. + bool isSingleStringLiteral() const { + return isUnary() && getLHSKind() == StringLiteralKind; + } + /// Return true if this twine can be dynamically accessed as a single /// StringRef value with getSingleStringRef(). bool isSingleStringRef() const { @@ -428,6 +445,7 @@ case CStringKind: case StdStringKind: case PtrAndLengthKind: + case StringLiteralKind: return true; default: return false; @@ -463,6 +481,7 @@ case StdStringKind: return StringRef(*LHS.stdString); case PtrAndLengthKind: + case StringLiteralKind: return StringRef(LHS.ptrAndLength.ptr, LHS.ptrAndLength.length); } } diff --git a/llvm/lib/Support/Twine.cpp b/llvm/lib/Support/Twine.cpp --- a/llvm/lib/Support/Twine.cpp +++ b/llvm/lib/Support/Twine.cpp @@ -44,6 +44,8 @@ const std::string *str = LHS.stdString; return StringRef(str->c_str(), str->size()); } + case StringLiteralKind: + return StringRef(LHS.ptrAndLength.ptr, LHS.ptrAndLength.length); default: break; } @@ -69,6 +71,7 @@ OS << *Ptr.stdString; break; case Twine::PtrAndLengthKind: + case Twine::StringLiteralKind: OS << StringRef(Ptr.ptrAndLength.ptr, Ptr.ptrAndLength.length); break; case Twine::FormatvObjectKind: @@ -124,6 +127,10 @@ OS << "ptrAndLength:\"" << StringRef(Ptr.ptrAndLength.ptr, Ptr.ptrAndLength.length) << "\""; break; + case Twine::StringLiteralKind: + OS << "constexprPtrAndLength:\"" + << StringRef(Ptr.ptrAndLength.ptr, Ptr.ptrAndLength.length) << "\""; + break; case Twine::FormatvObjectKind: OS << "formatv:\"" << *Ptr.formatvObject << "\""; break; diff --git a/llvm/unittests/ADT/TwineTest.cpp b/llvm/unittests/ADT/TwineTest.cpp --- a/llvm/unittests/ADT/TwineTest.cpp +++ b/llvm/unittests/ADT/TwineTest.cpp @@ -30,6 +30,7 @@ EXPECT_EQ("hi", Twine(StringRef("hi")).str()); EXPECT_EQ("hi", Twine(StringRef(std::string("hi"))).str()); EXPECT_EQ("hi", Twine(StringRef("hithere", 2)).str()); + EXPECT_EQ("hi", Twine(StringLiteral("hi")).str()); EXPECT_EQ("hi", Twine(SmallString<4>("hi")).str()); EXPECT_EQ("hi", Twine(formatv("{0}", "hi")).str()); EXPECT_EQ("hi", Twine(std::string_view("hi")).str()); @@ -96,6 +97,9 @@ EXPECT_EQ(0, *Twine("hello").toNullTerminatedStringRef(storage).end()); EXPECT_EQ(0, *Twine(StringRef("hello")).toNullTerminatedStringRef(storage).end()); + EXPECT_EQ( + 0, + *Twine(StringLiteral("hello")).toNullTerminatedStringRef(storage).end()); EXPECT_EQ(0, *Twine(SmallString<11>("hello")) .toNullTerminatedStringRef(storage) .end()); @@ -104,6 +108,12 @@ .end()); } +TEST(TwineTest, isSingleStringLiteral) { + EXPECT_TRUE(Twine(StringLiteral("hi")).isSingleStringLiteral()); + EXPECT_FALSE(Twine("hi").isSingleStringLiteral()); + EXPECT_FALSE(Twine(StringRef("hi")).isSingleStringLiteral()); +} + TEST(TwineTest, LazyEvaluation) { struct formatter : FormatAdapter { explicit formatter(int &Count) : FormatAdapter(0), Count(Count) {}