On 9/1/23 13:23, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --

In the review of P2564:
<https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628747.html>
it turned out that in order to correctly handle an example in the paper,
we should stop doing immediate evaluation in build_over_call and
bot_replace, and instead do it in cp_fold_r.  This patch does that.

Another benefit is that this is a pretty significant simplification, at
least in my opinion.  Also, this fixes the c++/110997 ICE (but the test
doesn't compile yet).

The main drawback seems to be that cp_fold_r doesn't process as much
code as we did before: uninstantiated templates

That's acceptable, it's an optional diagnostic.

and things like "false ? foo () : 1".

This is a problem. Maybe we want cp_fold_r to recurse into the arms of a COND_EXPR before folding them away? Maybe only if we know we've seen an immediate function?

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 8bd5c4a47f8..af4f98b1fe1 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3135,6 +3135,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree 
t,
          unsigned save_heap_alloc_count = ctx->global->heap_vars.length ();
          unsigned save_heap_dealloc_count = ctx->global->heap_dealloc_count;
+ /* Make sure we fold std::is_constant_evaluated to true in an
+            immediate function.  */
+         if (immediate_invocation_p (fun))

I think this should just check DECL_IMMEDIATE_FUNCTION_P, the context doesn't matter.

+           call_ctx.manifestly_const_eval = mce_true;
+
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 206e791fcfd..29132aad158 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -1058,9 +1058,21 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
        }
        break;
+ /* Expand immediate invocations. */
+    case CALL_EXPR:
+    case AGGR_INIT_EXPR:
+      if (!in_immediate_context ())

As you mentioned in your followup, we shouldn't need to check this because we don't call cp_fold_r in immediate context.

+       if (tree fn = cp_get_callee (stmt))
+         if (TREE_CODE (fn) != ADDR_EXPR || ADDR_EXPR_DENOTES_CALL_P (fn))
+           if (tree fndecl = cp_get_fndecl_from_callee (fn, /*fold*/false))
+             if (DECL_IMMEDIATE_FUNCTION_P (fndecl))
+               *stmt_p = stmt = cxx_constant_value (stmt);
+      break;
+
      case ADDR_EXPR:
        if (TREE_CODE (TREE_OPERAND (stmt, 0)) == FUNCTION_DECL
-         && DECL_IMMEDIATE_FUNCTION_P (TREE_OPERAND (stmt, 0)))
+         && DECL_IMMEDIATE_FUNCTION_P (TREE_OPERAND (stmt, 0))
+         && !in_immediate_context ())

Likewise.

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 799183dc646..7dfb6de2da3 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3254,7 +3254,7 @@ bot_manip (tree* tp, int* walk_subtrees, void* data_)
     variables.  */
static tree
-bot_replace (tree* t, int* walk_subtrees, void* data_)
+bot_replace (tree* t, int*, void* data_)

Generally we keep the parameter name as a comment like
int */*walk_subtrees*/

diff --git a/gcc/testsuite/g++.dg/cpp23/consteval-if2.C 
b/gcc/testsuite/g++.dg/cpp23/consteval-if2.C
index d1845da9e58..9fa95295c43 100644
--- a/gcc/testsuite/g++.dg/cpp23/consteval-if2.C
+++ b/gcc/testsuite/g++.dg/cpp23/consteval-if2.C
@@ -65,7 +65,7 @@ qux (int x)
    int r = 0;
    if not consteval    // { dg-warning "'if consteval' only available with" "" 
{ target c++20_only } }
      {
-      r += foo (x);    // { dg-error "'x' is not a constant expression" }
+      r += foo (x);    // { dg-error "'x' is not a constant expression" "" { 
xfail *-*-* } }

This whole function should have a comment that these errors are not required because qux is never instantiated.

diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval11.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval11.C
index 2f68ec0f892..9fd32dcab7b 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval11.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval11.C
@@ -5,25 +5,25 @@ consteval int bar (int i) { if (i != 1) throw 1; return 0; }  // { 
dg-error "is n
constexpr int a = bar (1);
  constexpr int b = bar (2);            // { dg-message "in 'constexpr' expansion 
of" }
-constexpr int c = 0 ? bar (3) : 1;     // { dg-message "in 'constexpr' expansion 
of" }
+constexpr int c = 0 ? bar (3) : 1;

As discussed above, we need to keep this diagnostic and the others like it.

Let's also add a test with the

template <typename T, typename F>
constexpr bool is_not(T t, F f) {
    return not f(t);
}

consteval bool is_even(int i) { return i % 2 == 0; }

static_assert(is_not(5, is_even)); // ok

example from the paper.

Jason

Reply via email to