From 764f9f7806aaaf41417d9c75091031a6c92099db Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Tue, 11 Oct 2016 20:39:16 +0000 Subject: [PATCH] Re-apply "Disallow ArrayRef assignment from temporaries." This re-applies r283798, disabled in r283803, with the static_assert tests disabled under MSVC. The deleted functions still seem to catch mistakes in MSVC, so it's not a significant loss. Part of rdar://problem/16375365 llvm-svn: 283935 --- llvm/include/llvm/ADT/ArrayRef.h | 16 ++++++++++++++++ llvm/unittests/ADT/ArrayRefTest.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/llvm/include/llvm/ADT/ArrayRef.h b/llvm/include/llvm/ADT/ArrayRef.h index c1d66c6..3efc09d 100644 --- a/llvm/include/llvm/ADT/ArrayRef.h +++ b/llvm/include/llvm/ADT/ArrayRef.h @@ -219,6 +219,22 @@ namespace llvm { return Data[Index]; } + /// Disallow accidental assignment from a temporary. + /// + /// The declaration here is extra complicated so that "arrayRef = {}" + /// continues to select the move assignment operator. + template + typename std::enable_if::value, ArrayRef>::type & + operator=(U &&Temporary) = delete; + + /// Disallow accidental assignment from a temporary. + /// + /// The declaration here is extra complicated so that "arrayRef = {}" + /// continues to select the move assignment operator. + template + typename std::enable_if::value, ArrayRef>::type & + operator=(std::initializer_list) = delete; + /// @} /// @name Expensive Operations /// @{ diff --git a/llvm/unittests/ADT/ArrayRefTest.cpp b/llvm/unittests/ADT/ArrayRefTest.cpp index 43e5005..ca75800 100644 --- a/llvm/unittests/ADT/ArrayRefTest.cpp +++ b/llvm/unittests/ADT/ArrayRefTest.cpp @@ -31,6 +31,26 @@ static_assert( !std::is_convertible, ArrayRef>::value, "Removing volatile"); +// Check that we can't accidentally assign a temporary location to an ArrayRef. +// (Unfortunately we can't make use of the same thing with constructors.) +// +// Disable this check under MSVC; even MSVC 2015 isn't inconsistent between +// std::is_assignable and actually writing such an assignment. +#if !defined(_MSC_VER) +static_assert( + !std::is_assignable, int *>::value, + "Assigning from single prvalue element"); +static_assert( + !std::is_assignable, int * &&>::value, + "Assigning from single xvalue element"); +static_assert( + std::is_assignable, int * &>::value, + "Assigning from single lvalue element"); +static_assert( + !std::is_assignable, std::initializer_list>::value, + "Assigning from an initializer list"); +#endif + namespace { TEST(ArrayRefTest, AllocatorCopy) { @@ -161,6 +181,14 @@ TEST(ArrayRefTest, InitializerList) { ArgTest12({1, 2}); } +TEST(ArrayRefTest, EmptyInitializerList) { + ArrayRef A = {}; + EXPECT_TRUE(A.empty()); + + A = {}; + EXPECT_TRUE(A.empty()); +} + // Test that makeArrayRef works on ArrayRef (no-op) TEST(ArrayRefTest, makeArrayRef) { static const int A1[] = {1, 2, 3, 4, 5, 6, 7, 8}; -- 2.7.4