Skip to content

Commit

Permalink
[lldb][test] Add a layout simulator test for std::unique_ptr (#98330)
Browse files Browse the repository at this point in the history
This is motivated by the upcoming refactor of libc++'s
`__compressed_pair` in #76756

As this will require changes to numerous LLDB libc++ data-formatters
(see early draft #96538), it
would be nice to have a test-suite that will actually exercise both the
old and new layout. We have a matrix bot that tests old versions of
Clang (but currently those only date back to Clang-15). Having them in
the test-suite will give us quicker signal on what broke.

We have an existing test that exercises various layouts of `std::string`
over time in `TestDataFormatterLibcxxStringSimulator.py`, but that's the
only STL type we have it for. This patch proposes a new
`libcxx-simulators` directory which will take the same approach for all
the STL types that we can feasibly support in this way (as @labath
points out, for some types this might just not be possible due to their
implementation complexity). Nonetheless, it'd be great to have a record
of how the layout of libc++ types changed over time.

Some related discussion:
*
#97568 (comment)
  • Loading branch information
Michael137 authored and yuxuanchen1997 committed Jul 25, 2024
1 parent abd9962 commit a4c9d84
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#ifndef STD_LLDB_COMPRESSED_PAIR_H
#define STD_LLDB_COMPRESSED_PAIR_H

#include <type_traits>
#include <utility> // for std::forward

namespace std {
namespace __lldb {

// Post-c88580c layout
struct __value_init_tag {};
struct __default_init_tag {};

template <class _Tp, int _Idx,
bool _CanBeEmptyBase =
std::is_empty<_Tp>::value && !std::is_final<_Tp>::value>
struct __compressed_pair_elem {
explicit __compressed_pair_elem(__default_init_tag) {}
explicit __compressed_pair_elem(__value_init_tag) : __value_() {}

explicit __compressed_pair_elem(_Tp __t) : __value_(__t) {}

_Tp &__get() { return __value_; }

private:
_Tp __value_;
};

template <class _Tp, int _Idx>
struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp {
explicit __compressed_pair_elem(_Tp __t) : _Tp(__t) {}
explicit __compressed_pair_elem(__default_init_tag) {}
explicit __compressed_pair_elem(__value_init_tag) : _Tp() {}

_Tp &__get() { return *this; }
};

template <class _T1, class _T2>
class __compressed_pair : private __compressed_pair_elem<_T1, 0>,
private __compressed_pair_elem<_T2, 1> {
public:
using _Base1 = __compressed_pair_elem<_T1, 0>;
using _Base2 = __compressed_pair_elem<_T2, 1>;

explicit __compressed_pair(_T1 __t1, _T2 __t2) : _Base1(__t1), _Base2(__t2) {}
explicit __compressed_pair()
: _Base1(__value_init_tag()), _Base2(__value_init_tag()) {}

template <class _U1, class _U2>
explicit __compressed_pair(_U1 &&__t1, _U2 &&__t2)
: _Base1(std::forward<_U1>(__t1)), _Base2(std::forward<_U2>(__t2)) {}

_T1 &first() { return static_cast<_Base1 &>(*this).__get(); }
};
} // namespace __lldb
} // namespace std

#endif // _H
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp
override CXXFLAGS_EXTRAS += -std=c++14
include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""
Test we can understand various layouts of the libc++'s std::unique_ptr
"""


import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class LibcxxUniquePtrDataFormatterSimulatorTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True

def test(self):
self.build()
lldbutil.run_to_source_breakpoint(
self, "Break here", lldb.SBFileSpec("main.cpp")
)
self.expect("frame variable var_up", substrs=["pointer ="])
self.expect("frame variable var_up", substrs=["deleter ="], matching=False)
self.expect(
"frame variable var_with_deleter_up", substrs=["pointer =", "deleter ="]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <libcxx-simulators-common/compressed_pair.h>

namespace std {
namespace __lldb {
template <class _Tp> struct default_delete {
default_delete() noexcept = default;

void operator()(_Tp *__ptr) const noexcept { delete __ptr; }
};

template <class _Tp, class _Dp = default_delete<_Tp>> class unique_ptr {
public:
typedef _Tp element_type;
typedef _Dp deleter_type;
typedef _Tp *pointer;

std::__lldb::__compressed_pair<pointer, deleter_type> __ptr_;
explicit unique_ptr(pointer __p) noexcept
: __ptr_(__p, std::__lldb::__value_init_tag()) {}
};
} // namespace __lldb
} // namespace std

struct StatefulDeleter {
StatefulDeleter() noexcept = default;

void operator()(int *__ptr) const noexcept { delete __ptr; }

int m_state = 50;
};

int main() {
std::__lldb::unique_ptr<int> var_up(new int(5));
std::__lldb::unique_ptr<int, StatefulDeleter> var_with_deleter_up(new int(5));
__builtin_printf("Break here\n");
return 0;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include <libcxx-simulators-common/compressed_pair.h>

#include <climits>
#include <memory>
#include <type_traits>
Expand Down Expand Up @@ -32,37 +34,6 @@
namespace std {
namespace __lldb {

template <class _Tp, int _Idx,
bool _CanBeEmptyBase =
std::is_empty<_Tp>::value && !std::is_final<_Tp>::value>
struct __compressed_pair_elem {
explicit __compressed_pair_elem(_Tp __t) : __value_(__t) {}

_Tp &__get() { return __value_; }

private:
_Tp __value_;
};

template <class _Tp, int _Idx>
struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp {
explicit __compressed_pair_elem(_Tp __t) : _Tp(__t) {}

_Tp &__get() { return *this; }
};

template <class _T1, class _T2>
class __compressed_pair : private __compressed_pair_elem<_T1, 0>,
private __compressed_pair_elem<_T2, 1> {
public:
using _Base1 = __compressed_pair_elem<_T1, 0>;
using _Base2 = __compressed_pair_elem<_T2, 1>;

explicit __compressed_pair(_T1 __t1, _T2 __t2) : _Base1(__t1), _Base2(__t2) {}

_T1 &first() { return static_cast<_Base1 &>(*this).__get(); }
};

#if defined(ALTERNATE_LAYOUT) && defined(SUBCLASS_PADDING)
template <class _CharT, size_t = sizeof(_CharT)> struct __padding {
unsigned char __xx[sizeof(_CharT) - 1];
Expand Down Expand Up @@ -212,7 +183,7 @@ template <class _CharT, class _Traits, class _Allocator> class basic_string {
};
};

__compressed_pair<__rep, allocator_type> __r_;
std::__lldb::__compressed_pair<__rep, allocator_type> __r_;

public:
template <size_t __N>
Expand Down

0 comments on commit a4c9d84

Please sign in to comment.