-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc++] Add tests to pin down the ABI of deque, list and vector #80191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-libcxx Author: Nikolas Klauser (philnik777) ChangesFull diff: https://github.com/llvm/llvm-project/pull/80191.diff 4 Files Affected:
diff --git a/libcxx/test/libcxx/containers/sequences/deque/abi.compile.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/abi.compile.pass.cpp
index 37e87d59503ee..6d92ca31dc599 100644
--- a/libcxx/test/libcxx/containers/sequences/deque/abi.compile.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/deque/abi.compile.pass.cpp
@@ -22,7 +22,7 @@ class small_iter_allocator {
public:
using value_type = T;
using pointer = small_pointer<T>;
- using size_type = std::int16_t;
+ using size_type = std::uint16_t;
using difference_type = std::int16_t;
small_iter_allocator() TEST_NOEXCEPT {}
@@ -37,27 +37,51 @@ class small_iter_allocator {
friend bool operator!=(small_iter_allocator, small_iter_allocator) { return false; }
};
+template <class T>
+class final_small_iter_allocator final {
+public:
+ using value_type = T;
+ using pointer = small_pointer<T>;
+ using size_type = std::uint16_t;
+ using difference_type = std::int16_t;
+
+ final_small_iter_allocator() TEST_NOEXCEPT {}
+
+ template <class U>
+ final_small_iter_allocator(final_small_iter_allocator<U>) TEST_NOEXCEPT {}
+
+ T* allocate(std::size_t n);
+ void deallocate(T* p, std::size_t);
+
+ friend bool operator==(final_small_iter_allocator, final_small_iter_allocator) { return true; }
+ friend bool operator!=(final_small_iter_allocator, final_small_iter_allocator) { return false; }
+};
+
#if __SIZE_WIDTH__ == 64
static_assert(sizeof(std::deque<int>) == 48, "");
static_assert(sizeof(std::deque<int, min_allocator<int> >) == 48, "");
static_assert(sizeof(std::deque<int, test_allocator<int> >) == 80, "");
static_assert(sizeof(std::deque<int, small_iter_allocator<int> >) == 12, "");
+static_assert(sizeof(std::deque<int, final_small_iter_allocator<int> >) == 16, "");
static_assert(sizeof(std::deque<char>) == 48, "");
static_assert(sizeof(std::deque<char, min_allocator<char> >) == 48, "");
static_assert(sizeof(std::deque<char, test_allocator<char> >) == 80, "");
static_assert(sizeof(std::deque<char, small_iter_allocator<char> >) == 12, "");
+static_assert(sizeof(std::deque<char, final_small_iter_allocator<char> >) == 16, "");
static_assert(TEST_ALIGNOF(std::deque<int>) == 8, "");
static_assert(TEST_ALIGNOF(std::deque<int, min_allocator<int> >) == 8, "");
static_assert(TEST_ALIGNOF(std::deque<int, test_allocator<int> >) == 8, "");
static_assert(TEST_ALIGNOF(std::deque<int, small_iter_allocator<int> >) == 2, "");
+static_assert(TEST_ALIGNOF(std::deque<int, final_small_iter_allocator<int> >) == 2, "");
static_assert(TEST_ALIGNOF(std::deque<char>) == 8, "");
static_assert(TEST_ALIGNOF(std::deque<char, min_allocator<char> >) == 8, "");
static_assert(TEST_ALIGNOF(std::deque<char, test_allocator<char> >) == 8, "");
static_assert(TEST_ALIGNOF(std::deque<char, small_iter_allocator<char> >) == 2, "");
+static_assert(TEST_ALIGNOF(std::deque<char, final_small_iter_allocator<char> >) == 2, "");
#elif __SIZE_WIDTH__ == 32
@@ -65,21 +89,25 @@ static_assert(sizeof(std::deque<int>) == 24, "");
static_assert(sizeof(std::deque<int, min_allocator<int> >) == 24, "");
static_assert(sizeof(std::deque<int, test_allocator<int> >) == 48, "");
static_assert(sizeof(std::deque<int, small_iter_allocator<int> >) == 12, "");
+static_assert(sizeof(std::deque<int, final_small_iter_allocator<int> >) == 12, "");
static_assert(sizeof(std::deque<char>) == 24, "");
static_assert(sizeof(std::deque<char, min_allocator<char> >) == 24, "");
static_assert(sizeof(std::deque<char, test_allocator<char> >) == 48, "");
static_assert(sizeof(std::deque<char, small_iter_allocator<char> >) == 12, "");
+static_assert(sizeof(std::deque<char, final_small_iter_allocator<char> >) == 12, "");
static_assert(TEST_ALIGNOF(std::deque<int>) == 4, "");
static_assert(TEST_ALIGNOF(std::deque<int, min_allocator<int> >) == 4, "");
static_assert(TEST_ALIGNOF(std::deque<int, test_allocator<int> >) == 4, "");
static_assert(TEST_ALIGNOF(std::deque<int, small_iter_allocator<int> >) == 2, "");
+static_assert(TEST_ALIGNOF(std::deque<int, final_small_iter_allocator<int> >) == 2, "");
static_assert(TEST_ALIGNOF(std::deque<char>) == 4, "");
static_assert(TEST_ALIGNOF(std::deque<char, min_allocator<char> >) == 4, "");
static_assert(TEST_ALIGNOF(std::deque<char, test_allocator<char> >) == 4, "");
static_assert(TEST_ALIGNOF(std::deque<char, small_iter_allocator<char> >) == 2, "");
+static_assert(TEST_ALIGNOF(std::deque<char, final_small_iter_allocator<char> >) == 2, "");
#else
# error std::size_t has an unexpected size
diff --git a/libcxx/test/libcxx/containers/sequences/list/abi.compile.pass.cpp b/libcxx/test/libcxx/containers/sequences/list/abi.compile.pass.cpp
new file mode 100644
index 0000000000000..39ae10d047f25
--- /dev/null
+++ b/libcxx/test/libcxx/containers/sequences/list/abi.compile.pass.cpp
@@ -0,0 +1,86 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <list>
+
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
+
+template <class T>
+class small_pointer {
+ std::uint16_t offset;
+};
+
+template <class T>
+class small_iter_allocator {
+public:
+ using value_type = T;
+ using pointer = small_pointer<T>;
+ using size_type = std::int16_t;
+ using difference_type = std::int16_t;
+
+ small_iter_allocator() TEST_NOEXCEPT {}
+
+ template <class U>
+ small_iter_allocator(small_iter_allocator<U>) TEST_NOEXCEPT {}
+
+ T* allocate(std::size_t n);
+ void deallocate(T* p, std::size_t);
+
+ friend bool operator==(small_iter_allocator, small_iter_allocator) { return true; }
+ friend bool operator!=(small_iter_allocator, small_iter_allocator) { return false; }
+};
+
+#if __SIZE_WIDTH__ == 64
+
+static_assert(sizeof(std::list<int>) == 24, "");
+static_assert(sizeof(std::list<int, min_allocator<int> >) == 24, "");
+static_assert(sizeof(std::list<int, test_allocator<int> >) == 40, "");
+static_assert(sizeof(std::list<int, small_iter_allocator<int> >) == 6, "");
+
+static_assert(sizeof(std::list<char>) == 24, "");
+static_assert(sizeof(std::list<char, min_allocator<char> >) == 24, "");
+static_assert(sizeof(std::list<char, test_allocator<char> >) == 40, "");
+static_assert(sizeof(std::list<char, small_iter_allocator<char> >) == 6, "");
+
+static_assert(TEST_ALIGNOF(std::list<int>) == 8, "");
+static_assert(TEST_ALIGNOF(std::list<int, min_allocator<int> >) == 8, "");
+static_assert(TEST_ALIGNOF(std::list<int, test_allocator<int> >) == 8, "");
+static_assert(TEST_ALIGNOF(std::list<int, small_iter_allocator<int> >) == 2, "");
+
+static_assert(TEST_ALIGNOF(std::list<char>) == 8, "");
+static_assert(TEST_ALIGNOF(std::list<char, min_allocator<char> >) == 8, "");
+static_assert(TEST_ALIGNOF(std::list<char, test_allocator<char> >) == 8, "");
+static_assert(TEST_ALIGNOF(std::list<char, small_iter_allocator<char> >) == 2, "");
+
+#elif __SIZE_WIDTH__ == 32
+
+static_assert(sizeof(std::list<int>) == 24, "");
+static_assert(sizeof(std::list<int, min_allocator<int> >) == 24, "");
+static_assert(sizeof(std::list<int, test_allocator<int> >) == 24, "");
+static_assert(sizeof(std::list<int, small_iter_allocator<int> >) == 6, "");
+
+static_assert(sizeof(std::list<char>) == 24, "");
+static_assert(sizeof(std::list<char, min_allocator<char> >) == 24, "");
+static_assert(sizeof(std::list<char, test_allocator<char> >) == 24, "");
+static_assert(sizeof(std::list<char, small_iter_allocator<char> >) == 6, "");
+
+static_assert(TEST_ALIGNOF(std::list<int>) == 4, "");
+static_assert(TEST_ALIGNOF(std::list<int, min_allocator<int> >) == 4, "");
+static_assert(TEST_ALIGNOF(std::list<int, test_allocator<int> >) == 4, "");
+static_assert(TEST_ALIGNOF(std::list<int, small_iter_allocator<int> >) == 2, "");
+
+static_assert(TEST_ALIGNOF(std::list<char>) == 4, "");
+static_assert(TEST_ALIGNOF(std::list<char, min_allocator<char> >) == 4, "");
+static_assert(TEST_ALIGNOF(std::list<char, test_allocator<char> >) == 4, "");
+static_assert(TEST_ALIGNOF(std::list<char, small_iter_allocator<char> >) == 2, "");
+
+#else
+# error std::size_t has an unexpected size
+#endif
diff --git a/libcxx/test/libcxx/containers/sequences/vector.bool/abi.compile.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector.bool/abi.compile.pass.cpp
new file mode 100644
index 0000000000000..1086d38c33f8c
--- /dev/null
+++ b/libcxx/test/libcxx/containers/sequences/vector.bool/abi.compile.pass.cpp
@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <vector>
+
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
+
+template <class T>
+class small_pointer {
+ std::uint16_t offset;
+};
+
+template <class T>
+class small_iter_allocator {
+public:
+ using value_type = T;
+ using pointer = small_pointer<T>;
+ using size_type = std::int16_t;
+ using difference_type = std::int16_t;
+
+ small_iter_allocator() TEST_NOEXCEPT {}
+
+ template <class U>
+ small_iter_allocator(small_iter_allocator<U>) TEST_NOEXCEPT {}
+
+ T* allocate(std::size_t n);
+ void deallocate(T* p, std::size_t);
+
+ friend bool operator==(small_iter_allocator, small_iter_allocator) { return true; }
+ friend bool operator!=(small_iter_allocator, small_iter_allocator) { return false; }
+};
+
+#if __SIZE_WIDTH__ == 64
+
+static_assert(sizeof(std::vector<bool>) == 24, "");
+static_assert(sizeof(std::vector<bool, min_allocator<bool> >) == 24, "");
+static_assert(sizeof(std::vector<bool, test_allocator<bool> >) == 40, "");
+static_assert(sizeof(std::vector<bool, small_iter_allocator<bool> >) == 6, "");
+
+static_assert(TEST_ALIGNOF(std::vector<bool>) == 8, "");
+static_assert(TEST_ALIGNOF(std::vector<bool, min_allocator<bool> >) == 8, "");
+static_assert(TEST_ALIGNOF(std::vector<bool, test_allocator<bool> >) == 8, "");
+static_assert(TEST_ALIGNOF(std::vector<bool, small_iter_allocator<bool> >) == 2, "");
+
+#elif __SIZE_WIDTH__ == 32
+
+static_assert(sizeof(std::vector<bool>) == 24, "");
+static_assert(sizeof(std::vector<bool, min_allocator<bool> >) == 24, "");
+static_assert(sizeof(std::vector<bool, test_allocator<bool> >) == 24, "");
+static_assert(sizeof(std::vector<bool, small_iter_allocator<bool> >) == 6, "");
+
+static_assert(TEST_ALIGNOF(std::vector<bool>) == 4, "");
+static_assert(TEST_ALIGNOF(std::vector<bool, min_allocator<bool> >) == 4, "");
+static_assert(TEST_ALIGNOF(std::vector<bool, test_allocator<bool> >) == 4, "");
+static_assert(TEST_ALIGNOF(std::vector<bool, small_iter_allocator<bool> >) == 2, "");
+
+#else
+# error std::size_t has an unexpected size
+#endif
diff --git a/libcxx/test/libcxx/containers/sequences/vector/abi.compile.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/abi.compile.pass.cpp
new file mode 100644
index 0000000000000..26a465a7dd8b9
--- /dev/null
+++ b/libcxx/test/libcxx/containers/sequences/vector/abi.compile.pass.cpp
@@ -0,0 +1,86 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <vector>
+
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
+
+template <class T>
+class small_pointer {
+ std::uint16_t offset;
+};
+
+template <class T>
+class small_iter_allocator {
+public:
+ using value_type = T;
+ using pointer = small_pointer<T>;
+ using size_type = std::int16_t;
+ using difference_type = std::int16_t;
+
+ small_iter_allocator() TEST_NOEXCEPT {}
+
+ template <class U>
+ small_iter_allocator(small_iter_allocator<U>) TEST_NOEXCEPT {}
+
+ T* allocate(std::size_t n);
+ void deallocate(T* p, std::size_t);
+
+ friend bool operator==(small_iter_allocator, small_iter_allocator) { return true; }
+ friend bool operator!=(small_iter_allocator, small_iter_allocator) { return false; }
+};
+
+#if __SIZE_WIDTH__ == 64
+
+static_assert(sizeof(std::vector<int>) == 24, "");
+static_assert(sizeof(std::vector<int, min_allocator<int> >) == 24, "");
+static_assert(sizeof(std::vector<int, test_allocator<int> >) == 40, "");
+static_assert(sizeof(std::vector<int, small_iter_allocator<int> >) == 6, "");
+
+static_assert(sizeof(std::vector<char>) == 24, "");
+static_assert(sizeof(std::vector<char, min_allocator<char> >) == 24, "");
+static_assert(sizeof(std::vector<char, test_allocator<char> >) == 40, "");
+static_assert(sizeof(std::vector<char, small_iter_allocator<char> >) == 6, "");
+
+static_assert(TEST_ALIGNOF(std::vector<int>) == 8, "");
+static_assert(TEST_ALIGNOF(std::vector<int, min_allocator<int> >) == 8, "");
+static_assert(TEST_ALIGNOF(std::vector<int, test_allocator<int> >) == 8, "");
+static_assert(TEST_ALIGNOF(std::vector<int, small_iter_allocator<int> >) == 2, "");
+
+static_assert(TEST_ALIGNOF(std::vector<char>) == 8, "");
+static_assert(TEST_ALIGNOF(std::vector<char, min_allocator<char> >) == 8, "");
+static_assert(TEST_ALIGNOF(std::vector<char, test_allocator<char> >) == 8, "");
+static_assert(TEST_ALIGNOF(std::vector<char, small_iter_allocator<char> >) == 2, "");
+
+#elif __SIZE_WIDTH__ == 32
+
+static_assert(sizeof(std::vector<int>) == 24, "");
+static_assert(sizeof(std::vector<int, min_allocator<int> >) == 24, "");
+static_assert(sizeof(std::vector<int, test_allocator<int> >) == 24, "");
+static_assert(sizeof(std::vector<int, small_iter_allocator<int> >) == 6, "");
+
+static_assert(sizeof(std::vector<char>) == 24, "");
+static_assert(sizeof(std::vector<char, min_allocator<char> >) == 24, "");
+static_assert(sizeof(std::vector<char, test_allocator<char> >) == 24, "");
+static_assert(sizeof(std::vector<char, small_iter_allocator<char> >) == 6, "");
+
+static_assert(TEST_ALIGNOF(std::vector<int>) == 4, "");
+static_assert(TEST_ALIGNOF(std::vector<int, min_allocator<int> >) == 4, "");
+static_assert(TEST_ALIGNOF(std::vector<int, test_allocator<int> >) == 4, "");
+static_assert(TEST_ALIGNOF(std::vector<int, small_iter_allocator<int> >) == 2, "");
+
+static_assert(TEST_ALIGNOF(std::vector<char>) == 4, "");
+static_assert(TEST_ALIGNOF(std::vector<char, min_allocator<char> >) == 4, "");
+static_assert(TEST_ALIGNOF(std::vector<char, test_allocator<char> >) == 4, "");
+static_assert(TEST_ALIGNOF(std::vector<char, small_iter_allocator<char> >) == 2, "");
+
+#else
+# error std::size_t has an unexpected size
+#endif
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM w/ green CI -- you seem to be missing something for 32 bit platforms.
Thanks for the patch, this seems really useful to guard against regressions! I mainly glossed over the approval to Louis. |
…g __compressed_pair with [[no_unique_address]]
583129d
to
4785bd0
Compare
This patch adds tests that lock down the ABI of types like deque, list and vector.
An upcoming patch will replace the usage of __compressed_pair in these classes
by [[no_unique_address]], so we are adding these tests to pin down their ABI
before making the change. That way, we can be confident that the patch making
the actual ABI-sensitive change is safe if it doesn't break these tests.