--- gcc/c-family/c-opts.cc.jj	2022-10-11 10:00:07.108129689 +0200
+++ gcc/c-family/c-opts.cc	2022-10-11 10:06:55.784412531 +0200
@@ -812,17 +812,9 @@ c_common_post_options (const char **pfil
   C_COMMON_OVERRIDE_OPTIONS;
 #endif
 
-  /* Excess precision other than "fast" requires front-end
-     support.  */
-  if (c_dialect_cxx ())
-    {
-      if (flag_excess_precision == EXCESS_PRECISION_STANDARD)
-	sorry ("%<-fexcess-precision=standard%> for C++");
-      flag_excess_precision = EXCESS_PRECISION_FAST;
-    }
-  else if (flag_excess_precision == EXCESS_PRECISION_DEFAULT)
+  if (flag_excess_precision == EXCESS_PRECISION_DEFAULT)
     flag_excess_precision = (flag_iso ? EXCESS_PRECISION_STANDARD
-				      : EXCESS_PRECISION_FAST);
+			     : EXCESS_PRECISION_FAST);
 
   /* ISO C restricts floating-point expression contraction to within
      source-language expressions (-ffp-contract=on, currently an alias
--- gcc/c-family/c-lex.cc.jj	2022-10-11 09:59:39.300518701 +0200
+++ gcc/c-family/c-lex.cc	2022-10-11 10:06:55.784412531 +0200
@@ -1008,10 +1008,7 @@ interpret_float (const cpp_token *token,
     else
       type = double_type_node;
 
-  if (c_dialect_cxx ())
-    const_type = NULL_TREE;
-  else
-    const_type = excess_precision_type (type);
+  const_type = excess_precision_type (type);
   if (!const_type)
     const_type = type;
 
--- gcc/cp/parser.cc.jj	2022-10-10 11:57:40.158723041 +0200
+++ gcc/cp/parser.cc	2022-10-11 11:56:50.815463848 +0200
@@ -5583,7 +5583,9 @@ cp_parser_primary_expression (cp_parser
       /* Floating-point literals are only allowed in an integral
 	 constant expression if they are cast to an integral or
 	 enumeration type.  */
-      if (TREE_CODE (token->u.value) == REAL_CST
+      if ((TREE_CODE (token->u.value) == REAL_CST
+	   || (TREE_CODE (token->u.value) == EXCESS_PRECISION_EXPR
+	       && TREE_CODE (TREE_OPERAND (token->u.value, 0)) == REAL_CST))
 	  && parser->integral_constant_expression_p
 	  && pedantic)
 	{
--- gcc/cp/cvt.cc.jj	2022-10-11 09:59:39.633514043 +0200
+++ gcc/cp/cvt.cc	2022-10-11 10:06:55.785412518 +0200
@@ -684,6 +684,33 @@ cp_convert_and_check (tree type, tree ex
   return result;
 }
 
+/* Similarly, but deal with excess precision.  SEMANTIC_TYPE is the type this
+   conversion would use without excess precision.  If SEMANTIC_TYPE is NULL,
+   this function is equivalent to cp_convert_and_check.  This function is
+   a wrapper that handles conversions that may be different than the usual
+   ones because of excess precision.  */
+
+tree
+cp_ep_convert_and_check (tree type, tree expr, tree semantic_type,
+			 tsubst_flags_t complain)
+{
+  if (TREE_TYPE (expr) == type)
+    return expr;
+  if (expr == error_mark_node)
+    return expr;
+  if (!semantic_type)
+    return cp_convert_and_check (type, expr, complain);
+
+  if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+      && TREE_TYPE (expr) != semantic_type)
+    /* For integers, we need to check the real conversion, not
+       the conversion to the excess precision type.  */
+    expr = cp_convert_and_check (semantic_type, expr, complain);
+  /* Result type is the excess precision type, which should be
+     large enough, so do not check.  */
+  return cp_convert (type, expr, complain);
+}
+
 /* Conversion...
 
    FLAGS indicates how we should behave.  */
--- gcc/cp/call.cc.jj	2022-10-11 09:59:39.424516967 +0200
+++ gcc/cp/call.cc	2022-10-11 10:06:55.787412490 +0200
@@ -5374,6 +5374,7 @@ build_conditional_expr (const op_locatio
   tree arg3_type;
   tree result = NULL_TREE;
   tree result_type = NULL_TREE;
+  tree semantic_result_type = NULL_TREE;
   bool is_glvalue = true;
   struct z_candidate *candidates = 0;
   struct z_candidate *cand;
@@ -5407,6 +5408,9 @@ build_conditional_expr (const op_locatio
 	   expression, since it needs to be materialized for the
 	   conversion to bool, so treat it as an xvalue in arg2.  */
 	arg2 = move (TARGET_EXPR_SLOT (arg1));
+      else if (TREE_CODE (arg1) == EXCESS_PRECISION_EXPR)
+	arg2 = arg1 = build1 (EXCESS_PRECISION_EXPR, TREE_TYPE (arg1),
+			      cp_save_expr (TREE_OPERAND (arg1, 0)));
       else
 	arg2 = arg1 = cp_save_expr (arg1);
     }
@@ -5565,6 +5569,46 @@ build_conditional_expr (const op_locatio
   if (error_operand_p (arg1))
     return error_mark_node;
 
+  arg2_type = unlowered_expr_type (arg2);
+  arg3_type = unlowered_expr_type (arg3);
+
+  if ((TREE_CODE (arg2) == EXCESS_PRECISION_EXPR
+       || TREE_CODE (arg3) == EXCESS_PRECISION_EXPR)
+      && (TREE_CODE (arg2_type) == INTEGER_TYPE
+	  || TREE_CODE (arg2_type) == REAL_TYPE
+	  || TREE_CODE (arg2_type) == COMPLEX_TYPE)
+      && (TREE_CODE (arg3_type) == INTEGER_TYPE
+	  || TREE_CODE (arg3_type) == REAL_TYPE
+	  || TREE_CODE (arg3_type) == COMPLEX_TYPE))
+    {
+      semantic_result_type
+	= type_after_usual_arithmetic_conversions (arg2_type, arg3_type);
+      if (semantic_result_type == error_mark_node
+	  && TREE_CODE (arg2_type) == REAL_TYPE
+	  && TREE_CODE (arg3_type) == REAL_TYPE
+	  && (extended_float_type_p (arg2_type)
+	      || extended_float_type_p (arg3_type))
+	  && cp_compare_floating_point_conversion_ranks (arg2_type,
+							 arg3_type) == 3)
+	{
+	  if (complain & tf_error)
+	    error_at (loc, "operands to %<?:%> of types %qT and %qT "
+			   "have unordered conversion rank",
+		      arg2_type, arg3_type);
+	  return error_mark_node;
+	}
+      if (TREE_CODE (arg2) == EXCESS_PRECISION_EXPR)
+	{
+	  arg2 = TREE_OPERAND (arg2, 0);
+	  arg2_type = TREE_TYPE (arg2);
+	}
+      if (TREE_CODE (arg3) == EXCESS_PRECISION_EXPR)
+	{
+	  arg3 = TREE_OPERAND (arg3, 0);
+	  arg3_type = TREE_TYPE (arg3);
+	}
+    }
+
   /* [expr.cond]
 
      If either the second or the third operand has type (possibly
@@ -5572,8 +5616,6 @@ build_conditional_expr (const op_locatio
      array-to-pointer (_conv.array_), and function-to-pointer
      (_conv.func_) standard conversions are performed on the second
      and third operands.  */
-  arg2_type = unlowered_expr_type (arg2);
-  arg3_type = unlowered_expr_type (arg3);
   if (VOID_TYPE_P (arg2_type) || VOID_TYPE_P (arg3_type))
     {
       /* 'void' won't help in resolving an overloaded expression on the
@@ -5937,6 +5979,10 @@ build_conditional_expr (const op_locatio
 	    }
 	}
 
+      if (semantic_result_type && INTEGRAL_TYPE_P (arg2_type))
+	arg2 = perform_implicit_conversion (semantic_result_type, arg2, complain);
+      else if (semantic_result_type && INTEGRAL_TYPE_P (arg3_type))
+	arg3 = perform_implicit_conversion (semantic_result_type, arg3, complain);
       arg2 = perform_implicit_conversion (result_type, arg2, complain);
       arg3 = perform_implicit_conversion (result_type, arg3, complain);
     }
@@ -6024,9 +6070,15 @@ build_conditional_expr (const op_locatio
       /* If this expression is an rvalue, but might be mistaken for an
 	 lvalue, we must add a NON_LVALUE_EXPR.  */
       result = rvalue (result);
+      if (semantic_result_type)
+	result = build1 (EXCESS_PRECISION_EXPR, semantic_result_type,
+			 result);
     }
   else
-    result = force_paren_expr (result);
+    {
+      result = force_paren_expr (result);
+      gcc_assert (semantic_result_type == NULL_TREE);
+    }
 
   return result;
 }
@@ -7890,7 +7942,7 @@ maybe_warn_array_conv (location_t loc, c
 }
 
 /* We call this recursively in convert_like_internal.  */
-static tree convert_like (conversion *, tree, tree, int, bool, bool,
+static tree convert_like (conversion *, tree, tree, int, bool, bool, bool,
 			  tsubst_flags_t);
 
 /* Perform the conversions in CONVS on the expression EXPR.  FN and
@@ -7906,7 +7958,7 @@ static tree convert_like (conversion *,
 static tree
 convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
 		       bool issue_conversion_warnings, bool c_cast_p,
-		       tsubst_flags_t complain)
+		       bool nested_p, tsubst_flags_t complain)
 {
   tree totype = convs->type;
   diagnostic_t diag_kind;
@@ -7983,7 +8035,8 @@ convert_like_internal (conversion *convs
 		print_z_candidate (loc, N_("candidate is:"), t->cand);
 	      expr = convert_like (t, expr, fn, argnum,
 				   /*issue_conversion_warnings=*/false,
-				   /*c_cast_p=*/false, complain);
+				   /*c_cast_p=*/false, /*nested_p=*/true,
+				   complain);
 	      if (convs->kind == ck_ref_bind)
 		expr = convert_to_reference (totype, expr, CONV_IMPLICIT,
 					     LOOKUP_NORMAL, NULL_TREE,
@@ -7998,13 +8051,15 @@ convert_like_internal (conversion *convs
 	    {
 	      expr = convert_like (t, expr, fn, argnum,
 				   /*issue_conversion_warnings=*/false,
-				   /*c_cast_p=*/false, complain);
+				   /*c_cast_p=*/false, /*nested_p=*/true,
+				   complain);
 	      break;
 	    }
 	  else if (t->kind == ck_ambig)
 	    return convert_like (t, expr, fn, argnum,
 				 /*issue_conversion_warnings=*/false,
-				 /*c_cast_p=*/false, complain);
+				 /*c_cast_p=*/false, /*nested_p=*/true,
+				 complain);
 	  else if (t->kind == ck_identity)
 	    break;
 	}
@@ -8124,6 +8179,8 @@ convert_like_internal (conversion *convs
 
       if (type_unknown_p (expr))
 	expr = instantiate_type (totype, expr, complain);
+      if (!nested_p && TREE_CODE (expr) == EXCESS_PRECISION_EXPR)
+	expr = cp_convert (totype, TREE_OPERAND (expr, 0), complain);
       if (expr == null_node
 	  && INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (totype))
 	/* If __null has been converted to an integer type, we do not want to
@@ -8163,7 +8220,8 @@ convert_like_internal (conversion *convs
 	    FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), ix, val)
 	      {
 		tree sub = convert_like (convs->u.list[ix], val, fn,
-					 argnum, false, false, complain);
+					 argnum, false, false,
+					 /*nested_p=*/true, complain);
 		if (sub == error_mark_node)
 		  return sub;
 		if (!BRACE_ENCLOSED_INITIALIZER_P (val)
@@ -8231,7 +8289,7 @@ convert_like_internal (conversion *convs
   expr = convert_like (next_conversion (convs), expr, fn, argnum,
 		       convs->kind == ck_ref_bind
 		       ? issue_conversion_warnings : false,
-		       c_cast_p, complain & ~tf_no_cleanup);
+		       c_cast_p, /*nested_p=*/true, complain & ~tf_no_cleanup);
   if (expr == error_mark_node)
     return error_mark_node;
 
@@ -8493,7 +8551,15 @@ convert_like_internal (conversion *convs
     return error_mark_node;
 
   warning_sentinel w (warn_zero_as_null_pointer_constant);
-  if (issue_conversion_warnings)
+  if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR)
+    {
+      if (issue_conversion_warnings)
+	expr = cp_ep_convert_and_check (totype, TREE_OPERAND (expr, 0),
+					TREE_TYPE (expr), complain);
+      else
+	expr = cp_convert (totype, TREE_OPERAND (expr, 0), complain);
+    }
+  else if (issue_conversion_warnings)
     expr = cp_convert_and_check (totype, expr, complain);
   else
     expr = cp_convert (totype, expr, complain);
@@ -8527,7 +8593,7 @@ conv_unsafe_in_template_p (tree to, tree
 
 static tree
 convert_like (conversion *convs, tree expr, tree fn, int argnum,
-	      bool issue_conversion_warnings, bool c_cast_p,
+	      bool issue_conversion_warnings, bool c_cast_p, bool nested_p,
 	      tsubst_flags_t complain)
 {
   /* Creating &TARGET_EXPR<> in a template breaks when substituting,
@@ -8550,7 +8616,8 @@ convert_like (conversion *convs, tree ex
 	 error_mark_node.  */
     }
   expr = convert_like_internal (convs, expr, fn, argnum,
-				issue_conversion_warnings, c_cast_p, complain);
+				issue_conversion_warnings, c_cast_p,
+				nested_p, complain);
   if (expr == error_mark_node)
     return error_mark_node;
   return conv_expr ? conv_expr : expr;
@@ -8563,7 +8630,7 @@ convert_like (conversion *convs, tree ex
 {
   return convert_like (convs, expr, NULL_TREE, 0,
 		       /*issue_conversion_warnings=*/true,
-		       /*c_cast_p=*/false, complain);
+		       /*c_cast_p=*/false, /*nested_p=*/false, complain);
 }
 
 /* Convenience wrapper for convert_like.  */
@@ -8574,7 +8641,7 @@ convert_like_with_context (conversion *c
 {
   return convert_like (convs, expr, fn, argnum,
 		       /*issue_conversion_warnings=*/true,
-		       /*c_cast_p=*/false, complain);
+		       /*c_cast_p=*/false, /*nested_p=*/false, complain);
 }
 
 /* ARG is being passed to a varargs function.  Perform any conversions
@@ -8605,6 +8672,8 @@ convert_arg_to_ellipsis (tree arg, tsubs
 		    "implicit conversion from %qH to %qI when passing "
 		    "argument to function",
 		    arg_type, double_type_node);
+      if (TREE_CODE (arg) == EXCESS_PRECISION_EXPR)
+	arg = TREE_OPERAND (arg, 0);
       arg = mark_rvalue_use (arg);
       arg = convert_to_real_nofold (double_type_node, arg);
     }
@@ -8911,9 +8980,9 @@ convert_for_arg_passing (tree type, tree
 /* Returns non-zero iff FN is a function with magic varargs, i.e. ones for
    which just decay_conversion or no conversions at all should be done.
    This is true for some builtins which don't act like normal functions.
-   Return 2 if no conversions at all should be done, 1 if just
-   decay_conversion.  Return 3 for special treatment of the 3rd argument
-   for __builtin_*_overflow_p.  */
+   Return 2 if just decay_conversion and removal of excess precision should
+   be done, 1 if just decay_conversion.  Return 3 for special treatment of
+   the 3rd argument for __builtin_*_overflow_p.  */
 
 int
 magic_varargs_p (tree fn)
@@ -8932,7 +9001,15 @@ magic_varargs_p (tree fn)
       case BUILT_IN_MUL_OVERFLOW_P:
 	return 3;
 
-      default:;
+      case BUILT_IN_ISFINITE:
+      case BUILT_IN_ISINF:
+      case BUILT_IN_ISINF_SIGN:
+      case BUILT_IN_ISNAN:
+      case BUILT_IN_ISNORMAL:
+      case BUILT_IN_FPCLASSIFY:
+	return 2;
+
+      default:
 	return lookup_attribute ("type generic",
 				 TYPE_ATTRIBUTES (TREE_TYPE (fn))) != 0;
       }
@@ -9764,7 +9841,7 @@ build_over_call (struct z_candidate *can
   for (; arg_index < vec_safe_length (args); ++arg_index)
     {
       tree a = (*args)[arg_index];
-      if ((magic == 3 && arg_index == 2) || magic == 2)
+      if (magic == 3 && arg_index == 2)
 	{
 	  /* Do no conversions for certain magic varargs.  */
 	  a = mark_type_use (a);
@@ -9772,8 +9849,12 @@ build_over_call (struct z_candidate *can
 	    return error_mark_node;
 	}
       else if (magic != 0)
-	/* For other magic varargs only do decay_conversion.  */
-	a = decay_conversion (a, complain);
+	{
+	  if (magic == 1 && TREE_CODE (a) == EXCESS_PRECISION_EXPR)
+	    a = TREE_OPERAND (a, 0);
+	  /* For other magic varargs only do decay_conversion.  */
+	  a = decay_conversion (a, complain);
+	}
       else if (DECL_CONSTRUCTOR_P (fn)
 	       && same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (fn),
 							     TREE_TYPE (a)))
@@ -13051,7 +13132,7 @@ perform_direct_initialization_if_possibl
   else
     expr = convert_like (conv, expr, NULL_TREE, 0,
 			 /*issue_conversion_warnings=*/false,
-			 c_cast_p, complain);
+			 c_cast_p, /*nested_p=*/false, complain);
 
   /* Free all the conversions we allocated.  */
   obstack_free (&conversion_obstack, p);
--- gcc/cp/constexpr.cc.jj	2022-10-11 09:59:39.481516169 +0200
+++ gcc/cp/constexpr.cc	2022-10-11 10:06:55.788412476 +0200
@@ -7618,6 +7618,19 @@ cxx_eval_constant_expression (const cons
       }
       break;
 
+    case EXCESS_PRECISION_EXPR:
+      {
+	tree oldop = TREE_OPERAND (t, 0);
+
+	tree op = cxx_eval_constant_expression (ctx, oldop,
+						lval,
+						non_constant_p, overflow_p);
+	if (*non_constant_p)
+	  return t;
+	r = fold_convert (TREE_TYPE (t), op);
+	break;
+      }
+
     case EMPTY_CLASS_EXPR:
       /* Handle EMPTY_CLASS_EXPR produced by build_call_a by lowering
 	 it to an appropriate CONSTRUCTOR.  */
@@ -8918,6 +8931,9 @@ potential_constant_expression_1 (tree t,
                sub-object of such an object;  */
       return RECUR (TREE_OPERAND (t, 0), rval);
 
+    case EXCESS_PRECISION_EXPR:
+      return RECUR (TREE_OPERAND (t, 0), rval);
+
     case VAR_DECL:
       if (DECL_HAS_VALUE_EXPR_P (t))
 	{
--- gcc/cp/pt.cc.jj	2022-10-11 09:59:39.698513133 +0200
+++ gcc/cp/pt.cc	2022-10-11 10:06:55.792412420 +0200
@@ -17401,6 +17401,15 @@ tsubst_copy (tree t, tree args, tsubst_f
 	return r;
       }
 
+    case EXCESS_PRECISION_EXPR:
+      {
+	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+	tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
+	if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR)
+	  return op0;
+	return build1_loc (EXPR_LOCATION (t), code, type, op0);
+      }
+
     case COMPONENT_REF:
       {
 	tree object;
@@ -20429,6 +20438,16 @@ tsubst_copy_and_build (tree t,
 				templated_operator_saved_lookups (t),
 				complain|decltype_flag));
 
+    case EXCESS_PRECISION_EXPR:
+      {
+	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+	tree op0 = RECUR (TREE_OPERAND (t, 0));
+	if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR)
+	  RETURN (op0);
+	RETURN (build1_loc (input_location, EXCESS_PRECISION_EXPR,
+			    type, op0));
+      }
+
     case FIX_TRUNC_EXPR:
       /* convert_like should have created an IMPLICIT_CONV_EXPR.  */
       gcc_unreachable ();
--- gcc/cp/cp-tree.h.jj	2022-10-11 09:59:39.512515736 +0200
+++ gcc/cp/cp-tree.h	2022-10-11 10:06:55.793412406 +0200
@@ -6766,6 +6766,8 @@ extern tree ocp_convert				(tree, tree,
 						 tsubst_flags_t);
 extern tree cp_convert				(tree, tree, tsubst_flags_t);
 extern tree cp_convert_and_check                (tree, tree, tsubst_flags_t);
+extern tree cp_ep_convert_and_check             (tree, tree, tree,
+						 tsubst_flags_t);
 extern tree cp_fold_convert			(tree, tree);
 extern tree cp_get_callee			(tree);
 extern tree cp_get_callee_fndecl		(tree);
--- gcc/cp/cp-gimplify.cc.jj	2022-10-11 09:59:39.482516155 +0200
+++ gcc/cp/cp-gimplify.cc	2022-10-11 10:06:55.794412392 +0200
@@ -2522,6 +2522,11 @@ cp_fold (tree x)
 
       break;
 
+    case EXCESS_PRECISION_EXPR:
+      op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops);
+      x = fold_convert_loc (EXPR_LOCATION (x), TREE_TYPE (x), op0);
+      break;
+
     case INDIRECT_REF:
       /* We don't need the decltype(auto) obfuscation anymore.  */
       if (REF_PARENTHESIZED_P (x))
--- gcc/cp/typeck.cc.jj	2022-10-11 09:59:39.738512574 +0200
+++ gcc/cp/typeck.cc	2022-10-11 10:24:31.875679017 +0200
@@ -4603,11 +4603,16 @@ convert_arguments (tree typelist, vec<tr
 	}
       else
 	{
-	  if (fndecl && magic_varargs_p (fndecl))
-	    /* Don't do ellipsis conversion for __built_in_constant_p
-	       as this will result in spurious errors for non-trivial
-	       types.  */
-	    val = require_complete_type (val, complain);
+	  int magic = fndecl ? magic_varargs_p (fndecl) : 0;
+	  if (magic)
+	    {
+	      if (magic == 1 && TREE_CODE (val) == EXCESS_PRECISION_EXPR)
+		val = TREE_OPERAND (val, 0);
+	      /* Don't do ellipsis conversion for __built_in_constant_p
+		 as this will result in spurious errors for non-trivial
+		 types.  */
+	      val = require_complete_type (val, complain);
+	    }
 	  else
 	    val = convert_arg_to_ellipsis (val, complain);
 
@@ -5057,7 +5062,7 @@ cp_build_binary_op (const op_location_t
 {
   tree op0, op1;
   enum tree_code code0, code1;
-  tree type0, type1;
+  tree type0, type1, orig_type0, orig_type1;
   const char *invalid_op_diag;
 
   /* Expression code to give to the expression when it is built.
@@ -5069,6 +5074,10 @@ cp_build_binary_op (const op_location_t
      In the simplest cases this is the common type of the arguments.  */
   tree result_type = NULL_TREE;
 
+  /* When the computation is in excess precision, the type of the
+     final EXCESS_PRECISION_EXPR.  */
+  tree semantic_result_type = NULL;
+
   /* Nonzero means operands have already been type-converted
      in whatever way is necessary.
      Zero means they need to be converted to RESULT_TYPE.  */
@@ -5116,6 +5125,10 @@ cp_build_binary_op (const op_location_t
   /* Tree holding instrumentation expression.  */
   tree instrument_expr = NULL_TREE;
 
+  /* True means this is an arithmetic operation that may need excess
+     precision.  */
+  bool may_need_excess_precision;
+
   /* Apply default conversions.  */
   op0 = resolve_nondeduced_context (orig_op0, complain);
   op1 = resolve_nondeduced_context (orig_op1, complain);
@@ -5167,8 +5180,8 @@ cp_build_binary_op (const op_location_t
 	}
     }
 
-  type0 = TREE_TYPE (op0); 
-  type1 = TREE_TYPE (op1);
+  orig_type0 = type0 = TREE_TYPE (op0); 
+  orig_type1 = type1 = TREE_TYPE (op1);
 
   /* The expression codes of the data types of the arguments tell us
      whether the arguments are integers, floating, pointers, etc.  */
@@ -5201,6 +5214,47 @@ cp_build_binary_op (const op_location_t
       return error_mark_node;
     }
 
+  switch (code)
+    {
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case EXACT_DIV_EXPR:
+      may_need_excess_precision = true;
+      break;
+    default:
+      may_need_excess_precision = false;
+      break;
+    }
+  if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR)
+    {
+      op0 = TREE_OPERAND (op0, 0);
+      type0 = TREE_TYPE (op0);
+    }
+  else if (may_need_excess_precision
+	   && (code0 == REAL_TYPE || code0 == COMPLEX_TYPE))
+    if (tree eptype = excess_precision_type (type0))
+      {
+	type0 = eptype;
+	op0 = convert (eptype, op0);
+      }
+  if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR)
+    {
+      op1 = TREE_OPERAND (op1, 0);
+      type1 = TREE_TYPE (op1);
+    }
+  else if (may_need_excess_precision
+	   && (code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
+    if (tree eptype = excess_precision_type (type1))
+      {
+	type1 = eptype;
+	op1 = convert (eptype, op1);
+      }
+
   /* Issue warnings about peculiar, but valid, uses of NULL.  */
   if ((null_node_p (orig_op0) || null_node_p (orig_op1))
       /* It's reasonable to use pointer values as operands of &&
@@ -5240,7 +5294,7 @@ cp_build_binary_op (const op_location_t
               op0 = convert (TREE_TYPE (type1), op0);
 	      op0 = save_expr (op0);
               op0 = build_vector_from_val (type1, op0);
-              type0 = TREE_TYPE (op0);
+	      orig_type0 = type0 = TREE_TYPE (op0);
               code0 = TREE_CODE (type0);
               converted = 1;
               break;
@@ -5250,7 +5304,7 @@ cp_build_binary_op (const op_location_t
               op1 = convert (TREE_TYPE (type0), op1);
 	      op1 = save_expr (op1);
               op1 = build_vector_from_val (type0, op1);
-              type1 = TREE_TYPE (op1);
+	      orig_type1 = type1 = TREE_TYPE (op1);
               code1 = TREE_CODE (type1);
               converted = 1;
               break;
@@ -6091,6 +6145,27 @@ cp_build_binary_op (const op_location_t
 				    TREE_TYPE (orig_op1));
 	}
     }
+  if (may_need_excess_precision
+      && (orig_type0 != type0 || orig_type1 != type1))
+    {
+      gcc_assert (common);
+      semantic_result_type = cp_common_type (orig_type0, orig_type1);
+      if (semantic_result_type == error_mark_node
+	  && code0 == REAL_TYPE
+	  && code1 == REAL_TYPE
+	  && (extended_float_type_p (orig_type0)
+	      || extended_float_type_p (orig_type1))
+	  && cp_compare_floating_point_conversion_ranks (orig_type0,
+							 orig_type1) == 3)
+	{
+	  if (complain & tf_error)
+	    {
+	      rich_location richloc (line_table, location);
+	      binary_op_error (&richloc, code, type0, type1);
+	    }
+	  return error_mark_node;
+	}
+    }
 
   if (code == SPACESHIP_EXPR)
     {
@@ -6181,6 +6256,8 @@ cp_build_binary_op (const op_location_t
 			 build_type ? build_type : result_type,
 			 NULL_TREE, op1);
       TREE_OPERAND (tmp, 0) = op0;
+      if (semantic_result_type)
+	tmp = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, tmp);
       return tmp;
     }
 
@@ -6268,6 +6345,9 @@ cp_build_binary_op (const op_location_t
 		}
 	    }
 	  result = build2 (COMPLEX_EXPR, result_type, real, imag);
+	  if (semantic_result_type)
+	    result = build1 (EXCESS_PRECISION_EXPR, semantic_result_type,
+			     result);
 	  return result;
 	}
 
@@ -6363,9 +6443,11 @@ cp_build_binary_op (const op_location_t
     {
       warning_sentinel w (warn_sign_conversion, short_compare);
       if (!same_type_p (TREE_TYPE (op0), result_type))
-	op0 = cp_convert_and_check (result_type, op0, complain);
+	op0 = cp_ep_convert_and_check (result_type, op0,
+				       semantic_result_type, complain);
       if (!same_type_p (TREE_TYPE (op1), result_type))
-	op1 = cp_convert_and_check (result_type, op1, complain);
+	op1 = cp_ep_convert_and_check (result_type, op1,
+				       semantic_result_type, complain);
 
       if (op0 == error_mark_node || op1 == error_mark_node)
 	return error_mark_node;
@@ -6435,6 +6517,9 @@ cp_build_binary_op (const op_location_t
   if (resultcode == SPACESHIP_EXPR && !processing_template_decl)
     result = get_target_expr (result, complain);
 
+  if (semantic_result_type)
+    result = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, result);
+
   if (!c_inhibit_evaluation_warnings)
     {
       if (!processing_template_decl)
@@ -7161,6 +7246,7 @@ cp_build_unary_op (enum tree_code code,
   tree arg = xarg;
   location_t location = cp_expr_loc_or_input_loc (arg);
   tree argtype = 0;
+  tree eptype = NULL_TREE;
   const char *errstring = NULL;
   tree val;
   const char *invalid_op_diag;
@@ -7181,6 +7267,12 @@ cp_build_unary_op (enum tree_code code,
       return error_mark_node;
     }
 
+  if (TREE_CODE (arg) == EXCESS_PRECISION_EXPR)
+    {
+      eptype = TREE_TYPE (arg);
+      arg = TREE_OPERAND (arg, 0);
+    }
+
   switch (code)
     {
     case UNARY_PLUS_EXPR:
@@ -7276,8 +7368,11 @@ cp_build_unary_op (enum tree_code code,
 
     case REALPART_EXPR:
     case IMAGPART_EXPR:
-      arg = build_real_imag_expr (input_location, code, arg);
-      return arg;
+      val = build_real_imag_expr (input_location, code, arg);
+      if (eptype && TREE_CODE (eptype) == COMPLEX_EXPR)
+	val = build1_loc (input_location, EXCESS_PRECISION_EXPR,
+			  TREE_TYPE (eptype), val);
+      return val;
 
     case PREINCREMENT_EXPR:
     case POSTINCREMENT_EXPR:
@@ -7288,7 +7383,7 @@ cp_build_unary_op (enum tree_code code,
 
       val = unary_complex_lvalue (code, arg);
       if (val != 0)
-	return val;
+	goto return_build_unary_op;
 
       arg = mark_lvalue_use (arg);
 
@@ -7304,8 +7399,8 @@ cp_build_unary_op (enum tree_code code,
 	  real = cp_build_unary_op (code, real, true, complain);
 	  if (real == error_mark_node || imag == error_mark_node)
 	    return error_mark_node;
-	  return build2 (COMPLEX_EXPR, TREE_TYPE (arg),
-			 real, imag);
+	  val = build2 (COMPLEX_EXPR, TREE_TYPE (arg), real, imag);
+	  goto return_build_unary_op;
 	}
 
       /* Report invalid types.  */
@@ -7468,7 +7563,7 @@ cp_build_unary_op (enum tree_code code,
 	  val = build2 (code, TREE_TYPE (arg), arg, inc);
 
 	TREE_SIDE_EFFECTS (val) = 1;
-	return val;
+	goto return_build_unary_op;
       }
 
     case ADDR_EXPR:
@@ -7484,7 +7579,11 @@ cp_build_unary_op (enum tree_code code,
     {
       if (argtype == 0)
 	argtype = TREE_TYPE (arg);
-      return build1 (code, argtype, arg);
+      val = build1 (code, argtype, arg);
+    return_build_unary_op:
+      if (eptype)
+	val = build1 (EXCESS_PRECISION_EXPR, eptype, val);
+      return val;
     }
 
   if (complain & tf_error)
@@ -7875,6 +7974,15 @@ cp_build_compound_expr (tree lhs, tree r
   if (lhs == error_mark_node || rhs == error_mark_node)
     return error_mark_node;
 
+  if (TREE_CODE (lhs) == EXCESS_PRECISION_EXPR)
+    lhs = TREE_OPERAND (lhs, 0);
+  tree eptype = NULL_TREE;
+  if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
+    {
+      eptype = TREE_TYPE (rhs);
+      rhs = TREE_OPERAND (rhs, 0);
+    }
+
   if (TREE_CODE (rhs) == TARGET_EXPR)
     {
       /* If the rhs is a TARGET_EXPR, then build the compound
@@ -7885,6 +7993,8 @@ cp_build_compound_expr (tree lhs, tree r
       init = build2 (COMPOUND_EXPR, TREE_TYPE (init), lhs, init);
       TREE_OPERAND (rhs, 1) = init;
 
+      if (eptype)
+	rhs = build1 (EXCESS_PRECISION_EXPR, eptype, rhs);
       return rhs;
     }
 
@@ -7896,7 +8006,10 @@ cp_build_compound_expr (tree lhs, tree r
       return error_mark_node;
     }
   
-  return build2 (COMPOUND_EXPR, TREE_TYPE (rhs), lhs, rhs);
+  tree ret = build2 (COMPOUND_EXPR, TREE_TYPE (rhs), lhs, rhs);
+  if (eptype)
+    ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret);
+  return ret;
 }
 
 /* Issue a diagnostic message if casting from SRC_TYPE to DEST_TYPE
@@ -8180,7 +8293,11 @@ build_static_cast_1 (location_t loc, tre
 
      Any expression can be explicitly converted to type cv void.  */
   if (VOID_TYPE_P (type))
-    return convert_to_void (expr, ICV_CAST, complain);
+    {
+      if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR)
+	expr = TREE_OPERAND (expr, 0);
+      return convert_to_void (expr, ICV_CAST, complain);
+    }
 
   /* [class.abstract]
      An abstract class shall not be used ... as the type of an explicit
@@ -8259,6 +8376,8 @@ build_static_cast_1 (location_t loc, tre
     {
       if (processing_template_decl)
 	return expr;
+      if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR)
+	expr = TREE_OPERAND (expr, 0);
       return ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL, complain);
     }
 
--- gcc/testsuite/gcc.target/i386/excess-precision-1.c.jj	2022-10-11 09:59:39.861510854 +0200
+++ gcc/testsuite/gcc.target/i386/excess-precision-1.c	2022-10-11 10:06:55.795412378 +0200
@@ -5,8 +5,14 @@
 
 #include <float.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 extern void abort (void);
 extern void exit (int);
+#ifdef __cplusplus
+}
+#endif
 
 volatile float f1 = 1.0f;
 volatile float f2 = 0x1.0p-30f;
--- gcc/testsuite/gcc.target/i386/excess-precision-2.c.jj	2022-10-11 09:59:39.877510630 +0200
+++ gcc/testsuite/gcc.target/i386/excess-precision-2.c	2022-10-11 10:06:55.796412364 +0200
@@ -4,8 +4,14 @@
 
 #include <float.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 extern void abort (void);
 extern void exit (int);
+#ifdef __cplusplus
+}
+#endif
 
 volatile long double ldadd1 = 1.0l + 0x1.0p-30l;
 volatile long double ld11f = 1.1f;
--- gcc/testsuite/gcc.target/i386/excess-precision-3.c.jj	2022-10-11 09:59:39.894510392 +0200
+++ gcc/testsuite/gcc.target/i386/excess-precision-3.c	2022-10-11 10:06:55.796412364 +0200
@@ -6,8 +6,14 @@
 #include <float.h>
 #include <stdarg.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 extern void abort (void);
 extern void exit (int);
+#ifdef __cplusplus
+}
+#endif
 
 volatile float f1 = 1.0f;
 volatile float f2 = 0x1.0p-30f;
@@ -100,6 +106,7 @@ check_double (double d)
     abort ();
 }
 
+#ifndef __cplusplus
 static inline void
 check_float_nonproto (f)
      float f;
@@ -115,6 +122,7 @@ check_double_nonproto (d)
   if (d != dadd2)
     abort ();
 }
+#endif
 
 static void
 check_double_va (int i, ...)
@@ -132,9 +140,11 @@ test_call (void)
   check_float (f1 + f2);
   check_double (d1 + d2 + d3);
   check_double (f1 + f2 + f3);
+#ifndef __cplusplus
   check_float_nonproto (f1 + f2);
   check_double_nonproto (d1 + d2 + d3);
   check_double_nonproto (f1 + f2 + f3);
+#endif
   check_double_va (0, d1 + d2 + d3);
   check_double_va (0, f1 + f2 + f3);
 }
--- gcc/testsuite/gcc.target/i386/excess-precision-7.c.jj	2022-10-11 09:59:39.917510070 +0200
+++ gcc/testsuite/gcc.target/i386/excess-precision-7.c	2022-10-11 10:06:55.796412364 +0200
@@ -4,8 +4,14 @@
 /* { dg-do run } */
 /* { dg-options "-std=c99 -mfpmath=387 -fexcess-precision=standard" } */
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 extern void abort (void);
 extern void exit (int);
+#ifdef __cplusplus
+}
+#endif
 
 int
 main (void)
--- gcc/testsuite/gcc.target/i386/excess-precision-9.c.jj	2022-10-11 09:59:39.947509650 +0200
+++ gcc/testsuite/gcc.target/i386/excess-precision-9.c	2022-10-11 10:06:55.796412364 +0200
@@ -3,8 +3,14 @@
 /* { dg-do run } */
 /* { dg-options "-std=c99 -mfpmath=387 -fexcess-precision=standard" } */
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 extern void abort (void);
 extern void exit (int);
+#ifdef __cplusplus
+}
+#endif
 
 int
 main (void)
--- gcc/testsuite/g++.target/i386/excess-precision-1.C.jj	2022-10-11 10:06:55.796412364 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-1.C	2022-10-11 10:06:55.796412364 +0200
@@ -0,0 +1,6 @@
+// Excess precision tests.  Test that excess precision is carried
+// through various operations.
+// { dg-do run }
+// { dg-options "-O2 -mfpmath=387 -fexcess-precision=standard" }
+
+#include "../../gcc.target/i386/excess-precision-1.c"
--- gcc/testsuite/g++.target/i386/excess-precision-2.C.jj	2022-10-11 10:06:55.796412364 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-2.C	2022-10-11 10:06:55.796412364 +0200
@@ -0,0 +1,5 @@
+// Excess precision tests.  Test excess precision of constants.
+// { dg-do run }
+// { dg-options "-O2 -mfpmath=387 -fexcess-precision=standard" }
+
+#include "../../gcc.target/i386/excess-precision-2.c"
--- gcc/testsuite/g++.target/i386/excess-precision-3.C.jj	2022-10-11 10:06:55.796412364 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-3.C	2022-10-11 10:06:55.796412364 +0200
@@ -0,0 +1,6 @@
+// Excess precision tests.  Test excess precision is removed when
+// necessary.
+// { dg-do run }
+// { dg-options "-O2 -mfpmath=387 -fexcess-precision=standard" }
+
+#include "../../gcc.target/i386/excess-precision-3.c"
--- gcc/testsuite/g++.target/i386/excess-precision-4.C.jj	2022-10-11 10:06:55.796412364 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-4.C	2022-10-11 10:06:55.796412364 +0200
@@ -0,0 +1,7 @@
+// Excess precision tests.  Test diagnostics for excess precision of
+// constants.
+// { dg-do compile }
+// { dg-options "-mfpmath=387 -fexcess-precision=standard" }
+
+float f = 0.0f * 1e50f; // { dg-warning "floating constant exceeds range of 'float'" }
+double d = 0.0 * 1e400; // { dg-warning "floating constant exceeds range of 'double'" }
--- gcc/testsuite/g++.target/i386/excess-precision-5.C.jj	2022-10-11 10:06:55.797412351 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-5.C	2022-10-11 10:06:55.797412351 +0200
@@ -0,0 +1,32 @@
+// Excess precision tests.  Verify excess precision doesn't affect
+// actual types.
+// { dg-do compile { target c++11 } }
+// { dg-options "-mfpmath=387 -fexcess-precision=standard" }
+
+namespace std {
+  template<typename T, T v> struct integral_constant {
+    static constexpr T value = v;
+  };
+  typedef integral_constant<bool, false> false_type;
+  typedef integral_constant<bool, true> true_type;
+  template<class T, class U>
+  struct is_same : std::false_type {};
+  template <class T>
+  struct is_same<T, T> : std::true_type {};
+}
+
+float f;
+double d;
+
+void
+test_types (void)
+{
+#define CHECK_FLOAT(E) static_assert (std::is_same <float, decltype (E)>::value, "")
+#define CHECK_DOUBLE(E) static_assert (std::is_same <double, decltype (E)>::value, "")
+  CHECK_FLOAT (f + f);
+  CHECK_DOUBLE (d + d);
+  CHECK_FLOAT (f * f / f);
+  CHECK_DOUBLE (d * d / d);
+  CHECK_FLOAT (f ? f - f : f);
+  CHECK_DOUBLE (d ? d - d : d);
+}
--- gcc/testsuite/g++.target/i386/excess-precision-6.C.jj	2022-10-11 10:06:55.797412351 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-6.C	2022-10-11 10:06:55.797412351 +0200
@@ -0,0 +1,19 @@
+// Excess precision tests.  Make sure sqrt is not inlined for float or
+// double.
+// { dg-do compile }
+// { dg-options "-mfpmath=387 -O2 -fno-math-errno -fexcess-precision=standard" }
+
+float f;
+double d;
+
+float fr;
+double dr;
+
+void
+test_builtins (void)
+{
+  fr = __builtin_sqrtf (f);
+  dr = __builtin_sqrt (d);
+}
+
+// { dg-final { scan-assembler-not "fsqrt" } }
--- gcc/testsuite/g++.target/i386/excess-precision-7.C.jj	2022-10-11 10:06:55.797412351 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-7.C	2022-10-11 10:06:55.797412351 +0200
@@ -0,0 +1,7 @@
+// Excess precision tests.  Test C99 semantics for conversions from
+// integers to floating point: no excess precision for either explicit
+// or implicit conversions.
+// { dg-do run }
+// { dg-options "-mfpmath=387 -fexcess-precision=standard" }
+
+#include "../../gcc.target/i386/excess-precision-7.c"
--- gcc/testsuite/g++.target/i386/excess-precision-8.C.jj	2022-10-11 10:06:55.797412351 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-8.C	2022-10-11 10:06:55.797412351 +0200
@@ -0,0 +1,105 @@
+// Excess precision tests.  Test excess precision is removed when
+// necessary.
+// { dg-do run }
+// { dg-options "-O2 -mfpmath=387 -fexcess-precision=standard" }
+
+#include <float.h>
+#include <stdarg.h>
+
+extern "C" void abort ();
+
+volatile float f1 = 1.0f;
+volatile float f2 = 0x1.0p-30f;
+volatile float f3 = 0x1.0p-60f;
+volatile double d1 = 1.0;
+volatile double d2 = 0x1.0p-30;
+volatile double d3 = 0x1.0p-60;
+volatile double d3d = 0x1.0p-52;
+volatile float fadd1 = 1.0f + 0x1.0p-30f;
+volatile double dadd2 = 1.0 + 0x1.0p-30 + 0x1.0p-60;
+volatile double dh = 0x1.0p-24;
+volatile float fha = 1.0f + 0x1.0p-23f;
+
+static inline void
+check_float (float f)
+{
+  if (f != fadd1)
+    abort ();
+}
+
+static inline void
+check_float (double)
+{
+  abort ();
+}
+
+static inline void
+check_float (long double)
+{
+  abort ();
+}
+
+static inline void
+check_double (double d)
+{
+  if (d != dadd2)
+    abort ();
+}
+
+static inline void
+check_double (long double)
+{
+  abort ();
+}
+
+static inline void
+check_float2 (float f)
+{
+  if (f != fha)
+    abort ();
+}
+
+struct S {
+  S () {}
+  S (float f) { if (f != fadd1) abort (); }
+};
+
+struct T {
+  T () {}
+  T (double d) { if (d != dadd2) abort (); }
+};
+
+static inline void
+check_float3 (S)
+{
+}
+
+static inline void
+check_double2 (T)
+{
+}
+
+void
+test_call ()
+{
+  check_float (f1 + f2);
+  check_double (f1 + f2);
+  check_double (d1 + d2 + d3);
+  /* Verify rounding direct to float without double rounding.  */
+  if (sizeof (long double) > sizeof (double))
+    check_float2 (d1 + dh + d3);
+  else
+    check_float2 (d1 + dh + d3d);
+  check_float3 (f1 + f2);
+  check_double2 (f1 + f2);
+  check_double2 (d1 + d2 + d3);
+  S s1 = static_cast<S> (f1 + f2);
+  T t2 = static_cast<T> (f1 + f2);
+  T t3 = static_cast<T> (d1 + d2 + d3);
+}
+
+int
+main ()
+{
+  test_call ();
+}
--- gcc/testsuite/g++.target/i386/excess-precision-9.C.jj	2022-10-11 10:06:55.797412351 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-9.C	2022-10-11 10:06:55.797412351 +0200
@@ -0,0 +1,6 @@
+// Excess precision tests.  Test implicit conversions in comparisons:
+// no excess precision in C++.
+// { dg-do run }
+// { dg-options "-mfpmath=387 -fexcess-precision=standard" }
+
+#include "../../gcc.target/i386/excess-precision-9.c"
--- gcc/testsuite/c-c++-common/dfp/convert-bfp-10.c.jj	2020-01-12 11:54:37.003404507 +0100
+++ gcc/testsuite/c-c++-common/dfp/convert-bfp-10.c	2022-10-11 11:20:40.511702027 +0200
@@ -1,4 +1,5 @@
 /* This test assumes IEEE float and double.  */
+/* { dg-additional-options "-fexcess-precision=fast" } */
 
 #include "convert.h"
 
--- gcc/testsuite/c-c++-common/dfp/compare-eq-const.c.jj	2020-01-12 11:54:37.003404507 +0100
+++ gcc/testsuite/c-c++-common/dfp/compare-eq-const.c	2022-10-11 11:18:31.432502023 +0200
@@ -1,5 +1,6 @@
 /* C99 6.5.9 Equality operators.
    Compare decimal float constants against each other. */
+/* { dg-additional-options "-fexcess-precision=fast" } */
 
 #include "dfp-dbg.h"
 
--- gcc/testsuite/g++.dg/cpp1z/constexpr-96862.C.jj	2020-09-03 20:11:34.160825160 +0200
+++ gcc/testsuite/g++.dg/cpp1z/constexpr-96862.C	2022-10-11 11:51:31.563910365 +0200
@@ -1,6 +1,6 @@
 // PR c++/96862
 // { dg-do compile { target c++17 } }
-// { dg-additional-options "-frounding-math" }
+// { dg-additional-options "-frounding-math -fexcess-precision=fast" }
 
 constexpr double a = 0x1.0p+100 + 0x1.0p-100;
 const double b = 0x1.0p+100 + 0x1.0p-100;
--- gcc/testsuite/g++.dg/cpp1z/decomp12.C.jj	2020-01-12 11:54:37.128402621 +0100
+++ gcc/testsuite/g++.dg/cpp1z/decomp12.C	2022-10-11 11:30:05.737825169 +0200
@@ -7,13 +7,13 @@ template <typename, typename> struct sam
 template <typename T> struct same_type<T, T> {};
 
 int main() {
-  std::tuple tuple = { 1, 'a', 2.3, true };
+  std::tuple tuple = { 1, 'a', 2.25, true };
   auto[i, c, d, b] = tuple;
   same_type<std::tuple_element<0, decltype(tuple)>::type, decltype(i)>{};
   same_type<decltype(i), int>{};
   same_type<decltype(c), char>{};
   same_type<decltype(d), double>{};
   same_type<decltype(b), bool>{};
-  if (i != 1 || c != 'a' || d != 2.3 || b != true)
+  if (i != 1 || c != 'a' || d != 2.25 || b != true)
     __builtin_abort ();
 }
--- gcc/testsuite/g++.dg/other/thunk1.C.jj	2020-01-12 11:54:37.218401263 +0100
+++ gcc/testsuite/g++.dg/other/thunk1.C	2022-10-11 11:30:37.350384645 +0200
@@ -1,5 +1,6 @@
 // PR c++/12007 Multiple inheritance float pass by value fails
 // { dg-do run }
+// { dg-additional-options "-fexcess-precision=fast" }
 
 extern "C" void abort (void);
 
--- gcc/testsuite/g++.dg/vect/pr64410.cc.jj	2020-01-12 11:54:37.279400343 +0100
+++ gcc/testsuite/g++.dg/vect/pr64410.cc	2022-10-11 11:31:54.970302984 +0200
@@ -1,5 +1,6 @@
 // { dg-do compile }
 // { dg-require-effective-target vect_double }
+// { dg-additional-options "-fexcess-precision=fast" }
 
 #include <vector>
 #include <complex>
--- gcc/testsuite/g++.dg/cpp1y/pr68180.C.jj	2020-01-12 11:54:37.121402727 +0100
+++ gcc/testsuite/g++.dg/cpp1y/pr68180.C	2022-10-11 11:50:42.324596315 +0200
@@ -1,6 +1,6 @@
 // PR c++/68180
 // { dg-do compile { target c++14 } }
-// { dg-additional-options "-Wno-psabi" }
+// { dg-additional-options "-Wno-psabi -fexcess-precision=fast" }
 
 typedef float __attribute__( ( vector_size( 16 ) ) ) float32x4_t;
 constexpr float32x4_t fill(float x) {
--- gcc/testsuite/g++.dg/cpp0x/variadic-tuple.C.jj	2022-05-20 11:45:17.801744787 +0200
+++ gcc/testsuite/g++.dg/cpp0x/variadic-tuple.C	2022-10-11 11:28:34.282099648 +0200
@@ -1,4 +1,5 @@
 // { dg-do run { target c++11 } }
+// { dg-additional-options "-fexcess-precision=fast" }
 // An implementation of TR1's <tuple> using variadic teplates
 // Contributed by Douglas Gregor <doug.gregor@gmail.com>
 
--- gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C.jj	2020-01-12 11:54:37.087403240 +0100
+++ gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C	2022-10-11 11:27:50.009716597 +0200
@@ -18,8 +18,8 @@ int main()
 {
   Test t;
   B b;
-  B b2(4.2);
+  B b2(4.25);
 
-  if (t.a != 4 || b.i != 42 || b2.d != 4.2)
+  if (t.a != 4 || b.i != 42 || b2.d != 4.25)
     __builtin_abort();
 }
--- gcc/testsuite/g++.old-deja/g++.brendan/copy9.C.jj	2020-01-11 16:31:54.872295939 +0100
+++ gcc/testsuite/g++.old-deja/g++.brendan/copy9.C	2022-10-11 11:10:40.589067853 +0200
@@ -1,4 +1,5 @@
 // { dg-do run  }
+// { dg-additional-options "-fexcess-precision=fast" }
 // GROUPS passed copy-ctors
 #include <iostream>
 
--- gcc/testsuite/g++.old-deja/g++.brendan/overload7.C.jj	2020-01-11 16:31:54.877295864 +0100
+++ gcc/testsuite/g++.old-deja/g++.brendan/overload7.C	2022-10-11 11:11:45.238166331 +0200
@@ -1,4 +1,5 @@
 // { dg-do run  }
+// { dg-additional-options "-fexcess-precision=fast" }
 // GROUPS passed overloading
 extern "C" int printf (const char *, ...);
 
