1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14
12 // template<class _M, class _N>
13 // constexpr common_type_t<_M,_N> lcm(_M __m, _N __n)
20 #include <type_traits>
21 #include "test_macros.h"
38 template <typename Input1
, typename Input2
, typename Output
>
39 constexpr bool test0(int in1
, int in2
, int out
)
41 auto value1
= static_cast<Input1
>(in1
);
42 auto value2
= static_cast<Input2
>(in2
);
43 static_assert(std::is_same_v
<Output
, decltype(std::lcm(value1
, value2
))>, "");
44 static_assert(std::is_same_v
<Output
, decltype(std::lcm(value2
, value1
))>, "");
45 assert(static_cast<Output
>(out
) == std::lcm(value1
, value2
));
50 template <typename Input1
, typename Input2
= Input1
>
51 constexpr bool do_test(int = 0)
53 using S1
= std::make_signed_t
<Input1
>;
54 using S2
= std::make_signed_t
<Input2
>;
55 using U1
= std::make_unsigned_t
<Input1
>;
56 using U2
= std::make_unsigned_t
<Input2
>;
57 bool accumulate
= true;
58 for (auto TC
: Cases
) {
59 { // Test with two signed types
60 using Output
= std::common_type_t
<S1
, S2
>;
61 accumulate
&= test0
<S1
, S2
, Output
>(TC
.x
, TC
.y
, TC
.expect
);
62 accumulate
&= test0
<S1
, S2
, Output
>(-TC
.x
, TC
.y
, TC
.expect
);
63 accumulate
&= test0
<S1
, S2
, Output
>(TC
.x
, -TC
.y
, TC
.expect
);
64 accumulate
&= test0
<S1
, S2
, Output
>(-TC
.x
, -TC
.y
, TC
.expect
);
65 accumulate
&= test0
<S2
, S1
, Output
>(TC
.x
, TC
.y
, TC
.expect
);
66 accumulate
&= test0
<S2
, S1
, Output
>(-TC
.x
, TC
.y
, TC
.expect
);
67 accumulate
&= test0
<S2
, S1
, Output
>(TC
.x
, -TC
.y
, TC
.expect
);
68 accumulate
&= test0
<S2
, S1
, Output
>(-TC
.x
, -TC
.y
, TC
.expect
);
70 { // test with two unsigned types
71 using Output
= std::common_type_t
<U1
, U2
>;
72 accumulate
&= test0
<U1
, U2
, Output
>(TC
.x
, TC
.y
, TC
.expect
);
73 accumulate
&= test0
<U2
, U1
, Output
>(TC
.x
, TC
.y
, TC
.expect
);
75 { // Test with mixed signs
76 using Output
= std::common_type_t
<S1
, U2
>;
77 accumulate
&= test0
<S1
, U2
, Output
>(TC
.x
, TC
.y
, TC
.expect
);
78 accumulate
&= test0
<U2
, S1
, Output
>(TC
.x
, TC
.y
, TC
.expect
);
79 accumulate
&= test0
<S1
, U2
, Output
>(-TC
.x
, TC
.y
, TC
.expect
);
80 accumulate
&= test0
<U2
, S1
, Output
>(TC
.x
, -TC
.y
, TC
.expect
);
82 { // Test with mixed signs
83 using Output
= std::common_type_t
<S2
, U1
>;
84 accumulate
&= test0
<S2
, U1
, Output
>(TC
.x
, TC
.y
, TC
.expect
);
85 accumulate
&= test0
<U1
, S2
, Output
>(TC
.x
, TC
.y
, TC
.expect
);
86 accumulate
&= test0
<S2
, U1
, Output
>(-TC
.x
, TC
.y
, TC
.expect
);
87 accumulate
&= test0
<U1
, S2
, Output
>(TC
.x
, -TC
.y
, TC
.expect
);
94 constexpr bool test_limits() {
95 assert(std::lcm(std::numeric_limits
<T
>::max() - 1, std::numeric_limits
<T
>::max() - 1) == std::numeric_limits
<T
>::max() - 1);
96 assert(std::lcm(std::numeric_limits
<T
>::max(), std::numeric_limits
<T
>::max()) == std::numeric_limits
<T
>::max());
100 int main(int argc
, char**)
102 int non_cce
= argc
; // a value that can't possibly be constexpr
104 static_assert(do_test
<signed char>(), "");
105 static_assert(do_test
<short>(), "");
106 static_assert(do_test
<int>(), "");
107 static_assert(do_test
<long>(), "");
108 static_assert(do_test
<long long>(), "");
110 assert(do_test
<signed char>(non_cce
));
111 assert(do_test
<short>(non_cce
));
112 assert(do_test
<int>(non_cce
));
113 assert(do_test
<long>(non_cce
));
114 assert(do_test
<long long>(non_cce
));
116 static_assert(do_test
<std::int8_t>(), "");
117 static_assert(do_test
<std::int16_t>(), "");
118 static_assert(do_test
<std::int32_t>(), "");
119 static_assert(do_test
<std::int64_t>(), "");
121 assert(do_test
<std::int8_t>(non_cce
));
122 assert(do_test
<std::int16_t>(non_cce
));
123 assert(do_test
<std::int32_t>(non_cce
));
124 assert(do_test
<std::int64_t>(non_cce
));
126 static_assert(do_test
<signed char, int>(), "");
127 static_assert(do_test
<int, signed char>(), "");
128 static_assert(do_test
<short, int>(), "");
129 static_assert(do_test
<int, short>(), "");
130 static_assert(do_test
<int, long>(), "");
131 static_assert(do_test
<long, int>(), "");
132 static_assert(do_test
<int, long long>(), "");
133 static_assert(do_test
<long long, int>(), "");
135 assert((do_test
<signed char, int>(non_cce
)));
136 assert((do_test
<int, signed char>(non_cce
)));
137 assert((do_test
<short, int>(non_cce
)));
138 assert((do_test
<int, short>(non_cce
)));
139 assert((do_test
<int, long>(non_cce
)));
140 assert((do_test
<long, int>(non_cce
)));
141 assert((do_test
<int, long long>(non_cce
)));
142 assert((do_test
<long long, int>(non_cce
)));
146 auto res1
= std::lcm(static_cast<std::int64_t>(1234), INT32_MIN
);
147 TEST_IGNORE_NODISCARD
std::lcm(INT_MIN
, 2UL); // this used to trigger UBSAN
148 static_assert(std::is_same_v
<decltype(res1
), std::int64_t>, "");
149 assert(res1
== 1324997410816LL);
152 // https://github.com/llvm/llvm-project/issues/96196
154 assert(test_limits
<unsigned int>());
155 assert(test_limits
<std::uint32_t>());
156 assert(test_limits
<std::uint64_t>());
157 assert(test_limits
<int>());
158 assert(test_limits
<std::int32_t>());
159 assert(test_limits
<std::int64_t>());
161 static_assert(test_limits
<unsigned int>(), "");
162 static_assert(test_limits
<std::uint32_t>(), "");
163 static_assert(test_limits
<std::uint64_t>(), "");
164 static_assert(test_limits
<int>(), "");
165 static_assert(test_limits
<std::int32_t>(), "");
166 static_assert(test_limits
<std::int64_t>(), "");