[PATCH] D26319: Disallow StringRef assignment from temporary std::strings.

Duncan Exon Smith via llvm-commits llvm-commits at lists.llvm.org
Sat Nov 5 07:11:27 PDT 2016


LGTM.

-- dpnes

> On Nov 4, 2016, at 17:18, Jordan Rose <jordan_rose at apple.com> wrote:
> 
> jordan_rose created this revision.
> jordan_rose added a reviewer: dexonsmith.
> jordan_rose added a subscriber: llvm-commits.
> jordan_rose set the repository for this revision to rL LLVM.
> jordan_rose added a dependency: D26317: Fix use-of-temporary with StringRef in code coverage.
> 
> Similar to https://reviews.llvm.org/D25446, this prevents accidentally referring to temporary storage that goes out of scope by the end of the statement:
> 
>  someStringRef = getStringByValue();
>  someStringRef = (Twine("-") + otherString).str();
> 
> Note that once again the constructor still has this problem:
> 
>  StringRef someStringRef = getStringByValue();
> 
> because once again we occasionally rely on this in calls:
> 
>  takesStringRef(getStringByValue());
>  takesStringRef(Twine("-") + otherString);
> 
> Still, it's a step, and it caught one real problem in Clang and one in Swift.
> 
> Depends on https://reviews.llvm.org/D26317
> 
> 
> Repository:
>  rL LLVM
> 
> https://reviews.llvm.org/D26319
> 
> Files:
>  include/llvm/ADT/StringRef.h
>  unittests/ADT/StringRefTest.cpp
> 
> 
> Index: unittests/ADT/StringRefTest.cpp
> ===================================================================
> --- unittests/ADT/StringRefTest.cpp
> +++ unittests/ADT/StringRefTest.cpp
> @@ -32,14 +32,50 @@
> 
> }
> 
> +// Check that we can't accidentally assign a temporary std::string to a
> +// StringRef. (Unfortunately we can't make use of the same thing with
> +// constructors.)
> +//
> +// Disable this check under MSVC; even MSVC 2015 isn't consistent between
> +// std::is_assignable and actually writing such an assignment.
> +#if !defined(_MSC_VER)
> +static_assert(
> +    !std::is_assignable<StringRef, std::string>::value,
> +    "Assigning from prvalue std::string");
> +static_assert(
> +    !std::is_assignable<StringRef, std::string &&>::value,
> +    "Assigning from xvalue std::string");
> +static_assert(
> +    std::is_assignable<StringRef, std::string &>::value,
> +    "Assigning from lvalue std::string");
> +static_assert(
> +    std::is_assignable<StringRef, const char *>::value,
> +    "Assigning from prvalue C string");
> +static_assert(
> +    std::is_assignable<StringRef, const char * &&>::value,
> +    "Assigning from xvalue C string");
> +static_assert(
> +    std::is_assignable<StringRef, const char * &>::value,
> +    "Assigning from lvalue C string");
> +#endif
> +
> +
> namespace {
> TEST(StringRefTest, Construction) {
>   EXPECT_EQ("", StringRef());
>   EXPECT_EQ("hello", StringRef("hello"));
>   EXPECT_EQ("hello", StringRef("hello world", 5));
>   EXPECT_EQ("hello", StringRef(std::string("hello")));
> }
> 
> +TEST(StringRefTest, EmptyInitializerList) {
> +  StringRef S = {};
> +  EXPECT_TRUE(S.empty());
> +
> +  S = {};
> +  EXPECT_TRUE(S.empty());
> +}
> +
> TEST(StringRefTest, Iteration) {
>   StringRef S("hello");
>   const char *p = "hello";
> Index: include/llvm/ADT/StringRef.h
> ===================================================================
> --- include/llvm/ADT/StringRef.h
> +++ include/llvm/ADT/StringRef.h
> @@ -215,6 +215,15 @@
>       return Data[Index];
>     }
> 
> +    /// Disallow accidental assignment from a temporary std::string.
> +    ///
> +    /// The declaration here is extra complicated so that `stringRef = {}`
> +    /// and `stringRef = "abc"` continue to select the move assignment operator.
> +    template <typename T>
> +    typename std::enable_if<std::is_same<T, std::string>::value,
> +                            StringRef>::type &
> +    operator=(T &&Str) = delete;
> +
>     /// @}
>     /// @name Type Conversions
>     /// @{
> 
> 
> <D26319.76957.patch>


More information about the llvm-commits mailing list