public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
From: "mpolacek at gcc dot gnu.org" <gcc-bugzilla@gcc.gnu.org>
To: gcc-bugs@gcc.gnu.org
Subject: [Bug c++/107687] [C++23] P2564 - consteval needs to propagate up
Date: Thu, 10 Aug 2023 22:58:12 +0000	[thread overview]
Message-ID: <bug-107687-4-RYOZNhSWaX@http.gcc.gnu.org/bugzilla/> (raw)
In-Reply-To: <bug-107687-4@http.gcc.gnu.org/bugzilla/>

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107687

Marek Polacek <mpolacek at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |ASSIGNED
           Assignee|unassigned at gcc dot gnu.org      |mpolacek at gcc dot gnu.org

--- Comment #1 from Marek Polacek <mpolacek at gcc dot gnu.org> ---
A (very) rudimentary patch that handles the simplest case so far:


From be2950f8cf3fb5ca0571054b4196de35d9807519 Mon Sep 17 00:00:00 2001
From: Marek Polacek <polacek@redhat.com>
Date: Thu, 10 Aug 2023 17:06:11 -0400
Subject: [PATCH] c++: implement P2564, consteval needs to propagate up
 [PR107687]

---
 gcc/cp/call.cc                               | 48 ++++++++++++++++++++
 gcc/cp/cp-gimplify.cc                        | 26 +++++++++--
 gcc/testsuite/g++.dg/cpp23/consteval-if10.C  |  2 +-
 gcc/testsuite/g++.dg/cpp2a/consteval-prop1.C | 36 +++++++++++++++
 4 files changed, 108 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop1.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 673ec91d60e..34b2fe1884d 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -9740,6 +9740,7 @@ build_trivial_dtor_call (tree instance, bool
no_ptr_deref)
 bool
 in_immediate_context ()
 {
+  // TODO update to say that manifestly constant eval ctx is an IFC
   return (cp_unevaluated_operand != 0
          || (current_function_decl != NULL_TREE
              && DECL_IMMEDIATE_FUNCTION_P (current_function_decl))
@@ -9762,6 +9763,34 @@ immediate_invocation_p (tree fn)
          && !in_immediate_context ());
 }

+/* Return true if FN is an immediate-escalating function.  */
+
+static bool
+immediate_escalating_function_p (tree fn)
+{
+  if (!fn)
+    return false;
+
+  gcc_checking_assert (TREE_CODE (fn) == FUNCTION_DECL);
+
+  /* An immediate-escalating function is
+      -- the call operator of a lambda that is not declared with the consteval
+        specifier  */
+  if (LAMBDA_FUNCTION_P (fn) && !DECL_IMMEDIATE_FUNCTION_P (fn))
+    return true;
+  /* -- a defaulted special member function that is not declared with the
+       consteval specifier  */
+  special_function_kind sfk = special_memfn_p (fn);
+  if (sfk != sfk_none
+      && DECL_DEFAULTED_FN (fn)
+      && !DECL_IMMEDIATE_FUNCTION_P (fn))
+    return true;
+  /* -- a function that results from the instantiation of a templated entity
+       defined with the constexpr specifier.  */
+  // TODO check if the DECL_DEFAULTED_FN part is actually OK here
+  return is_instantiation_of_constexpr (fn);
+}
+
 /* Subroutine of the various build_*_call functions.  Overload resolution
    has chosen a winning candidate CAND; build up a CALL_EXPR accordingly.
    ARGS is a TREE_LIST of the unconverted arguments to the call.  FLAGS is a
@@ -10484,6 +10513,7 @@ build_over_call (struct z_candidate *cand, int flags,
tsubst_flags_t complain)
       tree fndecl = STRIP_TEMPLATE (TREE_OPERAND (fn, 0));
       if (immediate_invocation_p (fndecl))
        {
+         tree orig_call = call;
          tree obj_arg = NULL_TREE;
          /* Undo convert_from_reference called by build_cxx_call.  */
          if (REFERENCE_REF_P (call))
@@ -10508,6 +10538,24 @@ build_over_call (struct z_candidate *cand, int flags,
tsubst_flags_t complain)
                    obj_arg = TREE_OPERAND (addr, 0);
                }
            }
+
+         /* [expr.const]p16 "An expression or conversion is
+            immediate-escalating if it is not initially in an immediate
+            function context and it is either
+             -- an immediate invocation that is not a constant expression and
+             is not a subexpression of an immediate invocation."
+
+             If we are in an immediate-escalating function, the
+             immediate-escalating expression or conversion makes it an
+             immediate function.  So CALL does not need to produce a constant
+             expression.  ??? It's ugly to call cxx_constant_value twice in
+             some cases.  */
+         if (immediate_escalating_function_p (current_function_decl)
+             && cxx_constant_value (call, obj_arg, tf_none) ==
error_mark_node)
+           {
+             SET_DECL_IMMEDIATE_FUNCTION_P (current_function_decl);
+             return orig_call;
+           }
          call = cxx_constant_value (call, obj_arg, complain);
          if (obj_arg && !error_operand_p (call))
            call = cp_build_init_expr (obj_arg, call);
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 206e791fcfd..5fc0e3cc84b 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -1017,6 +1017,20 @@ maybe_replace_decl (tree *tp, tree decl, tree
replacement)
   return true;
 }

+/* Maybe say that FN was initially not an immediate function, but was
+   promoted to one because its body contained an immediate-escalating
+   expression or conversion.  */
+
+static void
+maybe_explain_promoted_consteval (location_t loc, tree fn)
+{
+  /* A function cannot be marked both constexpr and consteval
+     except when we've promoted the former to the latter.  */
+  if (is_instantiation_of_constexpr (fn)
+      && DECL_DECLARED_CONSTEXPR_P (fn))
+    inform (loc, "%qD was promoted to an immediate function", fn);
+}
+
 /* Genericization context.  */

 struct cp_genericize_data
@@ -1050,9 +1064,13 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void
*data_)
          && DECL_IMMEDIATE_FUNCTION_P (PTRMEM_CST_MEMBER (stmt)))
        {
          if (!data->pset.add (stmt))
-           error_at (PTRMEM_CST_LOCATION (stmt),
-                     "taking address of an immediate function %qD",
-                     PTRMEM_CST_MEMBER (stmt));
+           {
+             error_at (PTRMEM_CST_LOCATION (stmt),
+                       "taking address of an immediate function %qD",
+                       PTRMEM_CST_MEMBER (stmt));
+             maybe_explain_promoted_consteval (PTRMEM_CST_LOCATION (stmt),
+                                               PTRMEM_CST_MEMBER (stmt));
+           }
          stmt = *stmt_p = build_zero_cst (TREE_TYPE (stmt));
          break;
        }
@@ -1065,6 +1083,8 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
          error_at (EXPR_LOCATION (stmt),
                    "taking address of an immediate function %qD",
                    TREE_OPERAND (stmt, 0));
+         maybe_explain_promoted_consteval (EXPR_LOCATION (stmt),
+                                           TREE_OPERAND (stmt, 0));
          stmt = *stmt_p = build_zero_cst (TREE_TYPE (stmt));
          break;
        }
diff --git a/gcc/testsuite/g++.dg/cpp23/consteval-if10.C
b/gcc/testsuite/g++.dg/cpp23/consteval-if10.C
index 4c0523fe1d0..f799e81113d 100644
--- a/gcc/testsuite/g++.dg/cpp23/consteval-if10.C
+++ b/gcc/testsuite/g++.dg/cpp23/consteval-if10.C
@@ -10,7 +10,7 @@ bar (int x)
   int r = 0;
   if consteval         // { dg-warning "'if consteval' only available with" ""
{ target c++20_only } }
     {
-      auto y = [=] { foo (x); };       // { dg-error "'x' is not a constant
expression" }
+      auto y = [=] { foo (x); };
       y ();
     }
   return r;
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop1.C
b/gcc/testsuite/g++.dg/cpp2a/consteval-prop1.C
new file mode 100644
index 00000000000..9a791b9cf0b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop1.C
@@ -0,0 +1,36 @@
+// P2564R3
+// { dg-do compile { target c++20 } }
+
+consteval int id(int i) { return i; }
+
+template <typename T>
+constexpr int
+f (T t)
+{
+  // OK, f promoted to consteval.
+  return id (t);
+}
+
+constexpr auto a1 = f (3);
+
+// As a consequence of f<int> being promoted to an immediate function, we
+// can't take its address.
+auto p1 = &f<int>; // { dg-error "taking address of an immediate function" }
+
+template <typename T>
+constexpr int
+f2 (T)
+{
+  // This produces a constant; f2 *not* promoted to consteval.
+  return id (42);
+}
+
+// ... so we can take its address.
+auto p2 = &f2<int>;
+
+constexpr int
+f3 (int i)
+{
+  // f3 isn't a function template and those don't get upgraded to consteval.
+  return id (i); // { dg-error "not a constant expression" }
+}

base-commit: ecfd8c7ffecf9e8f851c996ec149fbda7ef202f5
-- 
2.41.0

  parent reply	other threads:[~2023-08-10 22:58 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-14 18:36 [Bug c++/107687] New: " mpolacek at gcc dot gnu.org
2022-11-14 18:36 ` [Bug c++/107687] " mpolacek at gcc dot gnu.org
2023-08-10 22:58 ` mpolacek at gcc dot gnu.org [this message]
2023-08-11 19:39 ` mpolacek at gcc dot gnu.org
2023-12-05  0:42 ` cvs-commit at gcc dot gnu.org
2023-12-05  0:44 ` mpolacek at gcc dot gnu.org
2023-12-05  0:45 ` mpolacek at gcc dot gnu.org
2024-01-12  7:38 ` rguenth at gcc dot gnu.org

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bug-107687-4-RYOZNhSWaX@http.gcc.gnu.org/bugzilla/ \
    --to=gcc-bugzilla@gcc.gnu.org \
    --cc=gcc-bugs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).