From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 45ACD3858288; Thu, 10 Aug 2023 22:58:13 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 45ACD3858288 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1691708293; bh=VrRl1KyEG0VaKovZGAwkJqjMyXrUtRzaGD5YBOrm4Oo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=AkFRZqXUnWbkyMBM6PU4d84rCsZYGpTVdez3jFJVIlP1PDHqWo0W57nNYt4oKZbPo pfdnNPH7bGLe4tLcK/T08os5pwU5CN7eRNc/9/4OKyg7nrVW73G0pmbbXj1SY9p892 /sY2Rn6KZzPFCABtP2CT5G2EH3nKFdiuO0GOMlXc= From: "mpolacek at gcc dot 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 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: c++ X-Bugzilla-Version: unknown X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: mpolacek at gcc dot gnu.org X-Bugzilla-Status: ASSIGNED X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: mpolacek at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: bug_status assigned_to Message-ID: In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 List-Id: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D107687 Marek Polacek 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 --- A (very) rudimentary patch that handles the simplest case so far: >From be2950f8cf3fb5ca0571054b4196de35d9807519 Mon Sep 17 00:00:00 2001 From: Marek Polacek 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 !=3D 0 || (current_function_decl !=3D 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) =3D=3D FUNCTION_DECL); + + /* An immediate-escalating function is + -- the call operator of a lambda that is not declared with the const= eval + 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 =3D special_memfn_p (fn); + if (sfk !=3D sfk_none + && DECL_DEFAULTED_FN (fn) + && !DECL_IMMEDIATE_FUNCTION_P (fn)) + return true; + /* -- a function that results from the instantiation of a templated enti= ty + 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 flag= s, tsubst_flags_t complain) tree fndecl =3D STRIP_TEMPLATE (TREE_OPERAND (fn, 0)); if (immediate_invocation_p (fndecl)) { + tree orig_call =3D call; tree obj_arg =3D 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 fla= gs, tsubst_flags_t complain) obj_arg =3D 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 const= ant + 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) =3D=3D error_mark_node) + { + SET_DECL_IMMEDIATE_FUNCTION_P (current_function_decl); + return orig_call; + } call =3D cxx_constant_value (call, obj_arg, complain); if (obj_arg && !error_operand_p (call)) call =3D 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 =3D *stmt_p =3D build_zero_cst (TREE_TYPE (stmt)); break; } @@ -1065,6 +1083,8 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *da= ta_) 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 =3D *stmt_p =3D 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 =3D 0; if consteval // { dg-warning "'if consteval' only available with= " "" { target c++20_only } } { - auto y =3D [=3D] { foo (x); }; // { dg-error "'x' is not a con= stant expression" } + auto y =3D [=3D] { 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 +constexpr int +f (T t) +{ + // OK, f promoted to consteval. + return id (t); +} + +constexpr auto a1 =3D f (3); + +// As a consequence of f being promoted to an immediate function, we +// can't take its address. +auto p1 =3D &f; // { dg-error "taking address of an immediate functio= n" } + +template +constexpr int +f2 (T) +{ + // This produces a constant; f2 *not* promoted to consteval. + return id (42); +} + +// ... so we can take its address. +auto p2 =3D &f2; + +constexpr int +f3 (int i) +{ + // f3 isn't a function template and those don't get upgraded to consteva= l. + return id (i); // { dg-error "not a constant expression" } +} base-commit: ecfd8c7ffecf9e8f851c996ec149fbda7ef202f5 --=20 2.41.0=