Skip to content

Commit bf434a5

Browse files
committed
Improve the representation of <compare>'s zero-only type.
* Use an empty struct instead of a member pointer to represent this type, so that we don't actually pass a zero member pointer at runtime. * Mark the constructor as consteval to ensure that no code is emitted for it whenever possible. * Add a honeypot constructor to reject all non-int arguments, so that the only argument that can arrive at the real constructor is the literal 0. This results in better generated code, and rejecting invalid comparisons against nullptr, 0L, and so on, while also rejecting invalid comparisons against (1-1) and similar that would be allowed if we required an integer constant expression with value 0. Differential Revision: https://reviews.llvm.org/D85051
1 parent d256797 commit bf434a5

File tree

3 files changed

+73
-2
lines changed

3 files changed

+73
-2
lines changed

libcxx/include/__config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,12 @@ typedef unsigned int char32_t;
837837
# define _LIBCPP_CONSTEXPR constexpr
838838
#endif
839839

840+
#ifndef __cpp_consteval
841+
# define _LIBCPP_CONSTEVAL _LIBCPP_CONSTEXPR
842+
#else
843+
# define _LIBCPP_CONSTEVAL consteval
844+
#endif
845+
840846
#ifdef _LIBCPP_CXX03_LANG
841847
# define _LIBCPP_DEFAULT {}
842848
#else

libcxx/include/compare

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,13 @@ enum class _LIBCPP_ENUM_VIS _NCmpResult : signed char {
154154
__unordered = -127
155155
};
156156

157-
struct _CmpUnspecifiedType;
158-
using _CmpUnspecifiedParam = void (_CmpUnspecifiedType::*)();
157+
struct _CmpUnspecifiedParam {
158+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEVAL
159+
_CmpUnspecifiedParam(int _CmpUnspecifiedParam::*) {}
160+
161+
template<typename _Tp, typename = _VSTD::enable_if_t<!_VSTD::is_same_v<_Tp, int>>>
162+
_CmpUnspecifiedParam(_Tp) = delete;
163+
};
159164

160165
class weak_equality {
161166
_LIBCPP_INLINE_VISIBILITY
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
// UNSUPPORTED: c++03, c++11, c++14, c++17
11+
12+
// <compare>
13+
14+
// Ensure we reject all cases where an argument other than a literal 0 is used
15+
// for a comparison against a comparison category type.
16+
17+
#include <compare>
18+
19+
#define TEST_OP(v, op) \
20+
void(v op 0L); \
21+
void(0L op v); \
22+
void(v op nullptr); \
23+
void(nullptr op v); \
24+
void(v op(1 - 1)); \
25+
void((1 - 1) op v);
26+
27+
template <typename T>
28+
void test_category(T v) {
29+
TEST_OP(v, ==); // expected-error 18 {{}}
30+
TEST_OP(v, !=); // expected-error 18 {{}}
31+
TEST_OP(v, <); // expected-error 18 {{}}
32+
TEST_OP(v, <=); // expected-error 18 {{}}
33+
TEST_OP(v, >); // expected-error 18 {{}}
34+
TEST_OP(v, >=); // expected-error 18 {{}}
35+
TEST_OP(v, <=>); // expected-error 18 {{}}
36+
37+
void(v == 0);
38+
void(0 == v);
39+
void(v != 0);
40+
void(0 != v);
41+
void(v < 0);
42+
void(0 < v);
43+
void(v <= 0);
44+
void(0 <= v);
45+
void(v > 0);
46+
void(0 > v);
47+
void(v >= 0);
48+
void(0 >= v);
49+
#ifndef _LIBCPP_HAS_NO_THREE_WAY_COMPARISON
50+
void(v <=> 0); // expected-error 3 {{}}
51+
void(0 <=> v); // expected-error 3 {{}}
52+
#endif
53+
}
54+
55+
int main(int, char**) {
56+
test_category(std::strong_ordering::equivalent);
57+
test_category(std::weak_ordering::equivalent);
58+
test_category(std::partial_ordering::equivalent);
59+
return 0;
60+
}

0 commit comments

Comments
 (0)