diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 2737b14ea187db1a150d6f6c140dab313aa43daa..9d65130154da41a89d8e1dc2d199473883681b9a 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -52,6 +52,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "asan.h"
+#include "realmpfr.h"
 
 /* Possible cases of implicit conversions.  Used to select diagnostic messages
    and control folding initializers in convert_for_assignment.  */
@@ -8121,8 +8122,9 @@ print_spelling (char *buffer)
 }
 
 /* Check whether INIT, a floating or integer constant, is
-   representable in TYPE, a real floating type with the same radix.
-   Return true if OK, false if not.  */
+   representable in TYPE, a real floating type with the same radix or
+   a decimal floating type initialized with a binary floating
+   constant.  Return true if OK, false if not.  */
 static bool
 constexpr_init_fits_real_type (tree type, tree init)
 {
@@ -8130,8 +8132,16 @@ constexpr_init_fits_real_type (tree type, tree init)
   gcc_assert (TREE_CODE (init) == INTEGER_CST || TREE_CODE (init) == REAL_CST);
   if (TREE_CODE (init) == REAL_CST
       && TYPE_MODE (TREE_TYPE (init)) == TYPE_MODE (type))
-    /* Same mode, no conversion required.  */
-    return true;
+    {
+      /* Same mode, no conversion required except for the case of
+	 signaling NaNs if the types are incompatible (e.g. double and
+	 long double with the same mode).  */
+      if (REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (init))
+	  && !comptypes (TYPE_MAIN_VARIANT (type),
+			 TYPE_MAIN_VARIANT (TREE_TYPE (init))))
+	return false;
+      return true;
+    }
   if (TREE_CODE (init) == INTEGER_CST)
     {
       tree converted = build_real_from_int_cst (type, init);
@@ -8140,6 +8150,33 @@ constexpr_init_fits_real_type (tree type, tree init)
 				    TYPE_PRECISION (TREE_TYPE (init)));
       return !fail && wi::eq_p (w, wi::to_wide (init));
     }
+  if (REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (init)))
+    return false;
+  if ((REAL_VALUE_ISINF (TREE_REAL_CST (init))
+       && MODE_HAS_INFINITIES (TYPE_MODE (type)))
+      || (REAL_VALUE_ISNAN (TREE_REAL_CST (init))
+	  && MODE_HAS_NANS (TYPE_MODE (type))))
+    return true;
+  if (DECIMAL_FLOAT_TYPE_P (type)
+      && !DECIMAL_FLOAT_TYPE_P (TREE_TYPE (init)))
+    {
+      /* This is valid if the real number represented by the
+	 initializer can be exactly represented in the decimal
+	 type.  Compare the values using MPFR.  */
+      REAL_VALUE_TYPE t;
+      real_convert (&t, TYPE_MODE (type), &TREE_REAL_CST (init));
+      mpfr_t bin_val, dec_val;
+      mpfr_init2 (bin_val, REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (init)))->p);
+      mpfr_init2 (dec_val, REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (init)))->p);
+      mpfr_from_real (bin_val, &TREE_REAL_CST (init), MPFR_RNDN);
+      char string[256];
+      real_to_decimal (string, &t, sizeof string, 0, 1);
+      bool res = (mpfr_strtofr (dec_val, string, NULL, 10, MPFR_RNDN) == 0
+		  && mpfr_equal_p (bin_val, dec_val));
+      mpfr_clear (bin_val);
+      mpfr_clear (dec_val);
+      return res;
+    }
   /* exact_real_truncate is not quite right here, since it doesn't
      allow even an exact conversion to subnormal values.  */
   REAL_VALUE_TYPE t;
@@ -8194,18 +8231,12 @@ check_constexpr_init (location_t loc, tree type, tree init,
   if (TREE_CODE (type) == COMPLEX_TYPE
       && TREE_CODE (TREE_TYPE (type)) != REAL_TYPE)
     return;
-  /* Both the normative text and the relevant footnote are unclear, as
-     of the C2x CD, about what exactly counts as a change of value in
-     floating-point cases.  Here, we consider all conversions between
-     binary and decimal types (even of infinities and NaNs, where
-     quantum exponents are not involved) as involving a change of
-     value, and likewise for conversions between real and complex
-     types (even when the complex constant has imaginary part positive
-     zero), and conversions of signaling NaN to a different machine
-     mode.  But we allow exact conversions of integers to binary or
-     decimal floating types, and exact conversions between different
-     binary types or different decimal types, where "exact" in the
-     decimal case requires the quantum exponent to be preserved.  */
+  /* Following N3082, a real type cannot be initialized from a complex
+     type and a binary type cannot be initialized from a decimal type
+     (but initializing a decimal type from a binary type is OK).
+     Signaling NaN initializers are OK only if the types are
+     compatible (not just the same mode); all quiet NaN and infinity
+     initializations are considered to preserve the value.  */
   if (TREE_CODE (TREE_TYPE (init)) == COMPLEX_TYPE
       && TREE_CODE (type) == REAL_TYPE)
     {
@@ -8213,39 +8244,33 @@ check_constexpr_init (location_t loc, tree type, tree init,
 		"complex type");
       return;
     }
-  if (TREE_CODE (type) == COMPLEX_TYPE
-      && TREE_CODE (TREE_TYPE (init)) != COMPLEX_TYPE)
-    {
-      error_at (loc, "%<constexpr%> initializer for a complex type is of "
-		"real type");
-      return;
-    }
   if (TREE_CODE (type) == REAL_TYPE
-      && TREE_CODE (TREE_TYPE (init)) == REAL_TYPE)
+      && TREE_CODE (TREE_TYPE (init)) == REAL_TYPE
+      && DECIMAL_FLOAT_TYPE_P (TREE_TYPE (init))
+      && !DECIMAL_FLOAT_TYPE_P (type))
     {
-      if (DECIMAL_FLOAT_TYPE_P (type)
-	  && !DECIMAL_FLOAT_TYPE_P (TREE_TYPE (init)))
-	{
-	  error_at (loc, "%<constexpr%> initializer for a decimal "
-		    "floating-point type is of binary type");
-	  return;
-	}
-      else if (DECIMAL_FLOAT_TYPE_P (TREE_TYPE (init))
-	       && !DECIMAL_FLOAT_TYPE_P (type))
-	{
-	  error_at (loc, "%<constexpr%> initializer for a binary "
-		    "floating-point type is of decimal type");
-	  return;
-	}
+      error_at (loc, "%<constexpr%> initializer for a binary "
+		"floating-point type is of decimal type");
+      return;
     }
   bool fits;
   if (TREE_CODE (type) == COMPLEX_TYPE)
     {
-      gcc_assert (TREE_CODE (init) == COMPLEX_CST);
-      fits = (constexpr_init_fits_real_type (TREE_TYPE (type),
-					     TREE_REALPART (init))
-	      && constexpr_init_fits_real_type (TREE_TYPE (type),
-						TREE_IMAGPART (init)));
+      switch (TREE_CODE (init))
+	{
+	case INTEGER_CST:
+	case REAL_CST:
+	  fits = constexpr_init_fits_real_type (TREE_TYPE (type), init);
+	  break;
+	case COMPLEX_CST:
+	  fits = (constexpr_init_fits_real_type (TREE_TYPE (type),
+						 TREE_REALPART (init))
+		  && constexpr_init_fits_real_type (TREE_TYPE (type),
+						    TREE_IMAGPART (init)));
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
     }
   else
     fits = constexpr_init_fits_real_type (type, init);
diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-1.c b/gcc/testsuite/gcc.dg/c2x-constexpr-1.c
index d43d95ddd7c4d9c36d122e9bd9c6c3836b443062..97b54f17428f267e2c5bcb6e83f5da294a361fd8 100644
--- a/gcc/testsuite/gcc.dg/c2x-constexpr-1.c
+++ b/gcc/testsuite/gcc.dg/c2x-constexpr-1.c
@@ -174,6 +174,8 @@ constexpr int v94 = alignof (int);
 alignas (v94) int v95;
 constexpr int v97[100] = { [v82.x.f] = 7 };
 static int v98[v94];
+constexpr _Complex double v99 = 1.0;
+constexpr _Complex float v100 = 12345;
 
 void
 f0 ()
@@ -247,6 +249,8 @@ f0 ()
   (constexpr union u58) { 0 };
   (constexpr union u58) { { } }; /* { dg-warning "braces around scalar initializer" } */
   (constexpr union u58) { { 0 } }; /* { dg-warning "braces around scalar initializer" } */
+  (constexpr _Complex double) { 1.0 };
+  (constexpr _Complex float) { 12345 };
   /* It's not entirely clear if constexpr declarations are allowed in this
      position in a for loop; presume they are, as implicitly auto just as if no
      storage class specifiers were used.  */
diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-3.c b/gcc/testsuite/gcc.dg/c2x-constexpr-3.c
index 29fedc03afd4c160b7693723dea69bb644ff3798..4f6b8ed67794a963a34dc19a0c9e4f6d26bf9d2e 100644
--- a/gcc/testsuite/gcc.dg/c2x-constexpr-3.c
+++ b/gcc/testsuite/gcc.dg/c2x-constexpr-3.c
@@ -112,13 +112,9 @@ constexpr int v95 = (unsigned int) -1; /* { dg-error "'constexpr' initializer no
 constexpr unsigned char v96 = -1; /* { dg-error "'constexpr' initializer not representable in type of object" } */
 constexpr signed char v97 = 1234567LL; /* { dg-error "'constexpr' initializer not representable in type of object" } */
 /* { dg-warning "overflow in conversion" "overflow warning" { target *-*-* } .-1 } */
-/* Disallow all real/complex conversions (the C2x CD is unclear about
-   real-to-complex and about complex-to-real with imaginary part positive 0, if
-   the real parts can be exactly represented in the relevant types).  */
 constexpr double v98 = __builtin_complex (1.0, 0.0); /* { dg-error "'constexpr' initializer for a real type is of complex type" } */
 constexpr double v99 = __builtin_complex (1.0, 1.0); /* { dg-error "'constexpr' initializer for a real type is of complex type" } */
 constexpr double v100 = __builtin_complex (1.0, -0.0); /* { dg-error "'constexpr' initializer for a real type is of complex type" } */
-constexpr _Complex double v101 = 1.0; /* { dg-error "'constexpr' initializer for a complex type is of real type" } */
 constexpr float v102 = (unsigned long long) -1; /* { dg-error "'constexpr' initializer not representable in type of object" } */
 constexpr double v103 = (unsigned long long) -1; /* { dg-error "'constexpr' initializer not representable in type of object" } */
 constexpr float v104 = __LONG_LONG_MAX__; /* { dg-error "'constexpr' initializer not representable in type of object" } */
@@ -216,7 +212,6 @@ f0 ()
   (constexpr double) { __builtin_complex (1.0, 0.0) }; /* { dg-error "'constexpr' initializer for a real type is of complex type" } */
   (constexpr double) { __builtin_complex (1.0, 1.0) }; /* { dg-error "'constexpr' initializer for a real type is of complex type" } */
   (constexpr double) { __builtin_complex (1.0, -0.0) }; /* { dg-error "'constexpr' initializer for a real type is of complex type" } */
-  (constexpr _Complex double) { 1.0 }; /* { dg-error "'constexpr' initializer for a complex type is of real type" } */
   (constexpr float) { (unsigned long long) -1 }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
   (constexpr double) { (unsigned long long) -1 }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
   (constexpr float) { __LONG_LONG_MAX__ }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-8.c b/gcc/testsuite/gcc.dg/c2x-constexpr-8.c
index c7119c97a6978df7ebf7ef45fe812ea607aea7e8..11372cf1d5aad3ddbb4cd9c7c4c7ad71978031d9 100644
--- a/gcc/testsuite/gcc.dg/c2x-constexpr-8.c
+++ b/gcc/testsuite/gcc.dg/c2x-constexpr-8.c
@@ -10,6 +10,7 @@ constexpr float fn = __builtin_nan ("");
 constexpr double dn = __builtin_nanf ("");
 constexpr float fns = __builtin_nansf ("");
 constexpr double dns = __builtin_nans ("");
+constexpr _Complex double cdns = __builtin_nans ("");
 
 void
 f0 (void)
@@ -20,4 +21,5 @@ f0 (void)
   (constexpr double) { __builtin_nanf ("") };
   (constexpr float) { __builtin_nansf ("") };
   (constexpr double) { __builtin_nans ("") };
+  (constexpr _Complex double) { __builtin_nans ("") };
 }
diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-9.c b/gcc/testsuite/gcc.dg/c2x-constexpr-9.c
index c62fc738fa055a21d48d9b27a4da6c3330075000..8a07ed5b3833793383620cba0e4d428f58c0397a 100644
--- a/gcc/testsuite/gcc.dg/c2x-constexpr-9.c
+++ b/gcc/testsuite/gcc.dg/c2x-constexpr-9.c
@@ -4,10 +4,11 @@
 /* { dg-add-options ieee } */
 /* { dg-require-effective-target inff } */
 
-/* A conversion from signaling NaN to quiet NaN in a different format is not
-   valid for constexpr.  */
+/* A conversion from signaling NaN to quiet NaN in a different format or type
+   is not valid for constexpr.  */
 constexpr float fns = __builtin_nans (""); /* { dg-error "'constexpr' initializer not representable in type of object" } */
 constexpr double dns = __builtin_nansf (""); /* { dg-error "'constexpr' initializer not representable in type of object" } */
+constexpr long double ldns = __builtin_nans (""); /* { dg-error "'constexpr' initializer not representable in type of object" } */
 
 /* Test out-of-range values.  */
 constexpr float fu = __DBL_MIN__; /* { dg-error "'constexpr' initializer not representable in type of object" } */
@@ -22,6 +23,9 @@ constexpr _Complex float cfui = __builtin_complex (0.0, __DBL_MIN__); /* { dg-er
 constexpr _Complex float cfoi = __builtin_complex (0.0, __DBL_MAX__); /* { dg-error "'constexpr' initializer not representable in type of object" } */
 constexpr _Complex float cfpi = __builtin_complex (0.0, 0x1.ffffffp0); /* { dg-error "'constexpr' initializer not representable in type of object" } */
 
+constexpr _Complex float cfd = __DBL_MAX__; /* { dg-error "'constexpr' initializer not representable in type of object" } */
+constexpr _Complex float cfi = __LONG_LONG_MAX__; /* { dg-error "'constexpr' initializer not representable in type of object" } */
+
 void
 f0 ()
 {
@@ -36,4 +40,6 @@ f0 ()
   (constexpr _Complex float) { __builtin_complex (0.0, __DBL_MIN__) }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
   (constexpr _Complex float) { __builtin_complex (0.0, __DBL_MAX__) }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
   (constexpr _Complex float) { __builtin_complex (0.0, 0x1.ffffffp0) }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
+  (constexpr _Complex float) { __DBL_MAX__ }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
+  (constexpr _Complex float) { __LONG_LONG_MAX__ }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
 }
diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-1.c b/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-1.c
index 568f1428b40bf7c24027e4471bfe72938b139e3c..4ac6629ff5af782bd6125f20250291b378f14abc 100644
--- a/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-1.c
+++ b/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-1.c
@@ -37,6 +37,11 @@ constexpr _Decimal128 v32 = __builtin_nansd128 ("");
 constexpr _Decimal32 v33 = {};
 constexpr _Decimal64 v34 = {};
 constexpr _Decimal128 v35 = {};
+constexpr _Decimal32 v36 = 0.0;
+constexpr _Decimal32 v37 = 0.0009765625;
+constexpr _Decimal64 v38 = 6.103515625e-05;
+constexpr _Decimal32 v39 = __builtin_inf ();
+constexpr _Decimal32 v40 = __builtin_nan ("");
 
 void
 f0 ()
@@ -76,4 +81,9 @@ f0 ()
   (constexpr _Decimal32) {};
   (constexpr _Decimal64) {};
   (constexpr _Decimal128) {};
+  (constexpr _Decimal32) { 0.0 };
+  (constexpr _Decimal32) { 0.0009765625 };
+  (constexpr _Decimal64) { 6.103515625e-05 };
+  (constexpr _Decimal32) { __builtin_inf () };
+  (constexpr _Decimal32) { __builtin_nan ("") };
 }
diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-2.c b/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-2.c
index 8b1ecf239083e653a380258658a352138cacc2cc..8ce0d088ac3d75b7709e2bf993f5086a04413104 100644
--- a/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-2.c
+++ b/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-2.c
@@ -3,8 +3,10 @@
 /* { dg-options "-std=c2x -pedantic-errors" } */
 
 /* Test conversions between binary and decimal.  */
-constexpr _Decimal32 v1 = 0.0; /* { dg-error "'constexpr' initializer for a decimal floating-point type is of binary type" } */
 constexpr double v2 = 0.0DF; /* { dg-error "'constexpr' initializer for a binary floating-point type is of decimal type" } */
+constexpr double v2i = __builtin_infd32 (); /* { dg-error "'constexpr' initializer for a binary floating-point type is of decimal type" } */
+constexpr double v2n = __builtin_nand32 (""); /* { dg-error "'constexpr' initializer for a binary floating-point type is of decimal type" } */
+constexpr _Decimal128 v2d = 0x1p-100f; /* { dg-error "'constexpr' initializer not representable in type of object" } */
 
 /* A conversion from signaling NaN to quiet NaN in a different format is not
    valid for constexpr.  */
@@ -30,8 +32,10 @@ constexpr _Decimal32 v15 = 0e200DL; /* { dg-error "'constexpr' initializer not r
 void
 f0 ()
 {
-  (constexpr _Decimal32) { 0.0 }; /* { dg-error "'constexpr' initializer for a decimal floating-point type is of binary type" } */
   (constexpr double) { 0.0DF }; /* { dg-error "'constexpr' initializer for a binary floating-point type is of decimal type" } */
+  (constexpr double) { __builtin_infd32 () }; /* { dg-error "'constexpr' initializer for a binary floating-point type is of decimal type" } */
+  (constexpr double) { __builtin_nand32 ("") }; /* { dg-error "'constexpr' initializer for a binary floating-point type is of decimal type" } */
+  (constexpr _Decimal128) { 0x1p-100f }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
   (constexpr _Decimal32) { __builtin_nansd64 ("") }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
   (constexpr _Decimal32) { __builtin_nansd128 ("") }; /* { dg-error "'constexpr' initializer not representable in type of object" } */
   (constexpr _Decimal64) { __builtin_nansd32 ("") }; /* { dg-error "'constexpr' initializer not representable in type of object" } */