summaryrefslogtreecommitdiffstats
path: root/libcxx
diff options
context:
space:
mode:
authorEric Fiselier <eric@efcs.ca>2020-02-19 11:59:37 -0500
committerHans Wennborg <hans@chromium.org>2020-02-20 15:32:05 +0100
commit7a18790ae2f4b92dc26b2be963e588c8837d0076 (patch)
treeb1bb19d1370885c0f6a9a07ea8f4050589daa49e /libcxx
parenta572a8a147c76b9d31585c2d4257a5db566c9a9d (diff)
downloadbcm5719-llvm-7a18790ae2f4b92dc26b2be963e588c8837d0076.tar.gz
bcm5719-llvm-7a18790ae2f4b92dc26b2be963e588c8837d0076.zip
[libc++] Fix ABI break in __bit_reference.
The libc++ __bit_iterator type has weird ABI calling conventions as a quirk of the implementation. The const bit iterator is trivial, but the non-const bit iterator is not because it declares a user-defined copy constructor. Changing this now is an ABI break, so this test ensures that each type is trivial/non-trivial as expected. The definition of 'non-trivial for the purposes of calls': A type is considered non-trivial for the purposes of calls if: * it has a non-trivial copy constructor, move constructor, or destructor, or * all of its copy and move constructors are deleted. (cherry picked from commit a829443cc7359ecf0f2de8f82519f511795675ec)
Diffstat (limited to 'libcxx')
-rw-r--r--libcxx/include/__bit_reference15
-rw-r--r--libcxx/test/libcxx/containers/sequences/vector.bool/trivial_for_purposes_of_call.pass.cpp57
2 files changed, 72 insertions, 0 deletions
diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference
index 3d4da1cbb68..4a2b82064b3 100644
--- a/libcxx/include/__bit_reference
+++ b/libcxx/include/__bit_reference
@@ -1122,6 +1122,21 @@ public:
__bit_iterator(const __type_for_copy_to_const& __it) _NOEXCEPT
: __seg_(__it.__seg_), __ctz_(__it.__ctz_) {}
+ // The non-const __bit_iterator has historically had a non-trivial
+ // copy constructor (as a quirk of its construction). We need to maintain
+ // this for ABI purposes.
+ using __type_for_abi_non_trivial_copy_ctor =
+ _If<!_IsConst, __bit_iterator, struct __private_nat>;
+
+ _LIBCPP_INLINE_VISIBILITY
+ __bit_iterator(__type_for_abi_non_trivial_copy_ctor const& __it) _NOEXCEPT
+ : __seg_(__it.__seg_), __ctz_(__it.__ctz_) {}
+
+ // Always declare the copy assignment operator since the implicit declaration
+ // is deprecated.
+ _LIBCPP_INLINE_VISIBILITY
+ __bit_iterator& operator=(__bit_iterator const&) = default;
+
_LIBCPP_INLINE_VISIBILITY reference operator*() const _NOEXCEPT
{return reference(__seg_, __storage_type(1) << __ctz_);}
diff --git a/libcxx/test/libcxx/containers/sequences/vector.bool/trivial_for_purposes_of_call.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector.bool/trivial_for_purposes_of_call.pass.cpp
new file mode 100644
index 00000000000..7b0b5c427c6
--- /dev/null
+++ b/libcxx/test/libcxx/containers/sequences/vector.bool/trivial_for_purposes_of_call.pass.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <vector>
+
+// typedef ... iterator;
+// typedef ... const_iterator;
+
+// The libc++ __bit_iterator type has weird ABI calling conventions as a quirk
+// of the implementation. The const bit iterator is trivial, but the non-const
+// bit iterator is not because it declares a user-defined copy constructor.
+//
+// Changing this now is an ABI break, so this test ensures that each type
+// is trivial/non-trivial as expected.
+
+// The definition of 'non-trivial for the purposes of calls':
+// A type is considered non-trivial for the purposes of calls if:
+// * it has a non-trivial copy constructor, move constructor, or
+// destructor, or
+// * all of its copy and move constructors are deleted.
+
+// UNSUPPORTED: c++98, c++03
+
+#include <vector>
+#include <cassert>
+
+#include "test_macros.h"
+
+template <class T>
+using IsTrivialForCall = std::integral_constant<bool,
+ std::is_trivially_copy_constructible<T>::value &&
+ std::is_trivially_move_constructible<T>::value &&
+ std::is_trivially_destructible<T>::value
+ // Ignore the all-deleted case, it shouldn't occur here.
+ >;
+
+void test_const_iterator() {
+ using It = std::vector<bool>::const_iterator;
+ static_assert(IsTrivialForCall<It>::value, "");
+}
+
+void test_non_const_iterator() {
+ using It = std::vector<bool>::iterator;
+ static_assert(!IsTrivialForCall<It>::value, "");
+}
+
+int main(int, char**) {
+ test_const_iterator();
+ test_non_const_iterator();
+
+ return 0;
+}
OpenPOWER on IntegriCloud