diff --git a/libstdc++-v3/include/bits/chrono.h b/libstdc++-v3/include/bits/chrono.h
index 81b92d724f7..e9490767c56 100644
--- a/libstdc++-v3/include/bits/chrono.h
+++ b/libstdc++-v3/include/bits/chrono.h
@@ -505,26 +505,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 183f1aeda11..1d285bf916f 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 49c9fe77168..1a1188b2a2f 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 23c5d479b1f..cbdb7af0c65 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 }
