public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ PATCH] Allow frexp etc. builtins in c++14 constexpr (PR c++/50060)
@ 2016-07-15 18:42 Jakub Jelinek
  2016-07-18 17:16 ` Jason Merrill
  0 siblings, 1 reply; 8+ messages in thread
From: Jakub Jelinek @ 2016-07-15 18:42 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

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

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [C++ PATCH] Allow frexp etc. builtins in c++14 constexpr (PR c++/50060)
  2016-07-15 18:42 [C++ PATCH] Allow frexp etc. builtins in c++14 constexpr (PR c++/50060) Jakub Jelinek
@ 2016-07-18 17:16 ` Jason Merrill
  2016-07-18 18:03   ` Jakub Jelinek
  0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2016-07-18 17:16 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches List

On Fri, Jul 15, 2016 at 2:42 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> 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.

Yes.

> 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.

Why so specific?  Can't we just pass the return value from fold into
cxx_eval_constant_expression, if it isn't still a CALL_EXPR?

Incidentally, I think we should be using fold_builtin_call_array
rather than fold_build_call_array_loc.

> 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 evaluated as rvalues (and for non-builtins they are).

I'm a bit nervous about this, since some builtins take arguments by
magic rather than by value, but I'm willing to accept this and see
what breaks.

Jason

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [C++ PATCH] Allow frexp etc. builtins in c++14 constexpr (PR c++/50060)
  2016-07-18 17:16 ` Jason Merrill
@ 2016-07-18 18:03   ` Jakub Jelinek
  2016-07-18 18:08     ` Jason Merrill
  0 siblings, 1 reply; 8+ messages in thread
From: Jakub Jelinek @ 2016-07-18 18:03 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches List

On Mon, Jul 18, 2016 at 01:16:26PM -0400, Jason Merrill wrote:
> On Fri, Jul 15, 2016 at 2:42 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> > 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.
> 
> Yes.
> 
> > 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.
> 
> Why so specific?  Can't we just pass the return value from fold into
> cxx_eval_constant_expression, if it isn't still a CALL_EXPR?

I'll test it.

> Incidentally, I think we should be using fold_builtin_call_array
> rather than fold_build_call_array_loc.

That is reasonable, but not 100% sure what to do if it returns NULL
- it should return t, but if I do VERIFY_CONSTANT (t); there or
manually
    if (!*non_constant_p)
      {
	if (!allow_non_constant)
	  error ("%q+E is not a constant expression", t);
	*non_constant_p = true;
      }
    return t;
it will print the original expression (without folded arguments).
Another option would be to build_call_array_loc if we want to emit
the error.  Preferences?

> > 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 evaluated as rvalues (and for non-builtins they are).
> 
> I'm a bit nervous about this, since some builtins take arguments by
> magic rather than by value, but I'm willing to accept this and see
> what breaks.

If some builtin is special, wouldn't it be special regardless of whether
we want to take address of the builtin's return value or not?
I'm really not aware of any though, after all, gimplification will turn
all their arguments into rvalues anyway.

The following patch uses VERIFY_CONSTANT (t) for the above mentioned issue,
and passes make check-g++ RUNTESTFLAGS=dg.exp=*constexpr*, is that what you
want or something different?

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

	PR c++/50060
	* constexpr.c (cxx_eval_builtin_function_call): Pass false as lval
	when evaluating call arguments.  Use fold_builtin_call_array instead
	of fold_build_call_array_loc, return t if it returns NULL.
	For C++14 and later, pass new_call to if new_call
	cxx_eval_constant_expression.

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

--- gcc/cp/constexpr.c.jj	2016-07-16 10:41:04.525652516 +0200
+++ gcc/cp/constexpr.c	2016-07-18 19:53:45.059291912 +0200
@@ -1105,7 +1105,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.  */
@@ -1114,11 +1114,23 @@ cxx_eval_builtin_function_call (const co
 
   bool save_ffbcp = force_folding_builtin_constant_p;
   force_folding_builtin_constant_p = true;
-  new_call = fold_build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
-					CALL_EXPR_FN (t), nargs, args);
+  new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t),
+				      CALL_EXPR_FN (t), nargs, args);
+  if (new_call == NULL)
+    {
+      VERIFY_CONSTANT (t);
+      return t;
+    }
+
   /* Fold away the NOP_EXPR from fold_builtin_n.  */
   new_call = fold (new_call);
   force_folding_builtin_constant_p = save_ffbcp;
+
+  /* Folding some math builtins produces e.g. COMPOUND_EXPR etc.  */
+  if (cxx_dialect >= cxx14)
+    return cxx_eval_constant_expression (&new_ctx, new_call, lval,
+					 non_constant_p, overflow_p);
+
   VERIFY_CONSTANT (new_call);
   return new_call;
 }
--- gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C.jj	2016-07-18 19:45:30.528496123 +0200
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C	2016-07-18 19:45:30.528496123 +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

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [C++ PATCH] Allow frexp etc. builtins in c++14 constexpr (PR c++/50060)
  2016-07-18 18:03   ` Jakub Jelinek
@ 2016-07-18 18:08     ` Jason Merrill
  2016-07-18 18:33       ` Jakub Jelinek
  0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2016-07-18 18:08 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches List

On Mon, Jul 18, 2016 at 2:03 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Mon, Jul 18, 2016 at 01:16:26PM -0400, Jason Merrill wrote:
> That is reasonable, but not 100% sure what to do if it returns NULL
> - it should return t, but if I do VERIFY_CONSTANT (t); there or
> manually
>     if (!*non_constant_p)
>       {
>         if (!allow_non_constant)
>           error ("%q+E is not a constant expression", t);
>         *non_constant_p = true;
>       }
>     return t;
> it will print the original expression (without folded arguments).
> Another option would be to build_call_array_loc if we want to emit
> the error.  Preferences?

Hmm, I guess let's build the call for the error.

>    /* Fold away the NOP_EXPR from fold_builtin_n.  */
>    new_call = fold (new_call);
>    force_folding_builtin_constant_p = save_ffbcp;
> +
> +  /* Folding some math builtins produces e.g. COMPOUND_EXPR etc.  */
> +  if (cxx_dialect >= cxx14)
> +    return cxx_eval_constant_expression (&new_ctx, new_call, lval,
> +                                        non_constant_p, overflow_p);

If we do this unconditionally, can we drop the fold above?

Jason

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [C++ PATCH] Allow frexp etc. builtins in c++14 constexpr (PR c++/50060)
  2016-07-18 18:08     ` Jason Merrill
@ 2016-07-18 18:33       ` Jakub Jelinek
  2016-07-18 18:43         ` Jason Merrill
  0 siblings, 1 reply; 8+ messages in thread
From: Jakub Jelinek @ 2016-07-18 18:33 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches List

On Mon, Jul 18, 2016 at 02:07:50PM -0400, Jason Merrill wrote:
> On Mon, Jul 18, 2016 at 2:03 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> > On Mon, Jul 18, 2016 at 01:16:26PM -0400, Jason Merrill wrote:
> > That is reasonable, but not 100% sure what to do if it returns NULL
> > - it should return t, but if I do VERIFY_CONSTANT (t); there or
> > manually
> >     if (!*non_constant_p)
> >       {
> >         if (!allow_non_constant)
> >           error ("%q+E is not a constant expression", t);
> >         *non_constant_p = true;
> >       }
> >     return t;
> > it will print the original expression (without folded arguments).
> > Another option would be to build_call_array_loc if we want to emit
> > the error.  Preferences?
> 
> Hmm, I guess let's build the call for the error.

Ok.

> >    /* Fold away the NOP_EXPR from fold_builtin_n.  */
> >    new_call = fold (new_call);
> >    force_folding_builtin_constant_p = save_ffbcp;
> > +
> > +  /* Folding some math builtins produces e.g. COMPOUND_EXPR etc.  */
> > +  if (cxx_dialect >= cxx14)
> > +    return cxx_eval_constant_expression (&new_ctx, new_call, lval,
> > +                                        non_constant_p, overflow_p);
> 
> If we do this unconditionally, can we drop the fold above?

So I've tried following patch, but on
extern "C" double frexp (double, int *);

struct S
{
#ifdef FREXP
  constexpr S (double a) : y {}, x (frexp (a, &y)) {}
#else
  constexpr S (double a) : y {}, x ((y = 1, 0.8125)) {}
#endif
  double x;
  int y;
};

static_assert (S (6.5).x == 0.8125, "");

it means the testcase is accepted with -DFREXP in both
-std=gnu++11 and -std=gnu++14 modes and without -DFREXP in
-std=gnu++14 mode only.  I can move over the fold call
to the cxx11 block, but I think we need to reject it for C++11.

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

	PR c++/50060
	* constexpr.c (cxx_eval_builtin_function_call): Pass false as lval
	when evaluating call arguments.  Use fold_builtin_call_array instead
	of fold_build_call_array_loc, return t if it returns NULL.
	For C++14 and later, pass new_call to if new_call
	cxx_eval_constant_expression.

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

--- gcc/cp/constexpr.c.jj	2016-07-16 10:41:04.525652516 +0200
+++ gcc/cp/constexpr.c	2016-07-18 20:18:08.035709874 +0200
@@ -1105,7 +1105,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.  */
@@ -1114,13 +1114,23 @@ cxx_eval_builtin_function_call (const co
 
   bool save_ffbcp = force_folding_builtin_constant_p;
   force_folding_builtin_constant_p = true;
-  new_call = fold_build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
-					CALL_EXPR_FN (t), nargs, args);
-  /* Fold away the NOP_EXPR from fold_builtin_n.  */
-  new_call = fold (new_call);
+  new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t),
+				      CALL_EXPR_FN (t), nargs, args);
   force_folding_builtin_constant_p = save_ffbcp;
-  VERIFY_CONSTANT (new_call);
-  return new_call;
+  if (new_call == NULL)
+    {
+      if (!*non_constant_p && !ctx->quiet)
+	{
+	  new_call = build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
+					   CALL_EXPR_FN (t), nargs, args);
+	  error ("%q+E is not a constant expression", new_call);
+	}
+      *non_constant_p = true;
+      return t;
+    }
+
+  return cxx_eval_constant_expression (&new_ctx, new_call, lval,
+				       non_constant_p, overflow_p);
 }
 
 /* TEMP is the constant value of a temporary object of type TYPE.  Adjust
--- gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C.jj	2016-07-18 19:45:30.528496123 +0200
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C	2016-07-18 19:45:30.528496123 +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

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [C++ PATCH] Allow frexp etc. builtins in c++14 constexpr (PR c++/50060)
  2016-07-18 18:33       ` Jakub Jelinek
@ 2016-07-18 18:43         ` Jason Merrill
  2016-07-18 21:07           ` Jakub Jelinek
  0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2016-07-18 18:43 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches List

On Mon, Jul 18, 2016 at 2:33 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Mon, Jul 18, 2016 at 02:07:50PM -0400, Jason Merrill wrote:
>> >    /* Fold away the NOP_EXPR from fold_builtin_n.  */
>> >    new_call = fold (new_call);
>> >    force_folding_builtin_constant_p = save_ffbcp;
>> > +
>> > +  /* Folding some math builtins produces e.g. COMPOUND_EXPR etc.  */
>> > +  if (cxx_dialect >= cxx14)
>> > +    return cxx_eval_constant_expression (&new_ctx, new_call, lval,
>> > +                                        non_constant_p, overflow_p);
>>
>> If we do this unconditionally, can we drop the fold above?
>
> So I've tried following patch, but on
> extern "C" double frexp (double, int *);
>
> struct S
> {
> #ifdef FREXP
>   constexpr S (double a) : y {}, x (frexp (a, &y)) {}
> #else
>   constexpr S (double a) : y {}, x ((y = 1, 0.8125)) {}
> #endif
>   double x;
>   int y;
> };
>
> static_assert (S (6.5).x == 0.8125, "");
>
> it means the testcase is accepted with -DFREXP in both
> -std=gnu++11 and -std=gnu++14 modes and without -DFREXP in
> -std=gnu++14 mode only.  I can move over the fold call
> to the cxx11 block, but I think we need to reject it for C++11.

Ah, I guess we need to check cxx_dialect in cxx_eval_store_expression,
not just in potential_constant_expression.

Jason

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [C++ PATCH] Allow frexp etc. builtins in c++14 constexpr (PR c++/50060)
  2016-07-18 18:43         ` Jason Merrill
@ 2016-07-18 21:07           ` Jakub Jelinek
  2016-07-20 13:40             ` Jason Merrill
  0 siblings, 1 reply; 8+ messages in thread
From: Jakub Jelinek @ 2016-07-18 21:07 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches List

On Mon, Jul 18, 2016 at 02:42:43PM -0400, Jason Merrill wrote:
> Ah, I guess we need to check cxx_dialect in cxx_eval_store_expression,
> not just in potential_constant_expression.

Here is an updated version, bootstrapped/regtested on x86_64-linux and
i686-linux, ok for trunk?

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

	PR c++/50060
	* constexpr.c (cxx_eval_builtin_function_call): Pass false as lval
	when evaluating call arguments.  Use fold_builtin_call_array instead
	of fold_build_call_array_loc, return t if it returns NULL.  Otherwise
	check the result with potential_constant_expression and call
	cxx_eval_constant_expression on it.

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

--- gcc/cp/constexpr.c.jj	2016-07-18 20:42:51.163955883 +0200
+++ gcc/cp/constexpr.c	2016-07-18 20:55:47.246152938 +0200
@@ -1105,7 +1105,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.  */
@@ -1114,13 +1114,31 @@ cxx_eval_builtin_function_call (const co
 
   bool save_ffbcp = force_folding_builtin_constant_p;
   force_folding_builtin_constant_p = true;
-  new_call = fold_build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
-					CALL_EXPR_FN (t), nargs, args);
-  /* Fold away the NOP_EXPR from fold_builtin_n.  */
-  new_call = fold (new_call);
+  new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t),
+				      CALL_EXPR_FN (t), nargs, args);
   force_folding_builtin_constant_p = save_ffbcp;
-  VERIFY_CONSTANT (new_call);
-  return new_call;
+  if (new_call == NULL)
+    {
+      if (!*non_constant_p && !ctx->quiet)
+	{
+	  new_call = build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
+					   CALL_EXPR_FN (t), nargs, args);
+	  error ("%q+E is not a constant expression", new_call);
+	}
+      *non_constant_p = true;
+      return t;
+    }
+
+  if (!potential_constant_expression (new_call))
+    {
+      if (!*non_constant_p && !ctx->quiet)
+	error ("%q+E is not a constant expression", new_call);
+      *non_constant_p = true;
+      return t;
+    }
+
+  return cxx_eval_constant_expression (&new_ctx, new_call, lval,
+				       non_constant_p, overflow_p);
 }
 
 /* TEMP is the constant value of a temporary object of type TYPE.  Adjust
--- gcc/testsuite/g++.dg/cpp0x/constexpr-50060.C.jj	2016-07-18 21:03:12.505532831 +0200
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-50060.C	2016-07-18 21:05:41.306655422 +0200
@@ -0,0 +1,21 @@
+// PR c++/50060
+// { dg-do compile { target c++11 } }
+
+extern "C" double frexp (double, int *);
+
+struct S
+{
+  constexpr S (double a) : y {}, x (frexp (a, &y)) {}	// { dg-error "is not a constant expression" "S" { target { ! c++14 } } }
+  double x;
+  int y;
+};
+
+struct T
+{
+  constexpr T (double a) : y {}, x ((y = 1, 0.8125)) {}	// { dg-error "is not a constant-expression" "T" { target { ! c++14 } } }
+  double x;
+  int y;
+};
+
+static_assert (S (6.5).x == 0.8125, "");	// { dg-error "non-constant condition for static assertion|in constexpr expansion" "" { target { ! c++14 } } }
+static_assert (T (6.5).x == 0.8125, "");	// { dg-error "non-constant condition for static assertion|called in a constant expression" "" { target { ! c++14 } } }
--- gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C.jj	2016-07-18 20:46:00.992553765 +0200
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C	2016-07-18 20:46:00.992553765 +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

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [C++ PATCH] Allow frexp etc. builtins in c++14 constexpr (PR c++/50060)
  2016-07-18 21:07           ` Jakub Jelinek
@ 2016-07-20 13:40             ` Jason Merrill
  0 siblings, 0 replies; 8+ messages in thread
From: Jason Merrill @ 2016-07-20 13:40 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches List

OK.

On Mon, Jul 18, 2016 at 5:07 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Mon, Jul 18, 2016 at 02:42:43PM -0400, Jason Merrill wrote:
>> Ah, I guess we need to check cxx_dialect in cxx_eval_store_expression,
>> not just in potential_constant_expression.
>
> Here is an updated version, bootstrapped/regtested on x86_64-linux and
> i686-linux, ok for trunk?
>
> 2016-07-18  Jakub Jelinek  <jakub@redhat.com>
>
>         PR c++/50060
>         * constexpr.c (cxx_eval_builtin_function_call): Pass false as lval
>         when evaluating call arguments.  Use fold_builtin_call_array instead
>         of fold_build_call_array_loc, return t if it returns NULL.  Otherwise
>         check the result with potential_constant_expression and call
>         cxx_eval_constant_expression on it.
>
>         * g++.dg/cpp0x/constexpr-50060.C: New test.
>         * g++.dg/cpp1y/constexpr-50060.C: New test.
>
> --- gcc/cp/constexpr.c.jj       2016-07-18 20:42:51.163955883 +0200
> +++ gcc/cp/constexpr.c  2016-07-18 20:55:47.246152938 +0200
> @@ -1105,7 +1105,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.  */
> @@ -1114,13 +1114,31 @@ cxx_eval_builtin_function_call (const co
>
>    bool save_ffbcp = force_folding_builtin_constant_p;
>    force_folding_builtin_constant_p = true;
> -  new_call = fold_build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
> -                                       CALL_EXPR_FN (t), nargs, args);
> -  /* Fold away the NOP_EXPR from fold_builtin_n.  */
> -  new_call = fold (new_call);
> +  new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t),
> +                                     CALL_EXPR_FN (t), nargs, args);
>    force_folding_builtin_constant_p = save_ffbcp;
> -  VERIFY_CONSTANT (new_call);
> -  return new_call;
> +  if (new_call == NULL)
> +    {
> +      if (!*non_constant_p && !ctx->quiet)
> +       {
> +         new_call = build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
> +                                          CALL_EXPR_FN (t), nargs, args);
> +         error ("%q+E is not a constant expression", new_call);
> +       }
> +      *non_constant_p = true;
> +      return t;
> +    }
> +
> +  if (!potential_constant_expression (new_call))
> +    {
> +      if (!*non_constant_p && !ctx->quiet)
> +       error ("%q+E is not a constant expression", new_call);
> +      *non_constant_p = true;
> +      return t;
> +    }
> +
> +  return cxx_eval_constant_expression (&new_ctx, new_call, lval,
> +                                      non_constant_p, overflow_p);
>  }
>
>  /* TEMP is the constant value of a temporary object of type TYPE.  Adjust
> --- gcc/testsuite/g++.dg/cpp0x/constexpr-50060.C.jj     2016-07-18 21:03:12.505532831 +0200
> +++ gcc/testsuite/g++.dg/cpp0x/constexpr-50060.C        2016-07-18 21:05:41.306655422 +0200
> @@ -0,0 +1,21 @@
> +// PR c++/50060
> +// { dg-do compile { target c++11 } }
> +
> +extern "C" double frexp (double, int *);
> +
> +struct S
> +{
> +  constexpr S (double a) : y {}, x (frexp (a, &y)) {}  // { dg-error "is not a constant expression" "S" { target { ! c++14 } } }
> +  double x;
> +  int y;
> +};
> +
> +struct T
> +{
> +  constexpr T (double a) : y {}, x ((y = 1, 0.8125)) {}        // { dg-error "is not a constant-expression" "T" { target { ! c++14 } } }
> +  double x;
> +  int y;
> +};
> +
> +static_assert (S (6.5).x == 0.8125, "");       // { dg-error "non-constant condition for static assertion|in constexpr expansion" "" { target { ! c++14 } } }
> +static_assert (T (6.5).x == 0.8125, "");       // { dg-error "non-constant condition for static assertion|called in a constant expression" "" { target { ! c++14 } } }
> --- gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C.jj     2016-07-18 20:46:00.992553765 +0200
> +++ gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C        2016-07-18 20:46:00.992553765 +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

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-07-20 13:40 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-15 18:42 [C++ PATCH] Allow frexp etc. builtins in c++14 constexpr (PR c++/50060) Jakub Jelinek
2016-07-18 17:16 ` Jason Merrill
2016-07-18 18:03   ` Jakub Jelinek
2016-07-18 18:08     ` Jason Merrill
2016-07-18 18:33       ` Jakub Jelinek
2016-07-18 18:43         ` Jason Merrill
2016-07-18 21:07           ` Jakub Jelinek
2016-07-20 13:40             ` Jason Merrill

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).