Skip to content

Commit 7f35f39

Browse files
committed
🐛 Fix lists with incomplete types
Problem: - `intrusive_list` and `intrusive_forward_list` are constrained so that they can take incomplete types. This means using an incomplete type in a SFINAE context, which causes an error with GCC 16 (probably because it can lead to an ODR violation). Solution: - Use mandates, not requires; i.e. instead of concept-constraining, `static_assert` completeness in functions that need it.
1 parent 45b489f commit 7f35f39

3 files changed

Lines changed: 16 additions & 4 deletions

File tree

include/stdx/detail/list_common.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ concept base_double_linkable = base_single_linkable<T> and requires(T node) {
2323
} // namespace detail
2424

2525
template <typename T>
26-
concept single_linkable = not complete<T> or requires(T *node) {
26+
concept single_linkable = requires(T *node) {
2727
requires detail::base_single_linkable<
2828
std::remove_cvref_t<decltype(node->next)>>;
2929
};
3030

3131
template <typename T>
32-
concept double_linkable = not complete<T> or requires(T *node) {
32+
concept double_linkable = requires(T *node) {
3333
requires detail::base_double_linkable<
3434
std::remove_cvref_t<decltype(node->next)>>;
3535
requires detail::base_double_linkable<
@@ -46,6 +46,7 @@ constexpr auto
4646
namespace node_policy {
4747
template <typename Node> class checked {
4848
constexpr static auto valid_for_push(Node *node) -> bool {
49+
static_assert(single_linkable<Node>);
4950
if constexpr (detail::detect::has_prev_pointer<Node>) {
5051
return node->prev == nullptr and node->next == nullptr;
5152
} else {
@@ -79,13 +80,15 @@ template <typename Node> class checked {
7980
}
8081

8182
constexpr static auto on_pop(Node *node) {
83+
static_assert(single_linkable<Node>);
8284
if constexpr (detail::detect::has_prev_pointer<Node>) {
8385
node->prev = nullptr;
8486
}
8587
node->next = nullptr;
8688
}
8789

8890
constexpr static auto on_clear(Node *head) {
91+
static_assert(single_linkable<Node>);
8992
while (head != nullptr) {
9093
if constexpr (detail::detect::has_prev_pointer<Node>) {
9194
head->prev = nullptr;

include/stdx/intrusive_forward_list.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
namespace stdx {
88
inline namespace v1 {
9-
template <single_linkable NodeType,
9+
template <typename NodeType,
1010
template <typename> typename P = node_policy::checked>
1111
class intrusive_forward_list {
1212
friend P<NodeType>;
@@ -58,6 +58,7 @@ class intrusive_forward_list {
5858
pointer tail{};
5959

6060
constexpr auto unchecked_push_front(pointer n) -> void {
61+
static_assert(single_linkable<value_type>);
6162
n->next = head;
6263
head = n;
6364
if (tail == nullptr) {
@@ -66,6 +67,7 @@ class intrusive_forward_list {
6667
}
6768

6869
constexpr auto unchecked_push_back(pointer n) -> void {
70+
static_assert(single_linkable<value_type>);
6971
if (tail != nullptr) {
7072
tail->next = n;
7173
}
@@ -99,6 +101,7 @@ class intrusive_forward_list {
99101
}
100102

101103
constexpr auto pop_front() -> pointer {
104+
static_assert(single_linkable<value_type>);
102105
pointer poppedNode = head;
103106
head = head->next;
104107

include/stdx/intrusive_list.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
namespace stdx {
88
inline namespace v1 {
9-
template <double_linkable NodeType,
9+
template <typename NodeType,
1010
template <typename> typename P = node_policy::checked>
1111
class intrusive_list {
1212
friend P<NodeType>;
@@ -58,6 +58,7 @@ class intrusive_list {
5858
pointer tail{};
5959

6060
constexpr auto unchecked_push_front(pointer n) -> void {
61+
static_assert(double_linkable<value_type>);
6162
if (head != nullptr) {
6263
head->prev = n;
6364
}
@@ -70,6 +71,7 @@ class intrusive_list {
7071
}
7172

7273
constexpr auto unchecked_push_back(pointer n) -> void {
74+
static_assert(double_linkable<value_type>);
7375
if (tail != nullptr) {
7476
tail->next = n;
7577
}
@@ -82,6 +84,7 @@ class intrusive_list {
8284
}
8385

8486
constexpr auto unchecked_insert(iterator it, pointer n) -> void {
87+
static_assert(double_linkable<value_type>);
8588
if (it != end()) {
8689
auto p = it.operator->();
8790
n->next = p;
@@ -128,6 +131,7 @@ class intrusive_list {
128131
}
129132

130133
constexpr auto pop_front() -> pointer {
134+
static_assert(double_linkable<value_type>);
131135
pointer poppedNode = head;
132136
head = head->next;
133137

@@ -142,6 +146,7 @@ class intrusive_list {
142146
}
143147

144148
constexpr auto pop_back() -> pointer {
149+
static_assert(double_linkable<value_type>);
145150
pointer poppedNode = tail;
146151
tail = tail->prev;
147152

@@ -166,6 +171,7 @@ class intrusive_list {
166171
}
167172

168173
constexpr auto remove(pointer n) -> void {
174+
static_assert(double_linkable<value_type>);
169175
pointer nextNode = n->next;
170176
pointer prevNode = n->prev;
171177

0 commit comments

Comments
 (0)