Skip to content

[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

Merged
merged 2 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 36 additions & 6 deletions libcxx/include/ratio
Original file line number Diff line number Diff line change
Expand Up @@ -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 specialisation of the ratio template");
static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialisation 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;
Expand All @@ -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 specialisation of the ratio template");
static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialisation 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;
Expand All @@ -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 specialisation of the ratio template");
static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialisation of the ratio template");

public:
typedef typename ratio_multiply<
ratio<__gcd_n1_n2, _R1::den / __gcd_d1_d2>,
Expand All @@ -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 specialisation of the ratio template");
static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialisation of the ratio template");

public:
typedef typename ratio_multiply<
ratio<__gcd_n1_n2, _R1::den / __gcd_d1_d2>,
Expand All @@ -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 specialisation of the ratio template");
static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialisation 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 specialisation of the ratio template");
static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialisation of the ratio template");
};

// ratio_less

Expand Down Expand Up @@ -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 specialisation of the ratio template");
static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialisation 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 specialisation of the ratio template");
static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialisation 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 specialisation of the ratio template");
static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialisation 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 specialisation of the ratio template");
static_assert(__is_ratio<_R2>::value, "[ratio.general]/2 requires R2 to be a specialisation of the ratio template");
};

template <class _R1, class _R2>
struct __ratio_gcd {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//===----------------------------------------------------------------------===//
//
// 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.

#include <ratio>

struct invalid {
static const int num = 1;
static const int den = 1;
};

using valid = std::ratio<1, 1>;

namespace add {
using valid_valid = std::ratio_add<valid, valid>::type;
using invalid_valid =
std::ratio_add<invalid, valid>::type; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
using valid_invalid =
std::ratio_add<valid, invalid>::type; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}
} // namespace add

namespace subtract {
using valid_valid = std::ratio_subtract<valid, valid>::type;
using invalid_valid =
std::ratio_subtract<invalid, valid>::type; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
using valid_invalid =
std::ratio_subtract<valid, invalid>::type; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}
} // namespace subtract

namespace multiply {
using valid_valid = std::ratio_multiply<valid, valid>::type;
using invalid_valid =
std::ratio_multiply<invalid, valid>::type; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
using valid_invalid =
std::ratio_multiply<valid, invalid>::type; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}
} // namespace multiply

namespace divide {
using valid_valid = std::ratio_divide<valid, valid>::type;
using invalid_valid =
std::ratio_divide<invalid, valid>::type; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
using valid_invalid =
std::ratio_divide<valid, invalid>::type; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}
} // namespace divide
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//===----------------------------------------------------------------------===//
//
// 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 all std::ratio_xxx_v variables use the same instantiation, only one
// error will be generated. These values are tested in a separate test.

#include <ratio>

struct invalid {
static const int num = 1;
static const int den = 1;
};

using valid = std::ratio<1, 1>;

namespace equal {
using valid_valid = std::ratio_equal<valid, valid>::type;
using invalid_valid =
std::ratio_equal<invalid, valid>::type; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
using valid_invalid =
std::ratio_equal<valid, invalid>::type; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}
} // namespace equal

namespace not_equal {
using valid_valid = std::ratio_not_equal<valid, valid>::type;
using invalid_valid =
std::ratio_not_equal<invalid,
valid>::type; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
using valid_invalid =
std::ratio_not_equal<valid,
invalid>::type; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}
} // namespace not_equal

namespace less {
using valid_valid = std::ratio_less<valid, valid>::type;
using invalid_valid =
std::ratio_less<invalid, valid>::type; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
using valid_invalid =
std::ratio_less<valid, invalid>::type; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}
} // namespace less

namespace less_equal {
using valid_valid = std::ratio_less_equal<valid, valid>::type;
using invalid_valid =
std::ratio_less_equal<invalid,
valid>::type; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
using valid_invalid =
std::ratio_less_equal<valid,
invalid>::type; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}
} // namespace less_equal

namespace greater {
using valid_valid = std::ratio_greater<valid, valid>::type;
using invalid_valid =
std::ratio_greater<invalid, valid>::type; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
using valid_invalid =
std::ratio_greater<valid, invalid>::type; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}
} // namespace greater

namespace greater_equal {
using valid_valid = std::ratio_greater_equal<valid, valid>::type;
using invalid_valid =
std::ratio_greater_equal<invalid,
valid>::type; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
using valid_invalid =
std::ratio_greater_equal<valid,
invalid>::type; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}
} // namespace greater_equal
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//===----------------------------------------------------------------------===//
//
// 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++14

// <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 all std::ratio_xxx_v variables use the same instantiation, only one
// error will be generated. These values are tested in a separate test.

#include <ratio>

struct invalid {
constexpr static int num = 1;
constexpr static int den = 1;
};

using valid = std::ratio<1, 1>;

void test() {
// equal
(void)std::ratio_equal_v<valid, valid>;
(void)std::ratio_equal_v<invalid, valid>; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
(void)std::ratio_equal_v<valid, invalid>; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}

// not_equal
(void)std::ratio_not_equal_v<valid, valid>;
(void)std::ratio_not_equal_v<invalid,
valid>; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
(void)std::ratio_not_equal_v<valid,
invalid>; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}

// less
(void)std::ratio_less_v<valid, valid>;
(void)std::ratio_less_v<invalid, valid>; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
(void)std::ratio_less_v<valid, invalid>; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}

// less_equal
(void)std::ratio_less_equal_v<valid, valid>;
(void)std::ratio_less_equal_v<invalid,
valid>; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
(void)std::ratio_less_equal_v<valid,
invalid>; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}

// greater
(void)std::ratio_greater_v<valid, valid>;
(void)std::ratio_greater_v<invalid, valid>; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}
(void)std::ratio_greater_v<valid, invalid>; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}

// greater_equal
(void)std::ratio_greater_equal_v<valid, valid>;

(void)std::ratio_greater_equal_v<invalid,
valid>; // expected-error@*:* {{R1 to be a specialisation of the ratio template}}

(void)std::ratio_greater_equal_v<valid,
invalid>; // expected-error@*:* {{R2 to be a specialisation of the ratio template}}
}