re PR c++/86524 (std::less with pointer arguments not usable in static_assert in...
authorJakub Jelinek <jakub@redhat.com>
Fri, 21 Dec 2018 19:58:36 +0000 (20:58 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 21 Dec 2018 19:58:36 +0000 (20:58 +0100)
PR c++/86524
PR c++/88446
* cp-tree.h (cp_fold_maybe_rvalue, cp_fold_rvalue): Declare.
(fold_non_dependent_expr): Add manifestly_const_eval argument.
* constexpr.c (cxx_eval_builtin_function_call): Evaluate
__builtin_constant_p if ctx->manifestly_const_eval even in constexpr
functions.  Don't reuse dummy{1,2} vars between different arguments.
Use cp_fold_rvalue instead of cp_fully_fold.  Fix comment typo.
(fold_non_dependent_expr): Add manifestly_const_eval argument, pass
it through to cxx_eval_outermost_constant_expr and
maybe_constant_value.
* cp-gimplify.c (cp_fold_maybe_rvalue, cp_fold_rvalue): No longer
static.
* semantics.c (finish_static_assert): Call fold_non_dependent_expr
with true as manifestly_const_eval.

* g++.dg/cpp1y/constexpr-86524.C: New test.
* g++.dg/cpp2a/is-constant-evaluated4.C: New test.
* g++.dg/cpp2a/is-constant-evaluated5.C: New test.
* g++.dg/cpp2a/is-constant-evaluated6.C: New test.

From-SVN: r267341

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/cp-gimplify.c
gcc/cp/cp-tree.h
gcc/cp/semantics.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C [new file with mode: 0644]

index f4295f33d5eb647667ebae97f2956eea63e0f640..2201a472d53e40ed32f25a3c5f13820ebb769e67 100644 (file)
@@ -1,3 +1,21 @@
+2018-12-21  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/86524
+       PR c++/88446
+       * cp-tree.h (cp_fold_maybe_rvalue, cp_fold_rvalue): Declare.
+       (fold_non_dependent_expr): Add manifestly_const_eval argument.
+       * constexpr.c (cxx_eval_builtin_function_call): Evaluate
+       __builtin_constant_p if ctx->manifestly_const_eval even in constexpr
+       functions.  Don't reuse dummy{1,2} vars between different arguments.
+       Use cp_fold_rvalue instead of cp_fully_fold.  Fix comment typo.
+       (fold_non_dependent_expr): Add manifestly_const_eval argument, pass
+       it through to cxx_eval_outermost_constant_expr and
+       maybe_constant_value.
+       * cp-gimplify.c (cp_fold_maybe_rvalue, cp_fold_rvalue): No longer
+       static.
+       * semantics.c (finish_static_assert): Call fold_non_dependent_expr
+       with true as manifestly_const_eval.
+
 2018-12-20  Marek Polacek  <polacek@redhat.com>
 
        PR c++/88196 - ICE with class non-type template parameter.
index 15a30fdcdd0de0bad7c13586068bea3c69f6761a..cea414d33defb514b071caa9e8c1031be75b10e4 100644 (file)
@@ -1197,7 +1197,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
   /* If we aren't requiring a constant expression, defer __builtin_constant_p
      in a constexpr function until we have values for the parameters.  */
   if (bi_const_p
-      && ctx->quiet
+      && !ctx->manifestly_const_eval
       && current_function_decl
       && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
     {
@@ -1222,7 +1222,6 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
      return constant false for a non-constant argument.  */
   constexpr_ctx new_ctx = *ctx;
   new_ctx.quiet = true;
-  bool dummy1 = false, dummy2 = false;
   for (i = 0; i < nargs; ++i)
     {
       args[i] = CALL_EXPR_ARG (t, i);
@@ -1231,12 +1230,16 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
         of the builtin, verify it here.  */
       if (!builtin_valid_in_constant_expr_p (fun)
          || potential_constant_expression (args[i]))
-       args[i] = cxx_eval_constant_expression (&new_ctx, args[i], false,
-                                               &dummy1, &dummy2);
+       {
+         bool dummy1 = false, dummy2 = false;
+         args[i] = cxx_eval_constant_expression (&new_ctx, args[i], false,
+                                                 &dummy1, &dummy2);
+       }
+
       if (bi_const_p)
-       /* For __built_in_constant_p, fold all expressions with constant values
+       /* For __builtin_constant_p, fold all expressions with constant values
           even if they aren't C++ constant-expressions.  */
-       args[i] = cp_fully_fold (args[i]);
+       args[i] = cp_fold_rvalue (args[i]);
     }
 
   bool save_ffbcp = force_folding_builtin_constant_p;
@@ -5340,6 +5343,7 @@ clear_cv_and_fold_caches (void)
    (t, complain) followed by maybe_constant_value but is more efficient,
    because it calls instantiation_dependent_expression_p and
    potential_constant_expression at most once.
+   The manifestly_const_eval argument is passed to maybe_constant_value.
 
    Callers should generally pass their active complain, or if they are in a
    non-template, diagnosing context, they can use the default of
@@ -5350,7 +5354,8 @@ clear_cv_and_fold_caches (void)
 
 tree
 fold_non_dependent_expr (tree t,
-                        tsubst_flags_t complain /* = tf_warning_or_error */)
+                        tsubst_flags_t complain /* = tf_warning_or_error */,
+                        bool manifestly_const_eval /* = false */)
 {
   if (t == NULL_TREE)
     return NULL_TREE;
@@ -5380,7 +5385,8 @@ fold_non_dependent_expr (tree t,
              return t;
            }
 
-         tree r = cxx_eval_outermost_constant_expr (t, true, true, false,
+         tree r = cxx_eval_outermost_constant_expr (t, true, true,
+                                                    manifestly_const_eval,
                                                     NULL_TREE);
          /* cp_tree_equal looks through NOPs, so allow them.  */
          gcc_checking_assert (r == t
@@ -5398,7 +5404,7 @@ fold_non_dependent_expr (tree t,
       return t;
     }
 
-  return maybe_constant_value (t);
+  return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
 }
 
 /* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather
index 9d848eaaef093e4799b170a20cdcd857e77a5463..76bd8f6dcb74ea331fed797b7099564e1df13f06 100644 (file)
@@ -2118,7 +2118,7 @@ cxx_omp_disregard_value_expr (tree decl, bool shared)
 
 /* Fold expression X which is used as an rvalue if RVAL is true.  */
 
-static tree
+tree
 cp_fold_maybe_rvalue (tree x, bool rval)
 {
   while (true)
@@ -2141,7 +2141,7 @@ cp_fold_maybe_rvalue (tree x, bool rval)
 
 /* Fold expression X which is used as an rvalue.  */
 
-static tree
+tree
 cp_fold_rvalue (tree x)
 {
   return cp_fold_maybe_rvalue (x, true);
index f6b7c6e516b31e18c1a98c2909987d5774b2c30b..604e615721f7c02c42b3159304f0233d9ab9ddc3 100644 (file)
@@ -7543,6 +7543,8 @@ extern void cxx_omp_finish_clause         (tree, gimple_seq *);
 extern bool cxx_omp_privatize_by_reference     (const_tree);
 extern bool cxx_omp_disregard_value_expr       (tree, bool);
 extern void cp_fold_function                   (tree);
+extern tree cp_fold_maybe_rvalue               (tree, bool);
+extern tree cp_fold_rvalue                     (tree);
 extern tree cp_fully_fold                      (tree);
 extern tree cp_fully_fold_init                 (tree);
 extern void clear_fold_cache                   (void);
@@ -7668,7 +7670,9 @@ extern tree cxx_constant_value                    (tree, tree = NULL_TREE);
 extern tree cxx_constant_init                  (tree, tree = NULL_TREE);
 extern tree maybe_constant_value               (tree, tree = NULL_TREE, bool = false);
 extern tree maybe_constant_init                        (tree, tree = NULL_TREE, bool = false);
-extern tree fold_non_dependent_expr            (tree, tsubst_flags_t = tf_warning_or_error);
+extern tree fold_non_dependent_expr            (tree,
+                                                tsubst_flags_t = tf_warning_or_error,
+                                                bool = false);
 extern tree fold_simple                                (tree);
 extern bool is_sub_constant_expr                (tree);
 extern bool reduced_constant_expression_p       (tree);
index 0865076493d5c9f478de1cc28e5ad51584b0aa69..e201c3db9a2cb3301d6e870e75d7f5814c16f33b 100644 (file)
@@ -9225,7 +9225,8 @@ finish_static_assert (tree condition, tree message, location_t location,
   /* Fold the expression and convert it to a boolean value. */
   condition = perform_implicit_conversion_flags (boolean_type_node, condition,
                                                 complain, LOOKUP_NORMAL);
-  condition = fold_non_dependent_expr (condition, complain);
+  condition = fold_non_dependent_expr (condition, complain,
+                                      /*manifestly_const_eval=*/true);
 
   if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition))
     /* Do nothing; the condition is satisfied. */
index e5928ecec61d14f6ad2002b1f37406da369b7d34..eaabddfff23be4cdb9276aecec5b39d12b3209ce 100644 (file)
@@ -1,5 +1,12 @@
 2018-12-21  Jakub Jelinek  <jakub@redhat.com>
 
+       PR c++/86524
+       PR c++/88446
+       * g++.dg/cpp1y/constexpr-86524.C: New test.
+       * g++.dg/cpp2a/is-constant-evaluated4.C: New test.
+       * g++.dg/cpp2a/is-constant-evaluated5.C: New test.
+       * g++.dg/cpp2a/is-constant-evaluated6.C: New test.
+
        PR middle-end/85594
        PR middle-end/88553
        * gcc.dg/gomp/pr85594.c: New test.
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C
new file mode 100644 (file)
index 0000000..59e6b80
--- /dev/null
@@ -0,0 +1,41 @@
+// PR c++/86524
+// { dg-do run { target c++14 } }
+// { dg-options "-O2" }
+
+extern "C" void abort ();
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+constexpr bool
+foo (const int *x, const int *y)
+{
+  if (__builtin_constant_p (x < y))
+    return x < y;
+  return (uintptr_t) x < (uintptr_t) y;
+}
+
+void
+bar ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+constexpr void
+baz ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+int i, j;
+
+int
+main ()
+{
+  bar ();
+  baz ();
+  if (!(foo (&i, &j) ^ foo (&j, &i)))
+    abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C
new file mode 100644 (file)
index 0000000..809e3d2
--- /dev/null
@@ -0,0 +1,19 @@
+// P0595R2
+// { dg-do compile { target c++14 } }
+
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+constexpr int
+foo () noexcept
+{
+  return std::is_constant_evaluated () ? 5 : 12;
+}
+
+static_assert (std::is_constant_evaluated (), "");
+static_assert (foo () == 5, "");
diff --git a/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C
new file mode 100644 (file)
index 0000000..22b762d
--- /dev/null
@@ -0,0 +1,41 @@
+// PR c++/86524
+// { dg-do run { target c++14 } }
+// { dg-options "-O2" }
+
+extern "C" void abort ();
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+constexpr bool
+foo (const int *x, const int *y)
+{
+  if (__builtin_is_constant_evaluated ())
+    return x < y;
+  return (uintptr_t) x < (uintptr_t) y;
+}
+
+void
+bar ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+constexpr void
+baz ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+int i, j;
+
+int
+main ()
+{
+  bar ();
+  baz ();
+  if (!(foo (&i, &j) ^ foo (&j, &i)))
+    abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C
new file mode 100644 (file)
index 0000000..842e446
--- /dev/null
@@ -0,0 +1,29 @@
+// P0595R2
+// { dg-do compile { target c++14 } }
+
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+int a;
+
+constexpr bool
+foo (int x)
+{
+  return __builtin_constant_p (x);
+}
+
+constexpr bool
+bar (int x)
+{
+  return __builtin_constant_p (x + a);
+}
+
+static_assert (__builtin_constant_p (0) + 2 * std::is_constant_evaluated () == 3, "");
+static_assert (__builtin_constant_p (a) + 2 * std::is_constant_evaluated () == 2, "");
+static_assert (foo (0) + 2 * std::is_constant_evaluated () == 3, "");
+static_assert (bar (0) + 2 * std::is_constant_evaluated () == 2, "");