-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc++][ratio] Avoids accepting unrelated types. #80491
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: Mark de Wever (mordante) ChangesThe arithemtic and comparison operations are ill-formed when R1 or R2 is not a std::ratio. Fixes: #63753 Full diff: https://github.com/llvm/llvm-project/pull/80491.diff 4 Files Affected:
diff --git a/libcxx/include/ratio b/libcxx/include/ratio
index 3b11a2aa5bf6e..8563a0a1113ce 100644
--- a/libcxx/include/ratio
+++ b/libcxx/include/ratio
@@ -289,6 +289,9 @@ private:
static const intmax_t __gcd_n1_d2 = __static_gcd<_R1::num, _R2::den>::value;
static const intmax_t __gcd_d1_n2 = __static_gcd<_R1::den, _R2::num>::value;
+ static_assert(__is_ratio<_R1>::value, "[ratio.general]/2 requires R1 to be a specialication of the ratio template");
+ static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialication of the ratio template");
+
public:
typedef typename ratio< __ll_mul<_R1::num / __gcd_n1_d2, _R2::num / __gcd_d1_n2>::value,
__ll_mul<_R2::den / __gcd_n1_d2, _R1::den / __gcd_d1_n2>::value >::type type;
@@ -312,6 +315,9 @@ private:
static const intmax_t __gcd_n1_n2 = __static_gcd<_R1::num, _R2::num>::value;
static const intmax_t __gcd_d1_d2 = __static_gcd<_R1::den, _R2::den>::value;
+ static_assert(__is_ratio<_R1>::value, "[ratio.general]/2 requires R1 to be a specialication of the ratio template");
+ static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialication of the ratio template");
+
public:
typedef typename ratio< __ll_mul<_R1::num / __gcd_n1_n2, _R2::den / __gcd_d1_d2>::value,
__ll_mul<_R2::num / __gcd_n1_n2, _R1::den / __gcd_d1_d2>::value >::type type;
@@ -335,6 +341,9 @@ private:
static const intmax_t __gcd_n1_n2 = __static_gcd<_R1::num, _R2::num>::value;
static const intmax_t __gcd_d1_d2 = __static_gcd<_R1::den, _R2::den>::value;
+ static_assert(__is_ratio<_R1>::value, "[ratio.general]/2 requires R1 to be a specialication of the ratio template");
+ static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialication of the ratio template");
+
public:
typedef typename ratio_multiply<
ratio<__gcd_n1_n2, _R1::den / __gcd_d1_d2>,
@@ -361,6 +370,9 @@ private:
static const intmax_t __gcd_n1_n2 = __static_gcd<_R1::num, _R2::num>::value;
static const intmax_t __gcd_d1_d2 = __static_gcd<_R1::den, _R2::den>::value;
+ static_assert(__is_ratio<_R1>::value, "[ratio.general]/2 requires R1 to be a specialication of the ratio template");
+ static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialication of the ratio template");
+
public:
typedef typename ratio_multiply<
ratio<__gcd_n1_n2, _R1::den / __gcd_d1_d2>,
@@ -384,10 +396,16 @@ struct _LIBCPP_TEMPLATE_VIS ratio_subtract : public __ratio_subtract<_R1, _R2>::
// ratio_equal
template <class _R1, class _R2>
-struct _LIBCPP_TEMPLATE_VIS ratio_equal : _BoolConstant<(_R1::num == _R2::num && _R1::den == _R2::den)> {};
+struct _LIBCPP_TEMPLATE_VIS ratio_equal : _BoolConstant<(_R1::num == _R2::num && _R1::den == _R2::den)> {
+ static_assert(__is_ratio<_R1>::value, "[ratio.general]/2 requires R1 to be a specialication of the ratio template");
+ static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialication of the ratio template");
+};
template <class _R1, class _R2>
-struct _LIBCPP_TEMPLATE_VIS ratio_not_equal : _BoolConstant<!ratio_equal<_R1, _R2>::value> {};
+struct _LIBCPP_TEMPLATE_VIS ratio_not_equal : _BoolConstant<!ratio_equal<_R1, _R2>::value> {
+ static_assert(__is_ratio<_R1>::value, "[ratio.general]/2 requires R1 to be a specialication of the ratio template");
+ static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialication of the ratio template");
+};
// ratio_less
@@ -441,16 +459,28 @@ struct __ratio_less<_R1, _R2, -1LL, -1LL> {
};
template <class _R1, class _R2>
-struct _LIBCPP_TEMPLATE_VIS ratio_less : _BoolConstant<__ratio_less<_R1, _R2>::value> {};
+struct _LIBCPP_TEMPLATE_VIS ratio_less : _BoolConstant<__ratio_less<_R1, _R2>::value> {
+ static_assert(__is_ratio<_R1>::value, "[ratio.general]/2 requires R1 to be a specialication of the ratio template");
+ static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialication of the ratio template");
+};
template <class _R1, class _R2>
-struct _LIBCPP_TEMPLATE_VIS ratio_less_equal : _BoolConstant<!ratio_less<_R2, _R1>::value> {};
+struct _LIBCPP_TEMPLATE_VIS ratio_less_equal : _BoolConstant<!ratio_less<_R2, _R1>::value> {
+ static_assert(__is_ratio<_R1>::value, "[ratio.general]/2 requires R1 to be a specialication of the ratio template");
+ static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialication of the ratio template");
+};
template <class _R1, class _R2>
-struct _LIBCPP_TEMPLATE_VIS ratio_greater : _BoolConstant<ratio_less<_R2, _R1>::value> {};
+struct _LIBCPP_TEMPLATE_VIS ratio_greater : _BoolConstant<ratio_less<_R2, _R1>::value> {
+ static_assert(__is_ratio<_R1>::value, "[ratio.general]/2 requires R1 to be a specialication of the ratio template");
+ static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialication of the ratio template");
+};
template <class _R1, class _R2>
-struct _LIBCPP_TEMPLATE_VIS ratio_greater_equal : _BoolConstant<!ratio_less<_R1, _R2>::value> {};
+struct _LIBCPP_TEMPLATE_VIS ratio_greater_equal : _BoolConstant<!ratio_less<_R1, _R2>::value> {
+ static_assert(__is_ratio<_R1>::value, "[ratio.general]/2 requires R1 to be a specialication of the ratio template");
+ static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialication of the ratio template");
+};
template <class _R1, class _R2>
struct __ratio_gcd {
diff --git a/libcxx/test/std/utilities/ratio/ratio.arithmetic/R1_R2_requirement.verify.cpp b/libcxx/test/std/utilities/ratio/ratio.arithmetic/R1_R2_requirement.verify.cpp
new file mode 100644
index 0000000000000..93fdd9c02b3f6
--- /dev/null
+++ b/libcxx/test/std/utilities/ratio/ratio.arithmetic/R1_R2_requirement.verify.cpp
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <ratio>
+//
+// [ratio.general]/2
+// Throughout subclause [ratio], the names of template parameters are
+// used to express type requirements. If a template parameter is named
+// R1 or R2, and the template argument is not a specialization of the
+// ratio template, the program is ill-formed.
+//
+// test ratio_multiply
+
+#include <ratio>
+
+struct R {
+ constexpr static int num = 1;
+ constexpr static int den = 1;
+};
+
+using r = std::ratio<1, 1>;
+
+namespace add {
+using r_r = std::ratio_add<r, r>::type;
+using R_r = std::ratio_add<R, r>::type; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+using r_R = std::ratio_add<r, R>::type; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace add
+
+namespace subtract {
+using r_r = std::ratio_subtract<r, r>::type;
+using R_r = std::ratio_subtract<R, r>::type; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+using r_R = std::ratio_subtract<r, R>::type; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace subtract
+
+namespace multiply {
+using r_r = std::ratio_multiply<r, r>::type;
+using R_r = std::ratio_multiply<R, r>::type; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+using r_R = std::ratio_multiply<r, R>::type; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace multiply
+
+namespace divide {
+using r_r = std::ratio_divide<r, r>::type;
+using R_r = std::ratio_divide<R, r>::type; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+using r_R = std::ratio_divide<r, R>::type; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace divide
diff --git a/libcxx/test/std/utilities/ratio/ratio.comparison/R1_R2_requirement.verify.cpp b/libcxx/test/std/utilities/ratio/ratio.comparison/R1_R2_requirement.verify.cpp
new file mode 100644
index 0000000000000..a19477ea763a2
--- /dev/null
+++ b/libcxx/test/std/utilities/ratio/ratio.comparison/R1_R2_requirement.verify.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++17
+
+// <ratio>
+//
+// [ratio.general]/2
+// Throughout subclause [ratio], the names of template parameters are
+// used to express type requirements. If a template parameter is named
+// R1 or R2, and the template argument is not a specialization of the
+// ratio template, the program is ill-formed.
+//
+// Since std::ratio_xxx_v uses the same instantiations only one error
+// will be generated. These values are tested in a separate test.
+
+#include <ratio>
+
+struct R {
+ constexpr static int num = 1;
+ constexpr static int den = 1;
+};
+
+using r = std::ratio<1, 1>;
+
+namespace equal {
+using r_r = std::ratio_equal<r, r>::type;
+using R_r = std::ratio_equal<R, r>::type; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+using r_R = std::ratio_equal<r, R>::type; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace equal
+
+namespace not_equal {
+using r_r = std::ratio_not_equal<r, r>::type;
+using R_r = std::ratio_not_equal<R, r>::type; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+using r_R = std::ratio_not_equal<r, R>::type; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace not_equal
+
+namespace less {
+using r_r = std::ratio_less<r, r>::type;
+using R_r = std::ratio_less<R, r>::type; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+using r_R = std::ratio_less<r, R>::type; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace less
+
+namespace less_equal {
+using r_r = std::ratio_less_equal<r, r>::type;
+using R_r = std::ratio_less_equal<R, r>::type; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+using r_R = std::ratio_less_equal<r, R>::type; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace less_equal
+
+namespace greater {
+using r_r = std::ratio_greater<r, r>::type;
+using R_r = std::ratio_greater<R, r>::type; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+using r_R = std::ratio_greater<r, R>::type; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace greater
+
+namespace greater_equal {
+using r_r = std::ratio_greater_equal<r, r>::type;
+using R_r =
+ std::ratio_greater_equal<R, r>::type; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+using r_R =
+ std::ratio_greater_equal<r, R>::type; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace greater_equal
diff --git a/libcxx/test/std/utilities/ratio/ratio.comparison/R1_R2_requirement_v.verify.cpp b/libcxx/test/std/utilities/ratio/ratio.comparison/R1_R2_requirement_v.verify.cpp
new file mode 100644
index 0000000000000..d89f614558a6d
--- /dev/null
+++ b/libcxx/test/std/utilities/ratio/ratio.comparison/R1_R2_requirement_v.verify.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <ratio>
+//
+// [ratio.general]/2
+// Throughout subclause [ratio], the names of template parameters are
+// used to express type requirements. If a template parameter is named
+// R1 or R2, and the template argument is not a specialization of the
+// ratio template, the program is ill-formed.
+//
+// Since std::ratio_xxx uses the same instantiations only one error
+// will be generated. These types are tested in a separate test.
+
+#include <ratio>
+
+struct R {
+ constexpr static int num = 1;
+ constexpr static int den = 1;
+};
+
+using r = std::ratio<1, 1>;
+
+namespace equal {
+constexpr bool r_r_v = std::ratio_equal_v<r, r>;
+constexpr bool R_r_v =
+ std::ratio_equal_v<R, r>; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+constexpr bool r_R_v =
+ std::ratio_equal_v<r, R>; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace equal
+
+namespace not_equal {
+constexpr bool r_r_v = std::ratio_not_equal_v<r, r>;
+constexpr bool R_r_v =
+ std::ratio_not_equal_v<R, r>; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+constexpr bool r_R_v =
+ std::ratio_not_equal_v<r, R>; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace not_equal
+
+namespace less {
+constexpr bool r_r_v = std::ratio_less_v<r, r>;
+constexpr bool R_r_v =
+ std::ratio_less_v<R, r>; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+constexpr bool r_R_v =
+ std::ratio_less_v<r, R>; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace less
+
+namespace less_equal {
+constexpr bool r_r_v = std::ratio_less_equal_v<r, r>;
+constexpr bool R_r_v =
+ std::ratio_less_equal_v<R, r>; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+constexpr bool r_R_v =
+ std::ratio_less_equal_v<r, R>; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace less_equal
+
+namespace greater {
+constexpr bool r_r_v = std::ratio_greater_v<r, r>;
+constexpr bool R_r_v =
+ std::ratio_greater_v<R, r>; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+constexpr bool r_R_v =
+ std::ratio_greater_v<r, R>; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace greater
+
+namespace greater_equal {
+constexpr bool r_r_v = std::ratio_greater_equal_v<r, r>;
+constexpr bool R_r_v =
+ std::ratio_greater_equal_v<R, r>; // expected-error@*:* {{R1 to be a specialication of the ratio template}}
+constexpr bool r_R_v =
+ std::ratio_greater_equal_v<r, R>; // expected-error@*:* {{R2 to be a specialication of the ratio template}}
+} // namespace greater_equal
|
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.
Hope that this helps!!
The arithemtic and comparison operations are ill-formed when R1 or R2 is not a std::ratio. Fixes: llvm#63753
d2bb633
to
e982e81
Compare
libcxx/test/std/utilities/ratio/ratio.arithmetic/R1_R2_requirement.verify.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/utilities/ratio/ratio.comparison/R1_R2_requirement.verify.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/utilities/ratio/ratio.arithmetic/R1_R2_requirement.verify.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/utilities/ratio/ratio.arithmetic/R1_R2_requirement.verify.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/utilities/ratio/ratio.comparison/R1_R2_requirement.verify.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/utilities/ratio/ratio.comparison/R1_R2_requirement.verify.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/utilities/ratio/ratio.comparison/R1_R2_requirement_v.verify.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/utilities/ratio/ratio.comparison/R1_R2_requirement_v.verify.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/utilities/ratio/ratio.comparison/R1_R2_requirement_v.verify.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/utilities/ratio/ratio.comparison/R1_R2_requirement.verify.cpp
Outdated
Show resolved
Hide resolved
✅ With the latest revision this PR passed the C/C++ code formatter. |
67401b9
to
bfe8796
Compare
bfe8796
to
1c18400
Compare
The arithmetic and comparison operators are ill-formed when R1 or R2 is not a std::ratio.
Fixes: #63753