[C++ PATCH] Allow frexp etc. builtins in c++14 constexpr (PR c++/50060)

Jakub Jelinek jakub@redhat.com
Fri Jul 15 18:42:00 GMT 2016


Hi!

While in C++11, builtins returning two results, one of them by dereferencing
a pointer argument can't be constexpr, in my understanding in C++14
generalized constexprs they can.

So, this patch tweaks cxx_eval_builtin_function_call so that it handles how
builtins.c folds these builtins (i.e. COMPOUND_EXPR with first operand
being *arg = const1 and second operand const2, optionally all wrapped into a
NON_LVALUE_EXPR.

In addition, I've noticed that the lval argument is passed down to
evaluation of arguments, that doesn't make sense to me, IMHO arguments
should be always evakyated as rvalues (and for non-builtins they are).

sincos (which has stores 2 results through pointers) is folded earlier into
cexpi and thus worked already before.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2016-07-15  Jakub Jelinek  <jakub@redhat.com>

	PR c++/50060
	* constexpr.c (cxx_eval_builtin_function_call): Pass false as lval
	when evaluating call arguments, make the lval argument nameless.  For
	C++14 and later, if new_call is COMPOUND_EXPR with a assignment and
	constant, evaluate the assignment and return the constant.

	* g++.dg/cpp1y/constexpr-50060.C: New test.

--- gcc/cp/constexpr.c.jj	2016-07-11 22:18:01.000000000 +0200
+++ gcc/cp/constexpr.c	2016-07-15 15:27:50.820085561 +0200
@@ -1078,8 +1078,7 @@ get_nth_callarg (tree t, int n)
 
 static tree
 cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
-				bool lval,
-				bool *non_constant_p, bool *overflow_p)
+				bool, bool *non_constant_p, bool *overflow_p)
 {
   const int nargs = call_expr_nargs (t);
   tree *args = (tree *) alloca (nargs * sizeof (tree));
@@ -1105,7 +1104,7 @@ cxx_eval_builtin_function_call (const co
   for (i = 0; i < nargs; ++i)
     {
       args[i] = cxx_eval_constant_expression (&new_ctx, CALL_EXPR_ARG (t, i),
-					      lval, &dummy1, &dummy2);
+					      false, &dummy1, &dummy2);
       if (bi_const_p)
 	/* For __built_in_constant_p, fold all expressions with constant values
 	   even if they aren't C++ constant-expressions.  */
@@ -1119,6 +1118,27 @@ cxx_eval_builtin_function_call (const co
   /* Fold away the NOP_EXPR from fold_builtin_n.  */
   new_call = fold (new_call);
   force_folding_builtin_constant_p = save_ffbcp;
+
+  if (cxx_dialect >= cxx14)
+    {
+      tree r = new_call;
+      if (TREE_CODE (r) == NON_LVALUE_EXPR)
+	r = TREE_OPERAND (r, 0);
+      if (TREE_CODE (r) == COMPOUND_EXPR
+	  && TREE_CODE (TREE_OPERAND (r, 0)) == MODIFY_EXPR
+	  && reduced_constant_expression_p (TREE_OPERAND (TREE_OPERAND (r, 0),
+							  1)))
+	{
+	  /* The frexp, modf, remquo and lgamma_r builtins (and their variants)
+	     with &var as last argument are folded into
+	     (var = const1), const2, sometimes wrapped into
+	     NON_LVALUE_EXPR.  */
+	  cxx_eval_constant_expression (&new_ctx, TREE_OPERAND (r, 0),
+					false, non_constant_p, overflow_p);
+	  new_call = TREE_OPERAND (r, 1);
+	}
+    }
+
   VERIFY_CONSTANT (new_call);
   return new_call;
 }
--- gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C.jj	2016-07-15 15:34:12.469124944 +0200
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C	2016-07-15 15:59:36.285303078 +0200
@@ -0,0 +1,100 @@
+// PR c++/50060
+// { dg-do compile { target c++14 } }
+
+// sincos and lgamma_r aren't available in -std=c++14,
+// only in -std=gnu++14.  Use __builtin_* in that case.
+extern "C" void sincos (double, double *, double *);
+extern "C" double frexp (double, int *);
+extern "C" double modf (double, double *);
+extern "C" double remquo (double, double, int *);
+extern "C" double lgamma_r (double, int *);
+
+constexpr double
+f0 (double x)
+{
+  double y {};
+  double z {};
+  __builtin_sincos (x, &y, &z);
+  return y;
+}
+
+constexpr double
+f1 (double x)
+{
+  double y {};
+  double z {};
+  __builtin_sincos (x, &y, &z);
+  return z;
+}
+
+constexpr double
+f2 (double x)
+{
+  int y {};
+  return frexp (x, &y);
+}
+
+constexpr int
+f3 (double x)
+{
+  int y {};
+  frexp (x, &y);
+  return y;
+}
+
+constexpr double
+f4 (double x)
+{
+  double y {};
+  return modf (x, &y);
+}
+
+constexpr double
+f5 (double x)
+{
+  double y {};
+  modf (x, &y);
+  return y;
+}
+
+constexpr double
+f6 (double x, double y)
+{
+  int z {};
+  return remquo (x, y, &z);
+}
+
+constexpr int
+f7 (double x, double y)
+{
+  int z {};
+  remquo (x, y, &z);
+  return z;
+}
+
+constexpr double
+f8 (double x)
+{
+  int y {};
+  return __builtin_lgamma_r (x, &y);
+}
+
+constexpr int
+f9 (double x)
+{
+  int y {};
+  __builtin_lgamma_r (x, &y);
+  return y;
+}
+
+static_assert (f0 (0.0) == 0.0, "");
+static_assert (f1 (0.0) == 1.0, "");
+static_assert (f2 (6.5) == 0.8125, "");
+static_assert (f3 (6.5) == 3, "");
+static_assert (f4 (-7.25) == -0.25, "");
+static_assert (f5 (-7.25) == -7.0, "");
+static_assert (f6 (3.0, 2.0) == -1.0, "");
+static_assert (f7 (3.0, 2.0) == 2, "");
+static_assert (f8 (0.75) >= 0.20 && f8 (0.75) <= 0.21, "");
+static_assert (f8 (0.75) >= 0.20 && f8 (0.75) <= 0.21, "");
+static_assert (f9 (0.75) == 1, "");

	Jakub



More information about the Gcc-patches mailing list