public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-10238] libstdc++: Check for std::ratio in arithmetic and comparisons [PR110593]
@ 2024-03-18 14:04 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2024-03-18 14:04 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:ae8302e18f15f0befb372762b20a3a790a19a925

commit r12-10238-gae8302e18f15f0befb372762b20a3a790a19a925
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jul 19 18:18:46 2023 +0100

    libstdc++: Check for std::ratio in arithmetic and comparisons [PR110593]
    
    The standard says that it should be ill-formed to use std::ratio_equal
    etc. with types which are not specializations of std::ratio. This
    implements that requirement.
    
    We don't need to add assertions to every one of the class templates,
    because many of them are implemented in terms of other ones. For
    example, ratio_divide and ratio_subtract can rely on the assertions in
    ratio_multiply and ratio_add respectively.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/110593
            * include/bits/chrono.h (duration): Improve static assert
            messages.
            (__is_ratio): Move to ...
            * include/std/ratio (__is_ratio): ... here.
            (__is_ratio_v): New variable template and partial
            specialization.
            (__are_both_ratios): New function template.
            (__ratio_multiply, ratio_equal, ratio_less, __ratio_add):
            Add static assertion.
            * testsuite/20_util/ratio/requirements/type_constraints.cc:
            New test.
            * testsuite/20_util/duration/requirements/typedefs_neg1.cc:
            Adjust expected error.
            * testsuite/20_util/duration/requirements/typedefs_neg2.cc:
            Likewise.
    
    (cherry picked from commit 2d614822e9ea2a3d8800045d66e3220743753d09)

Diff:
---
 libstdc++-v3/include/bits/chrono.h                 | 19 ++------
 libstdc++-v3/include/std/ratio                     | 53 ++++++++++++++++++++--
 .../20_util/duration/requirements/typedefs_neg1.cc |  2 +-
 .../20_util/duration/requirements/typedefs_neg2.cc |  2 +-
 .../20_util/ratio/requirements/type_constraints.cc | 34 ++++++++++++++
 5 files changed, 87 insertions(+), 23 deletions(-)

diff --git a/libstdc++-v3/include/bits/chrono.h b/libstdc++-v3/include/bits/chrono.h
index c585cac3d8a..d09f8563a59 100644
--- a/libstdc++-v3/include/bits/chrono.h
+++ b/libstdc++-v3/include/bits/chrono.h
@@ -483,26 +483,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	{ return numeric_limits<_Rep>::lowest(); }
       };
 
-    /// @cond undocumented
-
-    template<typename _Tp>
-      struct __is_ratio
-      : std::false_type
-      { };
-
-    template<intmax_t _Num, intmax_t _Den>
-      struct __is_ratio<ratio<_Num, _Den>>
-      : std::true_type
-      { };
-
-    /// @endcond
-
     template<typename _Rep, typename _Period>
       class duration
       {
-	static_assert(!__is_duration<_Rep>::value, "rep cannot be a duration");
+	static_assert(!__is_duration<_Rep>::value,
+		      "rep cannot be a std::chrono::duration");
 	static_assert(__is_ratio<_Period>::value,
-		      "period must be a specialization of ratio");
+		      "period must be a specialization of std::ratio");
 	static_assert(_Period::num > 0, "period must be positive");
 
 	template<typename _Rep2>
diff --git a/libstdc++-v3/include/std/ratio b/libstdc++-v3/include/std/ratio
index 5a5643d2999..32a4da25a93 100644
--- a/libstdc++-v3/include/std/ratio
+++ b/libstdc++-v3/include/std/ratio
@@ -289,9 +289,43 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   /// @cond undocumented
 
+  template<typename _Tp>
+    struct __is_ratio
+    : std::false_type
+    { };
+
+  template<intmax_t _Num, intmax_t _Den>
+    struct __is_ratio<ratio<_Num, _Den>>
+    : std::true_type
+    { };
+
+#if __cpp_variable_templates
+  template<typename _Tp>
+    constexpr bool __is_ratio_v = false;
+  template<intmax_t _Num, intmax_t _Den>
+    constexpr bool __is_ratio_v<ratio<_Num, _Den>> = true;
+#endif
+
+  template<typename _R1, typename _R2>
+    constexpr bool
+    __are_both_ratios() noexcept
+    {
+#if __cpp_variable_templates && __cpp_if_constexpr
+      if constexpr (__is_ratio_v<_R1>)
+	if constexpr (__is_ratio_v<_R2>)
+	  return true;
+      return false;
+#else
+      return __and_<__is_ratio<_R1>, __is_ratio<_R2>>::value;
+#endif
+    }
+
   template<typename _R1, typename _R2>
     struct __ratio_multiply
     {
+      static_assert(std::__are_both_ratios<_R1, _R2>(),
+		    "both template arguments must be a std::ratio");
+
     private:
       static const intmax_t __gcd1 =
         __static_gcd<_R1::num, _R2::den>::value;
@@ -356,7 +390,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _R1, typename _R2>
     struct ratio_equal
     : integral_constant<bool, _R1::num == _R2::num && _R1::den == _R2::den>
-    { };
+    {
+      static_assert(std::__are_both_ratios<_R1, _R2>(),
+		    "both template arguments must be a std::ratio");
+    };
 
   /// ratio_not_equal
   template<typename _R1, typename _R2>
@@ -402,7 +439,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _R1, typename _R2>
     struct ratio_less
     : __ratio_less_impl<_R1, _R2>::type
-    { };
+    {
+      static_assert(std::__are_both_ratios<_R1, _R2>(),
+		    "both template arguments must be a std::ratio");
+    };
 
   /// ratio_less_equal
   template<typename _R1, typename _R2>
@@ -430,13 +470,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template <typename _R1, typename _R2>
     inline constexpr bool ratio_less_v = ratio_less<_R1, _R2>::value;
   template <typename _R1, typename _R2>
-    inline constexpr bool ratio_less_equal_v =
-      ratio_less_equal<_R1, _R2>::value;
+    inline constexpr bool ratio_less_equal_v
+      = ratio_less_equal<_R1, _R2>::value;
   template <typename _R1, typename _R2>
     inline constexpr bool ratio_greater_v = ratio_greater<_R1, _R2>::value;
   template <typename _R1, typename _R2>
     inline constexpr bool ratio_greater_equal_v
-    = ratio_greater_equal<_R1, _R2>::value;
+      = ratio_greater_equal<_R1, _R2>::value;
 #endif // C++17
 
   /// @cond undocumented
@@ -513,6 +553,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _R1, typename _R2>
     struct __ratio_add
     {
+      static_assert(std::__are_both_ratios<_R1, _R2>(),
+		    "both template arguments must be a std::ratio");
+
       typedef typename __ratio_add_impl<_R1, _R2>::type type;
       static constexpr intmax_t num = type::num;
       static constexpr intmax_t den = type::den;
diff --git a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg1.cc b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg1.cc
index 6e473acf19c..d71e31f9b59 100644
--- a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg1.cc
+++ b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg1.cc
@@ -29,4 +29,4 @@ void test01()
   test_type d; // { dg-error "required from here" }
 }
 
-// { dg-error "rep cannot be a duration" "" { target *-*-* } 0 }
+// { dg-error "rep cannot be a std::chrono::duration" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg2.cc b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg2.cc
index 39409e21fcc..0c0329b3fd1 100644
--- a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg2.cc
+++ b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg2.cc
@@ -30,7 +30,7 @@ void test01()
   test_type d;			// { dg-error "required from here" }
 }
 
-// { dg-error "must be a specialization of ratio" "" { target *-*-* } 0 }
+// { dg-error "must be a specialization of std::ratio" "" { target *-*-* } 0 }
 // { dg-prune-output "'num' is not a member of 'int'" }
 // { dg-prune-output "'den' is not a member of 'int'" }
 // { dg-prune-output "'int' is not a class, struct, or union type" }
diff --git a/libstdc++-v3/testsuite/20_util/ratio/requirements/type_constraints.cc b/libstdc++-v3/testsuite/20_util/ratio/requirements/type_constraints.cc
new file mode 100644
index 00000000000..ebf09bc8f07
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/ratio/requirements/type_constraints.cc
@@ -0,0 +1,34 @@
+// { dg-do compile { target c++11 } }
+
+// C++11 20.10.1 [ratio.general]
+// if the template argument types R1 and R2 are not specializations of the
+// ratio template, the program is ill-formed.
+
+#include <ratio>
+
+using namespace std;
+
+// A type that looks like std::ratio but isn't.
+template<int> struct Ratty { static constexpr int num = 1, den = 1; };
+
+using T1 = ratio_add<Ratty<1>, Ratty<1>>::type; // { dg-error "here" }
+using T2 = ratio_subtract<Ratty<3>, Ratty<3>>::type; // { dg-error "here" }
+using T3 = ratio_multiply<Ratty<3>, Ratty<3>>::type; // { dg-error "here" }
+using T4 = ratio_divide<Ratty<4>, Ratty<4>>::type; // { dg-error "here" }
+using T5 = ratio_equal<Ratty<5>, Ratty<5>>::type; // { dg-error "here" }
+using T6 = ratio_not_equal<Ratty<6>, Ratty<6>>::type; // { dg-error "here" }
+using T7 = ratio_less<Ratty<7>, Ratty<7>>::type; // { dg-error "here" }
+using T8 = ratio_less_equal<Ratty<8>, Ratty<8>>::type; // { dg-error "here" }
+using T9 = ratio_greater<Ratty<9>, Ratty<9>>::type; // { dg-error "here" }
+using T10 = ratio_greater_equal<Ratty<10>, Ratty<10>>::type; // { dg-error "here" }
+
+#if __cplusplus >= 201703L
+bool B11 = ratio_equal_v<Ratty<11>, Ratty<11>>; // { dg-error "here" "" { target c++17 } }
+bool B12 = ratio_not_equal_v<Ratty<12>, Ratty<12>>; // { dg-error "here" "" { target c++17 } }
+bool B13 = ratio_less_v<Ratty<13>, Ratty<13>>; // { dg-error "here" "" { target c++17 } }
+bool B14 = ratio_less_equal_v<Ratty<14>, Ratty<14>>; // { dg-error "here" "" { target c++17 } }
+bool B15 = ratio_greater_v<Ratty<15>, Ratty<15>>; // { dg-error "here" "" { target c++17 } }
+bool B16 = ratio_greater_equal_v<Ratty<16>, Ratty<16>>; // { dg-error "here" "" { target c++17 } }
+#endif
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-03-18 14:04 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-18 14:04 [gcc r12-10238] libstdc++: Check for std::ratio in arithmetic and comparisons [PR110593] Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).