From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by sourceware.org (Postfix) with ESMTPS id AF9403858D39 for ; Wed, 6 Dec 2023 11:39:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org AF9403858D39 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linaro.org ARC-Filter: OpenARC Filter v1.0.0 sourceware.org AF9403858D39 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:1450:4864:20::42e ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701862809; cv=none; b=jA5nrZX0Q+x438NGiVp8c0DaYriPzt1b1uSpg9qrHF/V+Z+Rxueg0v34AL+sB8HuQXShRc+xv4ShlzzSrW4Q9+MZ0UG4NrNyJ1U1bJwDF+izVClyqqDLTom39IDiL37TmP7DDasI9w3fk8fNxadreu5aCm4h9CCwYWLNyKtIH0s= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701862809; c=relaxed/simple; bh=uykLBS3cUJhQqa3qsivWh+pXx2XMxXb2tB+Rypj30zM=; h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To; b=DRABBmSA2qYDdWqX4tTKxRp2QehNlwy01KMAdKUf5SaWdxcRjbIHcTMp/xUT/D498hFeMbNxLUEP1Ui8xDTHkkoMepMrLwAfuDiQjEwu3JjaQhvHjAFVnkJWulvrndn30z3gi5YviVTK6cguQxvGe9suftNz8nb/v/wcop9kinY= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-wr1-x42e.google.com with SMTP id ffacd0b85a97d-33340c50af9so667429f8f.3 for ; Wed, 06 Dec 2023 03:39:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1701862797; x=1702467597; darn=gcc.gnu.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=gigIL+B+Fcl9r4vhI3Kw/git/NIn1+H5szqL9W89I1I=; b=SuwhwSYyrFt2yhjWggQuY9sh3eo/0UeIk4KO+W/V9rRdZK3KhDd9AE7eeWmXVa67Oa GVeYUeddyPf6hlIMViy6DY+ITdO2pdpU3SIX/elbse9bfNjyVhkGUD63YApNUndrscrf OhUXoVzpUdTfiC4RM9fXQHcxEP25klvG4oeCgzDfkF8VrV13LOHAGaq6i3LypE/WqJ8Q l3/Hcg9B5bOWm27/H7B/J6DM1+oKNwsZ8KZBsY2iniqQ5Q22yobVubpQk6G4IsFYVoRr 5trkiNwleqrkSdcFxYXa0QJpR1qRCPgwfnYqdFm46kPfXoWWe4vghFXoeuz6Qg6nQsr7 WkdA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701862797; x=1702467597; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=gigIL+B+Fcl9r4vhI3Kw/git/NIn1+H5szqL9W89I1I=; b=ItPjLEZsR/e64OuvPdtf+3PxcakqJglpCvF23FjjTyLhjCic3m8tnwlC65K6bxSbNM VynMp7bDblt/GVag0uSlTFC9BYkGFT+lMmzDr7Ae3y6EIFY6+QK222F6072RHtnFf8tp oJIjgFyjFfkLkgqPF33TlHE2Yr4i3zxveSeWokUt+XqEbTwyyKsClS3bag+LOH5gi8Gb o4uaHx8baqsL7Phdf1rkDc66U4rqPyy970lkOlU2j40TSqW11t06yinookUOb6zNdgpI f+cSQuLTWLE1koc8BRWju0xoh1vEFfQXXU6pTF2/dmGRL6m4eRXOUqoRFeIBNj0lFNhD rINA== X-Gm-Message-State: AOJu0YypRpi9M0alUNYz0kgw37JQWXYdJ6tlCe530uPXBASBWPYgwqxa C7rl/gDqpY4KVcezqUL9hKavTS8ojOSEwDZGsIck+w== X-Google-Smtp-Source: AGHT+IGm1V35f1Y5IIQAdRk9rGzi/gJXOGDvLENI7GI0ABBRR7CyuRy70xhNlT/Tr56VFF/5wWqj0RzMc7BNwyTehIg= X-Received: by 2002:a5d:51c3:0:b0:333:2fd2:3c00 with SMTP id n3-20020a5d51c3000000b003332fd23c00mr276191wrv.185.1701862796286; Wed, 06 Dec 2023 03:39:56 -0800 (PST) MIME-Version: 1.0 References: <6a3303b5-85b3-4d8f-a4e3-4f41455ec6d1@redhat.com> <1d9a1b66-c1ba-4aa1-80e3-09c5e1840845@redhat.com> In-Reply-To: From: Prathamesh Kulkarni Date: Wed, 6 Dec 2023 17:09:21 +0530 Message-ID: Subject: Re: [PATCH v8] c++: implement P2564, consteval needs to propagate up [PR107687] To: Marek Polacek Cc: Jason Merrill , GCC Patches Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-8.8 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP,T_SCC_BODY_TEXT_LINE,URIBL_BLACK autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On Tue, 5 Dec 2023 at 06:18, Marek Polacek wrote: > > On Mon, Dec 04, 2023 at 04:49:29PM -0500, Jason Merrill wrote: > > On 12/4/23 15:23, Marek Polacek wrote: > > > +/* FN is not a consteval function, but may become one. Remember to > > > + escalate it after all pending templates have been instantiated. */ > > > + > > > +void > > > +maybe_store_immediate_escalating_fn (tree fn) > > > +{ > > > + if (unchecked_immediate_escalating_function_p (fn)) > > > + remember_escalating_expr (fn); > > > +} > > > > > +++ b/gcc/cp/decl.cc > > > @@ -18441,7 +18441,10 @@ finish_function (bool inline_p) > > > if (!processing_template_decl > > > && !DECL_IMMEDIATE_FUNCTION_P (fndecl) > > > && !DECL_OMP_DECLARE_REDUCTION_P (fndecl)) > > > - cp_fold_function (fndecl); > > > + { > > > + cp_fold_function (fndecl); > > > + maybe_store_immediate_escalating_fn (fndecl); > > > + } > > > > I think maybe_store_, and the call to it from finish_function, are unneeded; > > we will have already decided whether we need to remember the function during > > the call to cp_fold_function. > > 'Tis true. > > > OK with that change. > > Here's what I pushed after another regtest. Thanks! Hi Marek, It seems the patch caused following regressions on aarch64: Running g++:g++.dg/modules/modules.exp ... FAIL: g++.dg/modules/xtreme-header-4_b.C -std=c++2b (internal compiler error: tree check: expected class 'type', have 'declaration' (template_decl) in get_originating_module_decl, at cp/module.cc:18659) FAIL: g++.dg/modules/xtreme-header-5_b.C -std=c++2b (internal compiler error: tree check: expected class 'type', have 'declaration' (template_decl) in get_originating_module_decl, at cp/module.cc:18659) FAIL: g++.dg/modules/xtreme-header_b.C -std=c++2b (internal compiler error: tree check: expected class 'type', have 'declaration' (template_decl) in get_originating_module_decl, at cp/module.cc:18659) Log files: https://ci.linaro.org/job/tcwg_gcc_check--master-aarch64-build/1299/artifact/artifacts/00-sumfiles/ Thanks, Prathamesh > > -- >8 -- > This patch implements P2564, described at , whereby > certain functions are promoted to consteval. For example: > > consteval int id(int i) { return i; } > > template > constexpr int f(T t) > { > return t + id(t); // id causes f to be promoted to consteval > } > > void g(int i) > { > f (3); > } > > now compiles. Previously the code was ill-formed: we would complain > that 't' in 'f' is not a constant expression. Since 'f' is now > consteval, it means that the call to id(t) is in an immediate context, > so doesn't have to produce a constant -- this is how we allow consteval > functions composition. But making 'f' consteval also means that > the call to 'f' in 'g' must yield a constant; failure to do so results > in an error. I made the effort to have cc1plus explain to us what's > going on. For example, calling f(i) produces this neat diagnostic: > > w.C:11:11: error: call to consteval function 'f(i)' is not a constant expression > 11 | f (i); > | ~~^~~ > w.C:11:11: error: 'i' is not a constant expression > w.C:6:22: note: 'constexpr int f(T) [with T = int]' was promoted to an immediate function because its body contains an immediate-escalating expression 'id(t)' > 6 | return t + id(t); // id causes f to be promoted to consteval > | ~~^~~ > > which hopefully makes it clear what's going on. > > Implementing this proposal has been tricky. One problem was delayed > instantiation: instantiating a function can set off a domino effect > where one call promotes a function to consteval but that then means > that another function should also be promoted, etc. > > In v1, I addressed the delayed instantiation problem by instantiating > trees early, so that we can escalate functions right away. That caused > a number of problems, and in certain cases, like consteval-prop3.C, it > can't work, because we need to wait till EOF to see the definition of > the function anyway. Overeager instantiation tends to cause diagnostic > problems too. > > In v2, I attempted to move the escalation to the gimplifier, at which > point all templates have been instantiated. That attempt flopped, > however, because once we've gimplified a function, its body is discarded > and as a consequence, you can no longer evaluate a call to that function > which is required for escalating, which needs to decide if a call is > a constant expression or not. > > Therefore, we have to perform the escalation before gimplifying, but > after instantiate_pending_templates. That's not easy because we have > no way to walk all the trees. In the v2 patch, I use two vectors: one > to store function decls that may become consteval, and another to > remember references to immediate-escalating functions. Unfortunately > the latter must also stash functions that call immediate-escalating > functions. Consider: > > int g(int i) > { > f(i); // f is immediate-escalating > } > > where g itself is not immediate-escalating, but we have to make sure > that if f gets promoted to consteval, we give an error. > > A new option, -fno-immediate-escalation, is provided to suppress > escalating functions. > > v2 also adds a new flag, DECL_ESCALATION_CHECKED_P, so that we don't > escalate a function multiple times, and so that we can distinguish between > explicitly consteval functions and functions that have been promoted > to consteval. > > In v3, I removed one of the new vectors and changed the other one > to a hash set. This version also contains numerous cleanups. > > v4 merges find_escalating_expr_r into cp_fold_immediate_r. It also > adds a new optimization in cp_fold_function. > > v5 greatly simplifies the code. > > v6 simplifies the code further and removes an ff_ flag. > > v7 removes maybe_promote_function_to_consteval and further simplifies > cp_fold_immediate_r logic. > > v8 removes maybe_store_immediate_escalating_fn. > > PR c++/107687 > PR c++/110997 > > gcc/c-family/ChangeLog: > > * c-cppbuiltin.cc (c_cpp_builtins): Update __cpp_consteval. > * c-opts.cc (c_common_post_options): Pre-C++20, unset > flag_immediate_escalation. > * c.opt (fimmediate-escalation): New option. > > gcc/cp/ChangeLog: > > * call.cc (in_immediate_context): No longer static. > * constexpr.cc (cxx_eval_call_expression): Adjust assert. > * cp-gimplify.cc (deferred_escalating_exprs): New vec. > (remember_escalating_expr): New. > (enum fold_flags): Remove ff_fold_immediate. > (immediate_escalating_function_p): New. > (unchecked_immediate_escalating_function_p): New. > (promote_function_to_consteval): New. > (cp_fold_immediate): Move above. Return non-null if any errors were > emitted. > (maybe_explain_promoted_consteval): New. > (cp_gimplify_expr) : Assert we've handled all > immediate invocations. > (taking_address_of_imm_fn_error): New. > (cp_fold_immediate_r): Merge ADDR_EXPR and PTRMEM_CST cases. Implement > P2564 - promoting functions to consteval. > : Implement P2564 - promoting functions to consteval. > (cp_fold_r): If an expression turns into a CALL_EXPR after cp_fold, > call cp_fold_immediate_r on the CALL_EXPR. > (cp_fold_function): Set DECL_ESCALATION_CHECKED_P if > deferred_escalating_exprs does not contain current_function_decl. > (process_and_check_pending_immediate_escalating_fns): New. > * cp-tree.h (struct lang_decl_fn): Add escalated_p bit-field. > (DECL_ESCALATION_CHECKED_P): New. > (immediate_invocation_p): Declare. > (process_pending_immediate_escalating_fns): Likewise. > * decl2.cc (c_parse_final_cleanups): Set at_eof to 2 after all > templates have been instantiated; and to 3 at the end of the function. > Call process_pending_immediate_escalating_fns. > * error.cc (dump_template_bindings): Check at_eof against an updated > value. > * module.cc (trees_out::lang_decl_bools): Stream escalated_p. > (trees_in::lang_decl_bools): Likewise. > * pt.cc (push_tinst_level_loc): Set at_eof to 3, not 2. > * typeck.cc (cp_build_addr_expr_1): Don't check > DECL_IMMEDIATE_FUNCTION_P. > > gcc/ChangeLog: > > * doc/invoke.texi: Document -fno-immediate-escalation. > > libstdc++-v3/ChangeLog: > > * testsuite/18_support/comparisons/categories/zero_neg.cc: Add > dg-prune-output. > * testsuite/std/format/string_neg.cc: Add dg-error. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp23/consteval-if10.C: Remove dg-error. > * g++.dg/cpp23/consteval-if2.C: Likewise. > * g++.dg/cpp23/feat-cxx2b.C: Adjust expected value of __cpp_consteval. > * g++.dg/cpp26/feat-cxx26.C: Likewise. > * g++.dg/cpp2a/consteval-memfn1.C: Add dg-error. > * g++.dg/cpp2a/consteval11.C: Likewise. > * g++.dg/cpp2a/consteval3.C: Adjust dg-error. > * g++.dg/cpp2a/consteval34.C: Add dg-error. > * g++.dg/cpp2a/consteval9.C: Likewise. > * g++.dg/cpp2a/feat-cxx2a.C: Adjust expected value of __cpp_consteval. > * g++.dg/cpp2a/spaceship-synth9.C: Adjust dg-error. > * g++.dg/cpp2a/consteval-prop1.C: New test. > * g++.dg/cpp2a/consteval-prop10.C: New test. > * g++.dg/cpp2a/consteval-prop11.C: New test. > * g++.dg/cpp2a/consteval-prop12.C: New test. > * g++.dg/cpp2a/consteval-prop13.C: New test. > * g++.dg/cpp2a/consteval-prop14.C: New test. > * g++.dg/cpp2a/consteval-prop15.C: New test. > * g++.dg/cpp2a/consteval-prop16.C: New test. > * g++.dg/cpp2a/consteval-prop17.C: New test. > * g++.dg/cpp2a/consteval-prop18.C: New test. > * g++.dg/cpp2a/consteval-prop19.C: New test. > * g++.dg/cpp2a/consteval-prop20.C: New test. > * g++.dg/cpp2a/consteval-prop2.C: New test. > * g++.dg/cpp2a/consteval-prop3.C: New test. > * g++.dg/cpp2a/consteval-prop4.C: New test. > * g++.dg/cpp2a/consteval-prop5.C: New test. > * g++.dg/cpp2a/consteval-prop6.C: New test. > * g++.dg/cpp2a/consteval-prop7.C: New test. > * g++.dg/cpp2a/consteval-prop8.C: New test. > * g++.dg/cpp2a/consteval-prop9.C: New test. > --- > gcc/c-family/c-cppbuiltin.cc | 2 +- > gcc/c-family/c-opts.cc | 5 + > gcc/c-family/c.opt | 4 + > gcc/cp/call.cc | 2 +- > gcc/cp/constexpr.cc | 4 +- > gcc/cp/cp-gimplify.cc | 348 ++++++++++++++---- > gcc/cp/cp-tree.h | 19 +- > gcc/cp/decl2.cc | 16 +- > gcc/cp/error.cc | 2 +- > gcc/cp/module.cc | 4 + > gcc/cp/pt.cc | 2 +- > gcc/cp/typeck.cc | 6 +- > gcc/doc/invoke.texi | 34 ++ > gcc/testsuite/g++.dg/cpp23/consteval-if10.C | 7 +- > gcc/testsuite/g++.dg/cpp23/consteval-if2.C | 14 +- > gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C | 4 +- > gcc/testsuite/g++.dg/cpp26/feat-cxx26.C | 4 +- > gcc/testsuite/g++.dg/cpp2a/consteval-memfn1.C | 3 + > gcc/testsuite/g++.dg/cpp2a/consteval-prop1.C | 169 +++++++++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop10.C | 41 +++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop11.C | 49 +++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop12.C | 30 ++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop13.C | 23 ++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop14.C | 78 ++++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop15.C | 107 ++++++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop16.C | 73 ++++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop17.C | 17 + > gcc/testsuite/g++.dg/cpp2a/consteval-prop18.C | 20 + > gcc/testsuite/g++.dg/cpp2a/consteval-prop19.C | 7 + > gcc/testsuite/g++.dg/cpp2a/consteval-prop2.C | 90 +++++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop20.C | 21 ++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop3.C | 27 ++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop4.C | 30 ++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop5.C | 27 ++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop6.C | 59 +++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop7.C | 76 ++++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop8.C | 82 +++++ > gcc/testsuite/g++.dg/cpp2a/consteval-prop9.C | 67 ++++ > gcc/testsuite/g++.dg/cpp2a/consteval11.C | 18 + > gcc/testsuite/g++.dg/cpp2a/consteval3.C | 4 +- > gcc/testsuite/g++.dg/cpp2a/consteval34.C | 8 + > gcc/testsuite/g++.dg/cpp2a/consteval36.C | 26 +- > gcc/testsuite/g++.dg/cpp2a/consteval9.C | 2 + > gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C | 4 +- > gcc/testsuite/g++.dg/cpp2a/spaceship-synth9.C | 2 +- > .../comparisons/categories/zero_neg.cc | 1 + > .../testsuite/std/format/string_neg.cc | 2 +- > 47 files changed, 1525 insertions(+), 115 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop1.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop10.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop11.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop12.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop13.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop14.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop15.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop16.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop17.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop18.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop19.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop2.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop20.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop3.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop4.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop5.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop6.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop7.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop8.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-prop9.C > > diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc > index e536429fa4c..2d1249f29ed 100644 > --- a/gcc/c-family/c-cppbuiltin.cc > +++ b/gcc/c-family/c-cppbuiltin.cc > @@ -1059,7 +1059,7 @@ c_cpp_builtins (cpp_reader *pfile) > cpp_define (pfile, "__cpp_constexpr=202002L"); > cpp_define (pfile, "__cpp_constexpr_in_decltype=201711L"); > cpp_define (pfile, "__cpp_conditional_explicit=201806L"); > - cpp_define (pfile, "__cpp_consteval=201811L"); > + cpp_define (pfile, "__cpp_consteval=202211L"); > cpp_define (pfile, "__cpp_constinit=201907L"); > cpp_define (pfile, "__cpp_deduction_guides=201907L"); > cpp_define (pfile, "__cpp_nontype_template_args=201911L"); > diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc > index d7faff10d66..d484ecfdfdb 100644 > --- a/gcc/c-family/c-opts.cc > +++ b/gcc/c-family/c-opts.cc > @@ -1139,6 +1139,11 @@ c_common_post_options (const char **pfilename) > if (cxx_dialect >= cxx20 || flag_concepts_ts) > flag_concepts = 1; > > + /* -fimmediate-escalation has no effect when immediate functions are not > + supported. */ > + if (flag_immediate_escalation && cxx_dialect < cxx20) > + flag_immediate_escalation = 0; > + > if (num_in_fnames > 1) > error ("too many filenames given; type %<%s %s%> for usage", > progname, "--help"); > diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt > index ab44a6da66a..3706505f8bf 100644 > --- a/gcc/c-family/c.opt > +++ b/gcc/c-family/c.opt > @@ -1898,6 +1898,10 @@ fhuge-objects > C++ ObjC++ WarnRemoved > No longer supported. > > +fimmediate-escalation > +C++ ObjC++ Var(flag_immediate_escalation) Init(1) > +Implement P2564 for consteval propagation. > + > fimplement-inlines > C++ ObjC++ Var(flag_implement_inlines) Init(1) > Export functions even if they can be inlined. > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc > index ae0decd87f1..c7efc5b077a 100644 > --- a/gcc/cp/call.cc > +++ b/gcc/cp/call.cc > @@ -9742,7 +9742,7 @@ in_immediate_context () > /* Return true if a call to FN with number of arguments NARGS > is an immediate invocation. */ > > -static bool > +bool > immediate_invocation_p (tree fn) > { > return (TREE_CODE (fn) == FUNCTION_DECL > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc > index 96c61666470..58187a4fd12 100644 > --- a/gcc/cp/constexpr.cc > +++ b/gcc/cp/constexpr.cc > @@ -3128,11 +3128,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, > /* OK */; > else if (!DECL_SAVED_TREE (fun)) > { > - /* When at_eof >= 2, cgraph has started throwing away > + /* When at_eof >= 3, cgraph has started throwing away > DECL_SAVED_TREE, so fail quietly. FIXME we get here because of > late code generation for VEC_INIT_EXPR, which needs to be > completely reconsidered. */ > - gcc_assert (at_eof >= 2 && ctx->quiet); > + gcc_assert (at_eof >= 3 && ctx->quiet); > *non_constant_p = true; > } > else if (tree copy = get_fundef_copy (new_call.fundef)) > diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc > index 795c811471d..5abb91bbdd3 100644 > --- a/gcc/cp/cp-gimplify.cc > +++ b/gcc/cp/cp-gimplify.cc > @@ -43,6 +43,21 @@ along with GCC; see the file COPYING3. If not see > #include "omp-general.h" > #include "opts.h" > > +/* Keep track of forward references to immediate-escalating functions in > + case they become consteval. This vector contains ADDR_EXPRs and > + PTRMEM_CSTs; it also stores FUNCTION_DECLs that had an escalating > + function call in them, to check that they can be evaluated to a constant, > + and immediate-escalating functions that may become consteval. */ > +static GTY(()) hash_set *deferred_escalating_exprs; > + > +static void > +remember_escalating_expr (tree t) > +{ > + if (!deferred_escalating_exprs) > + deferred_escalating_exprs = hash_set::create_ggc (37); > + deferred_escalating_exprs->add (t); > +} > + > /* Flags for cp_fold and cp_fold_r. */ > > enum fold_flags { > @@ -53,8 +68,6 @@ enum fold_flags { > definitely not in a manifestly constant-evaluated > context. */ > ff_mce_false = 1 << 1, > - /* Whether we're being called from cp_fold_immediate. */ > - ff_fold_immediate = 1 << 2, > }; > > using fold_flags_t = int; > @@ -72,6 +85,7 @@ static tree cp_genericize_r (tree *, int *, void *); > static tree cp_fold_r (tree *, int *, void *); > static void cp_genericize_tree (tree*, bool); > static tree cp_fold (tree, fold_flags_t); > +static tree cp_fold_immediate_r (tree *, int *, void *); > > /* Genericize a TRY_BLOCK. */ > > @@ -428,6 +442,104 @@ lvalue_has_side_effects (tree e) > return TREE_SIDE_EFFECTS (e); > } > > +/* Return true if FN is an immediate-escalating function. */ > + > +static bool > +immediate_escalating_function_p (tree fn) > +{ > + if (!fn || !flag_immediate_escalation) > + return false; > + > + gcc_checking_assert (TREE_CODE (fn) == FUNCTION_DECL); > + > + if (DECL_IMMEDIATE_FUNCTION_P (fn)) > + return false; > + > + /* An immediate-escalating function is > + -- the call operator of a lambda that is not declared with the consteval > + specifier */ > + if (LAMBDA_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)) > + return true; > + /* -- a function that results from the instantiation of a templated entity > + defined with the constexpr specifier. */ > + return is_instantiation_of_constexpr (fn); > +} > + > +/* Return true if FN is an immediate-escalating function that has not been > + checked for escalating expressions.. */ > + > +static bool > +unchecked_immediate_escalating_function_p (tree fn) > +{ > + return (immediate_escalating_function_p (fn) > + && !DECL_ESCALATION_CHECKED_P (fn)); > +} > + > +/* Promote FN to an immediate function, including its clones. */ > + > +static void > +promote_function_to_consteval (tree fn) > +{ > + SET_DECL_IMMEDIATE_FUNCTION_P (fn); > + DECL_ESCALATION_CHECKED_P (fn) = true; > + tree clone; > + FOR_EACH_CLONE (clone, fn) > + { > + SET_DECL_IMMEDIATE_FUNCTION_P (clone); > + DECL_ESCALATION_CHECKED_P (clone) = true; > + } > +} > + > +/* A wrapper around cp_fold_immediate_r. Return a non-null tree if > + we found a non-constant immediate function, or taking the address > + of an immediate function. */ > + > +tree > +cp_fold_immediate (tree *tp, mce_value manifestly_const_eval, > + tree decl /*= current_function_decl*/) > +{ > + if (cxx_dialect <= cxx17) > + return NULL_TREE; > + > + temp_override cfd (current_function_decl, decl); > + > + fold_flags_t flags = ff_none; > + if (manifestly_const_eval == mce_false) > + flags |= ff_mce_false; > + > + cp_fold_data data (flags); > + int save_errorcount = errorcount; > + tree r = cp_walk_tree_without_duplicates (tp, cp_fold_immediate_r, &data); > + if (errorcount > save_errorcount) > + return integer_one_node; > + return r; > +} > + > +/* Maybe say that FN (a function decl with DECL_IMMEDIATE_FUNCTION_P set) > + 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) > +{ > + if (DECL_ESCALATION_CHECKED_P (fn)) > + { > + /* See if we can figure out what made the function consteval. */ > + tree x = cp_fold_immediate (&DECL_SAVED_TREE (fn), mce_unknown, NULL_TREE); > + if (x) > + inform (cp_expr_loc_or_loc (x, loc), > + "%qD was promoted to an immediate function because its " > + "body contains an immediate-escalating expression %qE", fn, x); > + else > + inform (loc, "%qD was promoted to an immediate function", fn); > + } > +} > + > /* Gimplify *EXPR_P as rvalue into an expression that can't be modified > by expressions with side-effects in other operands. */ > > @@ -746,7 +858,9 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) > if (ret != GS_ERROR) > { > tree decl = cp_get_callee_fndecl_nofold (*expr_p); > - if (decl && fndecl_built_in_p (decl, BUILT_IN_FRONTEND)) > + if (!decl) > + break; > + if (fndecl_built_in_p (decl, BUILT_IN_FRONTEND)) > switch (DECL_FE_FUNCTION_CODE (decl)) > { > case CP_BUILT_IN_IS_CONSTANT_EVALUATED: > @@ -771,10 +885,12 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) > default: > break; > } > - else if (decl > - && fndecl_built_in_p (decl, BUILT_IN_CLZG, BUILT_IN_CTZG)) > + else if (fndecl_built_in_p (decl, BUILT_IN_CLZG, BUILT_IN_CTZG)) > ret = (enum gimplify_status) c_gimplify_expr (expr_p, pre_p, > post_p); > + else > + /* All consteval functions should have been processed by now. */ > + gcc_checking_assert (!immediate_invocation_p (decl)); > } > break; > > @@ -1035,6 +1151,20 @@ struct cp_genericize_data > bool handle_invisiref_parm_p; > }; > > +/* Emit an error about taking the address of an immediate function. > + EXPR is the whole expression; DECL is the immediate function. */ > + > +static void > +taking_address_of_imm_fn_error (tree expr, tree decl) > +{ > + auto_diagnostic_group d; > + const location_t loc = (TREE_CODE (expr) == PTRMEM_CST > + ? PTRMEM_CST_LOCATION (expr) > + : EXPR_LOCATION (expr)); > + error_at (loc, "taking address of an immediate function %qD", decl); > + maybe_explain_promoted_consteval (loc, decl); > +} > + > /* A subroutine of cp_fold_r to handle immediate functions. */ > > static tree > @@ -1045,90 +1175,128 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, void *data_) > /* The purpose of this is not to emit errors for mce_unknown. */ > const tsubst_flags_t complain = (data->flags & ff_mce_false > ? tf_error : tf_none); > + const tree_code code = TREE_CODE (stmt); > > /* No need to look into types or unevaluated operands. > NB: This affects cp_fold_r as well. */ > - if (TYPE_P (stmt) || unevaluated_p (TREE_CODE (stmt))) > + if (TYPE_P (stmt) || unevaluated_p (code) || in_immediate_context ()) > { > *walk_subtrees = 0; > return NULL_TREE; > } > > - switch (TREE_CODE (stmt)) > - { > - case PTRMEM_CST: > - if (TREE_CODE (PTRMEM_CST_MEMBER (stmt)) == FUNCTION_DECL > - && DECL_IMMEDIATE_FUNCTION_P (PTRMEM_CST_MEMBER (stmt))) > - { > - if (!data->pset.add (stmt) && (complain & tf_error)) > - { > - error_at (PTRMEM_CST_LOCATION (stmt), > - "taking address of an immediate function %qD", > - PTRMEM_CST_MEMBER (stmt)); > - *stmt_p = build_zero_cst (TREE_TYPE (stmt)); > - } > - return error_mark_node; > - } > - break; > + tree decl = NULL_TREE; > + bool call_p = false; > > - /* Expand immediate invocations. */ > + /* We are looking for &fn or fn(). */ > + switch (code) > + { > case CALL_EXPR: > case AGGR_INIT_EXPR: > 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 = cxx_constant_value (stmt, complain); > - if (stmt == error_mark_node) > - { > - if (complain & tf_error) > - *stmt_p = error_mark_node; > - return error_mark_node; > - } > - *stmt_p = stmt; > - } > + decl = cp_get_fndecl_from_callee (fn, /*fold*/false); > + call_p = true; > + break; > + case PTRMEM_CST: > + decl = PTRMEM_CST_MEMBER (stmt); > break; > - > case ADDR_EXPR: > - if (TREE_CODE (TREE_OPERAND (stmt, 0)) == FUNCTION_DECL > - && DECL_IMMEDIATE_FUNCTION_P (TREE_OPERAND (stmt, 0)) > - && !ADDR_EXPR_DENOTES_CALL_P (stmt)) > - { > - if (complain & tf_error) > - { > - error_at (EXPR_LOCATION (stmt), > - "taking address of an immediate function %qD", > - TREE_OPERAND (stmt, 0)); > - *stmt_p = build_zero_cst (TREE_TYPE (stmt)); > - } > - return error_mark_node; > - } > + if (!ADDR_EXPR_DENOTES_CALL_P (stmt)) > + decl = TREE_OPERAND (stmt, 0); > break; > - > default: > - break; > + return NULL_TREE; > } > > - return NULL_TREE; > -} > + if (!decl || TREE_CODE (decl) != FUNCTION_DECL) > + return NULL_TREE; > > -/* A wrapper around cp_fold_immediate_r. Return true if we found > - a non-constant immediate function, or taking the address of an > - immediate function. */ > + /* Fully escalate once all templates have been instantiated. What we're > + calling is not a consteval function but it may become one. This > + requires recursing; DECL may be promoted to consteval because it > + contains an escalating expression E, but E itself may have to be > + promoted first, etc. */ > + if (at_eof > 1 && unchecked_immediate_escalating_function_p (decl)) > + { > + /* Set before the actual walk to avoid endless recursion. */ > + DECL_ESCALATION_CHECKED_P (decl) = true; > + /* We're only looking for the first escalating expression. Let us not > + walk more trees than necessary, hence mce_unknown. */ > + cp_fold_immediate (&DECL_SAVED_TREE (decl), mce_unknown, decl); > + } > > -bool > -cp_fold_immediate (tree *tp, mce_value manifestly_const_eval) > -{ > - if (cxx_dialect <= cxx17) > - return false; > + /* [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." > > - fold_flags_t flags = ff_fold_immediate; > - if (manifestly_const_eval == mce_false) > - flags |= ff_mce_false; > + If we are in an immediate-escalating function, the immediate-escalating > + expression or conversion makes it an immediate function. So STMT does > + not need to produce a constant expression. */ > + if (DECL_IMMEDIATE_FUNCTION_P (decl)) > + { > + tree e = cxx_constant_value (stmt, tf_none); > + if (e == error_mark_node) > + { > + /* This takes care of, e.g., > + template > + constexpr int f(T t) > + { > + return id(t); > + } > + where id (consteval) causes f to be promoted. */ > + if (immediate_escalating_function_p (current_function_decl)) > + promote_function_to_consteval (current_function_decl); > + else if (complain & tf_error) > + { > + if (call_p) > + { > + auto_diagnostic_group d; > + location_t loc = cp_expr_loc_or_input_loc (stmt); > + error_at (loc, "call to consteval function %qE is " > + "not a constant expression", stmt); > + /* Explain why it's not a constant expression. */ > + *stmt_p = cxx_constant_value (stmt, complain); > + maybe_explain_promoted_consteval (loc, decl); > + } > + else if (!data->pset.add (stmt)) > + { > + taking_address_of_imm_fn_error (stmt, decl); > + *stmt_p = build_zero_cst (TREE_TYPE (stmt)); > + } > + /* If we're giving hard errors, continue the walk rather than > + bailing out after the first error. */ > + return NULL_TREE; > + } > + *walk_subtrees = 0; > + return stmt; > + } > + /* We've evaluated the consteval function call. */ > + if (call_p) > + *stmt_p = e; > + } > + /* We've encountered a function call that may turn out to be consteval > + later. Store its caller so that we can ensure that the call is > + a constant expression. */ > + else if (unchecked_immediate_escalating_function_p (decl)) > + { > + /* Make sure we're not inserting new elements while walking > + the deferred_escalating_exprs hash table; if we are, it's > + likely that a function wasn't properly marked checked for > + i-e expressions. */ > + gcc_checking_assert (at_eof <= 1); > + if (current_function_decl) > + remember_escalating_expr (current_function_decl); > + /* auto p = &f; in the global scope won't be ensconced in > + a function we could store for later at this point. (If there's > + no c_f_d at this point and we're dealing with a call, we should > + see the call when cp_fold_function __static_i_and_d.) */ > + else if (!call_p) > + remember_escalating_expr (stmt); > + } > > - cp_fold_data data (flags); > - return !!cp_walk_tree_without_duplicates (tp, cp_fold_immediate_r, &data); > + return NULL_TREE; > } > > /* Perform any pre-gimplification folding of C++ front end trees to > @@ -1178,11 +1346,19 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_) > *walk_subtrees = 0; > /* Don't return yet, still need the cp_fold below. */ > } > - cp_fold_immediate_r (stmt_p, walk_subtrees, data); > + else > + cp_fold_immediate_r (stmt_p, walk_subtrees, data); > } > > *stmt_p = stmt = cp_fold (*stmt_p, data->flags); > > + /* For certain trees, like +foo(), the cp_fold above will remove the +, > + and the subsequent tree walk would go straight down to the CALL_EXPR's > + operands, meaning that cp_fold_immediate_r would never see the > + CALL_EXPR. Ew :(. */ > + if (TREE_CODE (stmt) == CALL_EXPR && code != CALL_EXPR) > + cp_fold_immediate_r (stmt_p, walk_subtrees, data); > + > if (data->pset.add (stmt)) > { > /* Don't walk subtrees of stmts we've already walked once, otherwise > @@ -1304,6 +1480,44 @@ cp_fold_function (tree fndecl) > pass ff_mce_false. */ > cp_fold_data data (ff_genericize | ff_mce_false); > cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_r, &data, NULL); > + > + /* This is merely an optimization: if FNDECL has no i-e expressions, > + we'll not save c_f_d, and we can safely say that FNDECL will not > + be promoted to consteval. */ > + if (deferred_escalating_exprs > + && !deferred_escalating_exprs->contains (current_function_decl)) > + DECL_ESCALATION_CHECKED_P (fndecl) = true; > +} > + > +/* We've stashed immediate-escalating functions. Now see if they indeed > + ought to be promoted to consteval. */ > + > +void > +process_and_check_pending_immediate_escalating_fns () > +{ > + /* This will be null for -fno-immediate-escalation. */ > + if (!deferred_escalating_exprs) > + return; > + > + for (auto e : *deferred_escalating_exprs) > + if (TREE_CODE (e) == FUNCTION_DECL && !DECL_ESCALATION_CHECKED_P (e)) > + cp_fold_immediate (&DECL_SAVED_TREE (e), mce_false, e); > + > + /* We've escalated every function that could have been promoted to > + consteval. Check that we are not taking the address of a consteval > + function. */ > + for (auto e : *deferred_escalating_exprs) > + { > + if (TREE_CODE (e) == FUNCTION_DECL) > + continue; > + tree decl = (TREE_CODE (e) == PTRMEM_CST > + ? PTRMEM_CST_MEMBER (e) > + : TREE_OPERAND (e, 0)); > + if (DECL_IMMEDIATE_FUNCTION_P (decl)) > + taking_address_of_imm_fn_error (e, decl); > + } > + > + deferred_escalating_exprs = nullptr; > } > > /* Turn SPACESHIP_EXPR EXPR into GENERIC. */ > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index 6b3ce9d87da..fef80816c5f 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -2946,8 +2946,9 @@ struct GTY(()) lang_decl_fn { > unsigned maybe_deleted : 1; > unsigned coroutine_p : 1; > unsigned implicit_constexpr : 1; > + unsigned escalated_p : 1; > > - unsigned spare : 9; > + unsigned spare : 8; > > /* 32-bits padding on 64-bit host. */ > > @@ -3399,6 +3400,14 @@ struct GTY(()) lang_decl { > #define DECL_MAYBE_DELETED(NODE) \ > (LANG_DECL_FN_CHECK (NODE)->maybe_deleted) > > +/* Nonzero for FUNCTION_DECL means that this function's body has been > + checked for immediate-escalating expressions and maybe promoted. It > + does *not* mean the function is consteval. It must not be set in > + a function that was marked consteval by the user, so that we can > + distinguish between explicitly consteval functions and promoted consteval > + functions. */ > +#define DECL_ESCALATION_CHECKED_P(NODE) (LANG_DECL_FN_CHECK (NODE)->escalated_p) > + > /* True (in a FUNCTION_DECL) if NODE is a virtual function that is an > invalid overrider for a function from a base class. Once we have > complained about an invalid overrider we avoid complaining about it > @@ -5882,7 +5891,8 @@ extern GTY(()) vec *keyed_classes; > > > /* Nonzero if we're done parsing and into end-of-file activities. > - Two if we're done with front-end processing. */ > + 2 if all templates have been instantiated. > + 3 if we're done with front-end processing. */ > > extern int at_eof; > > @@ -6774,6 +6784,7 @@ extern tree perform_direct_initialization_if_possible (tree, tree, bool, > extern vec *resolve_args (vec*, tsubst_flags_t); > extern tree in_charge_arg_for_name (tree); > extern bool in_immediate_context (); > +extern bool immediate_invocation_p (tree); > extern tree build_cxx_call (tree, int, tree *, > tsubst_flags_t, > tree = NULL_TREE); > @@ -8415,7 +8426,9 @@ extern tree process_stmt_assume_attribute (tree, tree, location_t); > extern bool simple_empty_class_p (tree, tree, tree_code); > extern tree fold_builtin_source_location (const_tree); > extern tree get_source_location_impl_type (); > -extern bool cp_fold_immediate (tree *, mce_value); > +extern tree cp_fold_immediate (tree *, mce_value, > + tree = current_function_decl); > +extern void process_and_check_pending_immediate_escalating_fns (); > > /* in name-lookup.cc */ > extern tree strip_using_decl (tree); > diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc > index 9e666e5eece..bee84879023 100644 > --- a/gcc/cp/decl2.cc > +++ b/gcc/cp/decl2.cc > @@ -169,7 +169,9 @@ typedef hash_map one for init. The fini table is only ever used when !cxa_atexit. */ > static GTY(()) priority_map_t *static_init_fini_fns[2]; > > -/* Nonzero if we're done parsing and into end-of-file activities. */ > +/* Nonzero if we're done parsing and into end-of-file activities. > + 2 if all templates have been instantiated. > + 3 if we're done with front-end processing. */ > > int at_eof; > > @@ -4987,6 +4989,7 @@ c_parse_final_cleanups (void) > tree decl; > > locus_at_end_of_parsing = input_location; > + /* We're done parsing. */ > at_eof = 1; > > /* Bad parse errors. Just forget about it. */ > @@ -5252,6 +5255,9 @@ c_parse_final_cleanups (void) > reconsider = true; > } > > + /* All templates have been instantiated. */ > + at_eof = 2; > + > void *module_cookie = finish_module_processing (parse_in); > > lower_var_init (); > @@ -5294,7 +5300,11 @@ c_parse_final_cleanups (void) > if (static_init_fini_fns[true]) > for (auto iter : *static_init_fini_fns[true]) > iter.second = nreverse (iter.second); > - > + > + /* Now we've instantiated all templates. Now we can escalate the functions > + we squirreled away earlier. */ > + process_and_check_pending_immediate_escalating_fns (); > + > /* Then, do the Objective-C stuff. This is where all the > Objective-C module stuff gets generated (symtab, > class/protocol/selector lists etc). This must be done after C++ > @@ -5376,7 +5386,7 @@ c_parse_final_cleanups (void) > timevar_start (TV_PHASE_PARSING); > > /* Indicate that we're done with front end processing. */ > - at_eof = 2; > + at_eof = 3; > } > > /* Perform any post compilation-proper cleanups for the C++ front-end. > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc > index 785909c362a..3b1b5de5ea4 100644 > --- a/gcc/cp/error.cc > +++ b/gcc/cp/error.cc > @@ -478,7 +478,7 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args, > > /* Don't try to do this once cgraph starts throwing away front-end > information. */ > - if (at_eof >= 2) > + if (at_eof >= 3) > return; > > FOR_EACH_VEC_SAFE_ELT (typenames, i, t) > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc > index 33fcf396875..1b57fbe2124 100644 > --- a/gcc/cp/module.cc > +++ b/gcc/cp/module.cc > @@ -5683,6 +5683,8 @@ trees_out::lang_decl_bools (tree t) > WB (lang->u.fn.has_dependent_explicit_spec_p); > WB (lang->u.fn.immediate_fn_p); > WB (lang->u.fn.maybe_deleted); > + WB (lang->u.fn.escalated_p); > + /* We do not stream lang->u.fn.implicit_constexpr. */ > goto lds_min; > > case lds_decomp: /* lang_decl_decomp. */ > @@ -5751,6 +5753,8 @@ trees_in::lang_decl_bools (tree t) > RB (lang->u.fn.has_dependent_explicit_spec_p); > RB (lang->u.fn.immediate_fn_p); > RB (lang->u.fn.maybe_deleted); > + RB (lang->u.fn.escalated_p); > + /* We do not stream lang->u.fn.implicit_constexpr. */ > goto lds_min; > > case lds_decomp: /* lang_decl_decomp. */ > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > index 7265201e036..924a20973b4 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -11107,7 +11107,7 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc) > if (tinst_depth >= max_tinst_depth) > { > /* Tell error.cc not to try to instantiate any templates. */ > - at_eof = 2; > + at_eof = 3; > fatal_error (input_location, > "template instantiation depth exceeds maximum of %d" > " (use %<-ftemplate-depth=%> to increase the maximum)", > diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc > index bf8ffaa7e75..8e4cfae08aa 100644 > --- a/gcc/cp/typeck.cc > +++ b/gcc/cp/typeck.cc > @@ -7269,11 +7269,9 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain) > complain); > } > > - /* For addresses of immediate functions ensure we have EXPR_LOCATION > - set for possible later diagnostics. */ > + /* Ensure we have EXPR_LOCATION set for possible later diagnostics. */ > if (TREE_CODE (val) == ADDR_EXPR > - && TREE_CODE (TREE_OPERAND (val, 0)) == FUNCTION_DECL > - && DECL_IMMEDIATE_FUNCTION_P (TREE_OPERAND (val, 0))) > + && TREE_CODE (TREE_OPERAND (val, 0)) == FUNCTION_DECL) > SET_EXPR_LOCATION (val, input_location); > > return val; > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index 2b51ff304f6..681e3f3f466 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -219,6 +219,7 @@ in the following sections. > -fno-elide-constructors > -fno-enforce-eh-specs > -fno-gnu-keywords > +-fno-immediate-escalation > -fno-implicit-templates > -fno-implicit-inline-templates > -fno-implement-inlines > @@ -3386,6 +3387,39 @@ word as an identifier. You can use the keyword @code{__typeof__} instead. > This option is implied by the strict ISO C++ dialects: @option{-ansi}, > @option{-std=c++98}, @option{-std=c++11}, etc. > > +@opindex fno-immediate-escalation > +@opindex fimmediate-escalation > +@item -fno-immediate-escalation > +Do not enable immediate function escalation whereby certain functions > +can be promoted to consteval, as specified in P2564R3. For example: > + > +@example > +consteval int id(int i) @{ return i; @} > + > +constexpr int f(auto t) > +@{ > + return t + id(t); // id causes f to be promoted to consteval > +@} > + > +void g(int i) > +@{ > + f (3); > +@} > +@end example > + > +compiles in C++20: @code{f} is an immediate-escalating function (due to > +the @code{auto} it is a function template and is declared @code{constexpr}) > +and @code{id(t)} is an immediate-escalating expression, so @code{f} is > +promoted to @code{consteval}. Consequently, the call to @code{id(t)} > +is in an immediate context, so doesn't have to produce a constant (that > +is the mechanism allowing consteval function composition). However, > +with @option{-fno-immediate-escalation}, @code{f} is not promoted to > +@code{consteval}, and since the call to consteval function @code{id(t)} > +is not a constant expression, the compiler rejects the code. > + > +This option is turned on by default; it is only effective in C++20 mode > +or later. > + > @opindex fimplicit-constexpr > @item -fimplicit-constexpr > Make inline functions implicitly constexpr, if they satisfy the > diff --git a/gcc/testsuite/g++.dg/cpp23/consteval-if10.C b/gcc/testsuite/g++.dg/cpp23/consteval-if10.C > index 4c0523fe1d0..b8709beba85 100644 > --- a/gcc/testsuite/g++.dg/cpp23/consteval-if10.C > +++ b/gcc/testsuite/g++.dg/cpp23/consteval-if10.C > @@ -2,6 +2,9 @@ > // { dg-do compile { target c++20 } } > // { dg-options "" } > > +// We used to give errors but the lambdas are now promoted to consteval > +// and are in a immediate function context, so no errors. > + > consteval int foo (int x) { return x; } > > constexpr int > @@ -10,7 +13,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; > @@ -23,7 +26,7 @@ baz (T x) > T 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/cpp23/consteval-if2.C b/gcc/testsuite/g++.dg/cpp23/consteval-if2.C > index b2c5472b7de..3b258711ce6 100644 > --- a/gcc/testsuite/g++.dg/cpp23/consteval-if2.C > +++ b/gcc/testsuite/g++.dg/cpp23/consteval-if2.C > @@ -33,7 +33,7 @@ baz (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 "not a constant expression" } > } > else > { > @@ -45,11 +45,11 @@ baz (int x) > } > else > { > - r += foo (8 * x); // { dg-error "'x' is not a constant expression" } > + r += foo (8 * x); // { dg-error "is not a constant expression" } > } > if ! consteval // { dg-warning "'if consteval' only available with" "" { target c++20_only } } > { > - r += foo (32 * x);// { dg-error "'x' is not a constant expression" } > + r += foo (32 * x);// { dg-error "not a constant expression" } > } > if consteval // { dg-warning "'if consteval' only available with" "" { target c++20_only } } > { > @@ -98,7 +98,7 @@ corge (T x) > T 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); > } > else > { > @@ -110,11 +110,11 @@ corge (T x) > } > else > { > - r += foo (8 * x); // { dg-error "is not a constant expression" } > + r += foo (8 * x); > } > if ! consteval // { dg-warning "'if consteval' only available with" "" { target c++20_only } } > { > - r += foo (32 * x);// { dg-error "is not a constant expression" } > + r += foo (32 * x); > } > if consteval // { dg-warning "'if consteval' only available with" "" { target c++20_only } } > { > @@ -126,5 +126,5 @@ corge (T x) > int > garply (int x) > { > - return corge (x); > + return corge (x); // { dg-error "is not a constant expression" } > } > diff --git a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C > index 9e29b01adc1..2b21bd1bc0d 100644 > --- a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C > +++ b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C > @@ -480,8 +480,8 @@ > > #ifndef __cpp_consteval > # error "__cpp_consteval" > -#elif __cpp_consteval != 201811 > -# error "__cpp_consteval != 201811" > +#elif __cpp_consteval != 202211L > +# error "__cpp_consteval != 202211L" > #endif > > #ifndef __cpp_concepts > diff --git a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C > index 6244f8fdfe4..4507ea07d1c 100644 > --- a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C > +++ b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C > @@ -480,8 +480,8 @@ > > #ifndef __cpp_consteval > # error "__cpp_consteval" > -#elif __cpp_consteval != 201811 > -# error "__cpp_consteval != 201811" > +#elif __cpp_consteval != 202211L > +# error "__cpp_consteval != 202211L" > #endif > > #ifndef __cpp_concepts > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-memfn1.C b/gcc/testsuite/g++.dg/cpp2a/consteval-memfn1.C > index 46eed13446d..ca923519f98 100644 > --- a/gcc/testsuite/g++.dg/cpp2a/consteval-memfn1.C > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-memfn1.C > @@ -20,10 +20,13 @@ template > void VerifyHash(fixed_string s) { > s.size(0); // { dg-bogus "" } > s.size(-1); // { dg-message "expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > s.size_static(0); // { dg-bogus "" } > s.size_static(-1); // { dg-message "expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > fixed_string::size_static(0); // { dg-bogus "" } > fixed_string::size_static(-1); // { dg-message "expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > s(); // { dg-bogus "" } > } > > 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..5e7b208113f > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop1.C > @@ -0,0 +1,169 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// Some of these were cribbed from clang's cxx2b-consteval-propagate.cpp. > + > +consteval int id(int i) { return i; } > + > +template > +constexpr int > +f0 (T t) > +{ > + // OK, f0 promoted to consteval. > + return id (t); // { dg-message "immediate-escalating expression .id\\(t\\)." } > +} > + > +constexpr auto a0 = f0 (3); > + > +// As a consequence of f0 being promoted to an immediate function, we > +// can't take its address. > +auto p0 = &f0; // { dg-error "taking address of an immediate function" } > + > +template > +constexpr int > +f1 (T t) > +{ > + // OK, f1 promoted to consteval. > + return t + id (t); // { dg-message "immediate-escalating expression .id\\(t\\)." } > +} > + > +constexpr auto a1 = f1 (3); > + > +// As a consequence of f1 being promoted to an immediate function, we > +// can't take its address. > +auto p1 = &f1; // { dg-error "taking address of an immediate function" } > + > +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 = &f2; > + > +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" } > +} > + > +auto p3 = &f3; > + > +template > +constexpr int > +f4 (T t) > +{ > + auto p = id; // { dg-message "immediate-escalating expression .id." } > + (void) p; > + return t; > +} > + > +auto p6 = &f4; // { dg-error "taking address of an immediate function" } > + > +static_assert (f4 (42) == 42); > + > +// Constructors. > +consteval int zero (int) > +{ > + return 0; > +} > + > +struct A { > + // A::A(auto) promoted to consteval. > + constexpr A(auto i) { zero (i); } > +}; > + > +constexpr void > +f5 (auto i) > +{ > + A a{i}; > +} > + > +constexpr void > +f5_nt (int i) > +{ > + A a{i}; // { dg-error "call to consteval function|not a constant" } > +} > + > +void > +f6 () > +{ > + f5 (0); > +} > + > +struct B { > + constexpr B(int) { } > +}; > + > +B b1(f0((f1(7)))); > + > +template > +constexpr int cid(T t) { return t; } > + > +auto p4 = &cid; > +auto p5 = &cid; > + > +int g = 7; // { dg-message ".int g. is not const" } > + > +B b2(f0(cid(g))); // { dg-error "call to consteval function|not usable" } > + > +struct C { > + consteval C (int) {}; > +}; > + > +constexpr int > +f7 (auto t) > +{ > + C c(t); // { dg-message "immediate-escalating expression .c.C::C\\(t\\)." } > + return 0; > +} > + > +int i1 = f7 (g); // { dg-error "call to consteval function|not usable" } > + > +struct Y { > + int y; > + int x = id (y); > + consteval Y (int i) : y (id (i)) {} > +}; > + > +Y y1(1); > +Y y2(g); // { dg-error "call to consteval function|not usable" } > + > +struct Y2 { > + int y; > + int x = id (y); > + constexpr Y2 (auto i) : y (id (i)) {} > +}; > + > +Y2 y3(1); > +Y2 y4(g); // { dg-error "call to consteval function|not usable" } > + > +auto l1 = [](int i) constexpr { > + int t = id (i); > + return id (0); > +}; > + > +int (*pl1)(int) = l1; // { dg-error "call to consteval function|returns address of immediate function" } > + > +auto l2 = [](int i) { > + int t = id (i); > + return id (0); > +}; > + > +int (*pl2)(int) = l2; // { dg-error "call to consteval function|returns address of immediate function" } > + > +// Not defined = won't produce a constant expression. > +consteval int undef (); // { dg-warning "used but never defined" } > + > +struct S { > + int a = [] { return undef (); }(); > +}; > + > +struct S2 { // { dg-error "used before its definition" } > + int a = [] (int u = undef ()) { > + return u; > + }(); > +} s2; // { dg-error "call to consteval function" } > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop10.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop10.C > new file mode 100644 > index 00000000000..4e33e6e3d0e > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop10.C > @@ -0,0 +1,41 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// Test default arguments. > + > +consteval int id (int i) { return i; } > + > +template > +constexpr int > +f1 (int i = id (42)) > +{ > + return i; > +} > + > +int non_const; // { dg-message ".int non_const. is not const" } > + > +template > +constexpr int > +f2 (int i = id (non_const)) > +{ > + return i; > +} > + > +constexpr int > +f3 (auto) > +{ > + return f2(); // { dg-message "contains an immediate-escalating expression .id\\(non_const\\)." } > +} > + > +auto a = &f3; // { dg-error "taking address of an immediate function" } > + > +void > +g (int i) > +{ > + f1 (42); > + f1 (i); > + f1 (); > + f2 (42); > + f2 (i); > + f2 (); // { dg-error "call to consteval function .id\\(non_const\\). is not a constant expression" } > +// { dg-error ".non_const. is not usable in a constant expression" "" { target *-*-* } .-1 } > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop11.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop11.C > new file mode 100644 > index 00000000000..aca9675cd53 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop11.C > @@ -0,0 +1,49 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// { dg-options "-fdiagnostics-show-caret" } > +// Test diagnostic. > + > +consteval int id (int i) { return i; } > +constexpr int foo (int i ) { return i; } > + > +constexpr int > +foobar (auto i) > +{ > + return i + id (i); > + /* { dg-begin-multiline-output "" } > + return i + id (i); > + ~~~^~~ > + { dg-end-multiline-output "" } */ > +} > + > +void > +g (int x) > +{ > + foobar (x); // { dg-error "10:call to consteval function .foobar\\(x\\). is not a constant expression" } > +// { dg-error ".x. is not a constant expression" "" { target *-*-* } .-1 } > + /* { dg-begin-multiline-output "" } > +foobar (x); > + ~~~~~~~^~~ > + { dg-end-multiline-output "" } */ > +} > + > +constexpr int > +f2 (auto i) > +{ > + auto p = &id; > + /* { dg-begin-multiline-output "" } > + auto p = &id; > + ^~~ > + { dg-end-multiline-output "" } */ > + return p (i); > +} > + > +void > +g2 (int x) > +{ > + f2 (x); // { dg-error "6:call to consteval function .f2\\(x\\). is not a constant expression|not a constant expression" } > + /* { dg-begin-multiline-output "" } > +f2 (x); > + ~~~^~~ > + { dg-end-multiline-output "" } */ > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop12.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop12.C > new file mode 100644 > index 00000000000..2949ab83af8 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop12.C > @@ -0,0 +1,30 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > + > +consteval int > +zero (int) > +{ > + return 0; > +} > + > +constexpr int > +f (auto i) > +{ > + return zero (i); > +} > + > +constexpr int > +g (auto) > +{ > + // This call is a constant expression, so don't promote g. > + return f (42); > +} > + > +void > +do_test () > +{ > + g (2); > +} > + > +// Must work. > +auto q = &g; > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop13.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop13.C > new file mode 100644 > index 00000000000..6c20b98a87c > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop13.C > @@ -0,0 +1,23 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// Verify we don't recurse endlessly while determining whether a function > +// should be propagated to consteval. > + > +consteval int id (int i) { return i; } > + > +constexpr int f2 (auto); > + > +constexpr int > +f1 (auto i) > +{ > + return f2 (i); > +} > + > +constexpr int > +f2 (auto i) > +{ > + return f1 (i); > +} > + > +auto p = &f1; > +auto q = &f2; > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop14.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop14.C > new file mode 100644 > index 00000000000..cdc1f6dc862 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop14.C > @@ -0,0 +1,78 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// Test more CALL_EXPRs in a function, some of which are escalating. > + > +consteval int id (int i) { return i; } > +constexpr int neg (int i) { return -i; } > +constexpr int foo (auto i) { return id (i); } > + > +constexpr int > +f1 (auto i) > +{ > + auto x = id (i); // { dg-message "promoted to an immediate function because its body contains an immediate-escalating expression .id\\(i\\)." } > + auto y = neg (i); > + return x + y; > +} > + > +constexpr int > +f2 (auto i) > +{ > + return neg (id (i)); // { dg-message "promoted to an immediate function because its body contains an immediate-escalating expression .id\\(i\\)." } > +} > + > +constexpr int > +f3 (auto i) > +{ > + auto x = i + neg (neg (neg (id (neg (neg (i)))))); // { dg-message "promoted to an immediate function because its body contains an immediate-escalating expression .id\\(neg\\(neg\\(i\\)\\)\\)." } > + return x; > +} > + > +constexpr int > +f4 (auto i) > +{ > + return i + neg ((id (2 * i) + neg (i)) / 2); // { dg-message "promoted to an immediate function because its body contains an immediate-escalating expression .id\\(\\(i \\* 2\\)\\)." } > +} > + > +constexpr int > +f5 (auto i) > +{ > + (void) neg (i); > + (void) neg (i); > + (void) neg (i); > + (void) neg (i); > + (void) neg (i); > + (void) neg (i); > + (void) +id (i); // { dg-message "promoted to an immediate function because its body contains an immediate-escalating expression .id\\(i\\)." } > + (void) neg (i); > + return i; > +} > + > +constexpr int > +f6 (auto i) > +{ > + auto x = neg (i + foo (i)); // { dg-message "promoted to an immediate function because its body contains an immediate-escalating expression .foo\\(i\\)." } > + return x; > +} > + > +void > +g (int i) > +{ > + f1 (i); // { dg-error "call to consteval function .f1\\(i\\). is not a constant expression" } > +// { dg-error ".i. is not a constant expression" "" { target *-*-* } .-1 } > + f1 (42); > + f2 (i); // { dg-error "call to consteval function .f2\\(i\\). is not a constant expression" } > +// { dg-error ".i. is not a constant expression" "" { target *-*-* } .-1 } > + f2 (42); > + f3 (i); // { dg-error "call to consteval function .f3\\(i\\). is not a constant expression" } > +// { dg-error ".i. is not a constant expression" "" { target *-*-* } .-1 } > + f3 (42); > + f4 (i); // { dg-error "call to consteval function .f4\\(i\\). is not a constant expression" } > +// { dg-error ".i. is not a constant expression" "" { target *-*-* } .-1 } > + f4 (42); > + f5 (i); // { dg-error "call to consteval function .f5\\(i\\). is not a constant expression" } > +// { dg-error ".i. is not a constant expression" "" { target *-*-* } .-1 } > + f5 (42); > + f6 (i); // { dg-error "call to consteval function .f6\\(i\\). is not a constant expression" } > +// { dg-error ".i. is not a constant expression" "" { target *-*-* } .-1 } > + f6 (42); > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop15.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop15.C > new file mode 100644 > index 00000000000..3341c510a9f > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop15.C > @@ -0,0 +1,107 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// { dg-options "-Wno-c++23-extensions" } > + > +consteval int id (int i) { return i; } > + > +constexpr int > +f1 (auto i) > +{ > + auto p = &id; // { dg-message "promoted to an immediate function because its body contains an immediate-escalating expression .id." } > + (void) p; > + return i; > +} > + > +constexpr int > +f2 (auto i) > +{ > + return f1 (i); > +} > + > +constexpr int > +f3 (auto i) > +{ > + return f2 (i); > +} > + > +constexpr int > +f4 (auto i) > +{ > + return f3 (i); > +} > + > +constexpr int > +f5 (auto i) > +{ > + return f4 (i); // { dg-message "promoted to an immediate function because its body contains an immediate-escalating expression .f4\\(i\\)." } > +} > + > +constexpr int > +f6 (auto) > +{ > + // This call is a constant expression, so don't promote f6. > + return f4 (42); > +} > + > +constexpr int > +f7 (auto i) > +{ > + if consteval { > + auto p = &id; > + (void) p; > + } > + return i; > +} > + > +constexpr int > +f8 (auto i) > +{ > + if not consteval { > + (void) 0; > + } else { > + auto p = &id; > + (void) p; > + } > + return i; > +} > + > +constexpr int > +f9 (auto i) > +{ > + if consteval { > + return id(i); > + } > + return i; > +} > + > +constexpr int > +f10 (auto i) > +{ > + if not consteval { > + (void) 0; > + } else { > + return id(i); > + } > + return i; > +} > + > +void > +g (int non_const) > +{ > + f1 (42); > + f1 (non_const); // { dg-error "call to consteval function .f1\\(non_const\\). is not a constant expression" } > +// { dg-error ".non_const. is not a constant expression" "" { target *-*-* } .-1 } > + f5 (42); > + f5 (non_const); // { dg-error "call to consteval function .f5\\(non_const\\). is not a constant expression" } > +// { dg-error ".non_const. is not a constant expression" "" { target *-*-* } .-1 } > + f6 (42); > + f6 (non_const); > + f7 (42); > + f7 (non_const); > + f8 (42); > + f8 (non_const); > + f9 (42); > + f9 (non_const); > + f10 (42); > + f10 (non_const); > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop16.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop16.C > new file mode 100644 > index 00000000000..7952d495d8b > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop16.C > @@ -0,0 +1,73 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// Test unevaluated operands. > + > +consteval int id (int i) { return i; } > + > +constexpr int > +f1 (auto i) > +{ > + // Unevaluated operand -> don't promote. > + auto p = sizeof (&id); > + (void) p; > + return i; > +} > + > +constexpr int > +f2 (auto i) > +{ > + // Unevaluated operand -> don't promote. > + auto p = noexcept (id); > + (void) p; > + return i; > +} > + > +constexpr int > +f3 (auto i) > +{ > + // Unevaluated operand -> don't promote. > + auto p = noexcept (id (i)); > + (void) p; > + return i; > +} > + > +constexpr int > +f4 (auto i) > +{ > + // Unevaluated operand -> don't promote. > + decltype(id) p; > + (void) p; > + return i; > +} > + > +constexpr int > +f5 (auto i) > +{ > + // Unevaluated operand -> don't promote. > + __extension__ auto p = alignof (id (i)); > + (void) p; > + return i; > +} > + > +constexpr int > +f6 (auto i) requires requires { id (i); } > +{ > + return i; > +} > + > +void > +g (int non_const) > +{ > + f1 (42); > + f1 (non_const); > + f2 (42); > + f2 (non_const); > + f3 (42); > + f3 (non_const); > + f4 (42); > + f4 (non_const); > + f5 (42); > + f5 (non_const); > + f6 (42); > + f6 (non_const); > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop17.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop17.C > new file mode 100644 > index 00000000000..47ec9b60b6c > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop17.C > @@ -0,0 +1,17 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// { dg-options "-fno-immediate-escalation" } > + > +consteval int id(int i) { return i; } > + > +constexpr int > +f (auto i) > +{ > + return id (i); // { dg-error "not a constant expression" } > +} > + > +int > +g () > +{ > + return f (42); > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop18.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop18.C > new file mode 100644 > index 00000000000..a18106f8e0f > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop18.C > @@ -0,0 +1,20 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > + > +consteval int id(int i) { return i; } > + > +constexpr int > +f (auto t) > +{ > + return t + id (t); > +} > + > +constexpr int > +f2 (auto t) > +{ > + return t + f(t); // { dg-message "immediate-escalating expression .f\\(t\\)." } > +} > + > +int z; // { dg-message "not const" } > +auto y1 = f2 (42); > +auto y2 = f2 (z); // { dg-error "value of .z. is not usable in a constant expression|call to consteval function" } > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop19.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop19.C > new file mode 100644 > index 00000000000..3ceb05e41f4 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop19.C > @@ -0,0 +1,7 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > + > +consteval int g(int p) { return p; } > +template constexpr auto f(T) { return g; } > +int r = f(1)(2); // proposed ok > +int s = f(1)(2) + r; // { dg-error "call to consteval function|returns address of immediate function" } > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop2.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop2.C > new file mode 100644 > index 00000000000..30129a4a266 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop2.C > @@ -0,0 +1,90 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// Testcase from P2564R3. > + > +consteval int id(int i) { return i; } > +constexpr char id(char c) { return c; } > + > +template > +constexpr int f(T t) { > + return t + id(t); // { dg-message "immediate-escalating expression .id\\(t\\)." } > +} > + > +auto a = &f; // OK, f is not an immediate function > +auto b = &f; // { dg-error "taking address of an immediate function" } > + > +static_assert(f(3) == 6); // OK > + > +template > +constexpr int g(T t) { // g is not an immediate function > + return t + id(42); // because id(42) is already a constant > +} > + > +template > +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 > + > +int x = 0; > + > +template > +constexpr T h(T t = id(x)) { // h is not an immediate function > + return t; > +} > + > +template > +constexpr T hh() { // hh is an immediate function > + return h(); // { dg-error "the value of .x. is not usable in a constant expression" } > +// { dg-message "immediate-escalating expression .id\\(x\\)." "" { target *-*-* } .-1 } > +} > + > +int i = hh(); // { dg-error "call to consteval function|called in a constant expression" } > + // error: hh() is an immediate-escalating expression > + // outside of an immediate-escalating function > +struct A { > + int x; > + int y = id(x); > +}; > + > +// [expr.const]#example-9 says: > +// k is not an immediate function because A(42) is a > +// constant expression and thus not immediate-escalating > +// In the evaluation of A(42), the member x has just been initialized > +// to constant 42. And A(42) is constant-evaluated because "An aggregate > +// initialization is an immediate invocation if it evaluates a default > +// member initializer that has a subexpression that is an > +// immediate-escalating expression." > +template > +constexpr int k(int) { > + return A(42).y; > +} > + > +int > +test (int i) > +{ > + int r = g (42) + g(i); > + int t = k(42) > + + k(i); // { dg-bogus "call to|constant" "" { xfail *-*-* } } > + return r + t; > +} > + > +// Just like above, but make the call to id(x) actually a constant. > +struct A2 { > + static constexpr int x = 42; > + int y = id(x); > +}; > + > +template > +constexpr int k2(int) { > + return A2(42).y; > +} > + > +int > +test2 (int i) > +{ > + return k2(42) + k2(i); > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop20.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop20.C > new file mode 100644 > index 00000000000..f1bb08e2dba > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop20.C > @@ -0,0 +1,21 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// { dg-options "-Wno-c++23-extensions" } > + > +consteval int id(int i) { return i; } > + > +constexpr int > +f (auto i) > +{ > + return id (i); > +} > + > +void > +g () > +{ > + auto p = &f; // { dg-error "taking address" } > + decltype(&f) x; > + if consteval { > + auto q = &f; > + } > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop3.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop3.C > new file mode 100644 > index 00000000000..f181cb32942 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop3.C > @@ -0,0 +1,27 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// Cribbed from clang's cxx2b-consteval-propagate.cpp. > + > +consteval int id(int i) { return i; } > + > +template > +constexpr int f(T t); > + > +auto a1 = &f; > +auto b1 = &f; > + > +template > +constexpr int f(T t) { > + return id(0); > +} > + > +template > +constexpr int f2(T); > + > +auto a2 = &f2; // { dg-error "taking address" } > +auto b2 = &f2; // { dg-error "taking address" } > + > +template > +constexpr int f2(T t) { > + return id(t); > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop4.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop4.C > new file mode 100644 > index 00000000000..3a2e09b17b0 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop4.C > @@ -0,0 +1,30 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// From clang's cxx2b-consteval-propagate.cpp. This test ICEd when I worked on > +// P2564. > + > +consteval int f (int); > + > +struct S { > + int a = 0; > + int b = f (a); > +}; > + > +constexpr bool > +g (auto i) > +{ > + S s{i}; > + return s.b == 2 *i; > +} > + > +consteval int > +f (int i) > +{ > + return 2 * i; > +} > + > +void > +test () > +{ > + static_assert(g(42)); > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop5.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop5.C > new file mode 100644 > index 00000000000..3bd1b9d1674 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop5.C > @@ -0,0 +1,27 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > + > +consteval int f (int i) { return i; } > + > +struct S { > + int x = f(42); > +}; > + > +constexpr S > +immediate (auto) > +{ > + return S{}; > +} > + > +void > +g () > +{ > + immediate (0); > +} > + > +consteval void > +test () > +{ > + constexpr S s = immediate(0); > + static_assert(s.x == 42); > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop6.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop6.C > new file mode 100644 > index 00000000000..93ed398d9bf > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop6.C > @@ -0,0 +1,59 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// From cxx2b-consteval-propagate.cpp. > + > +void side_effect(); > + > +consteval int > +f (int x) > +{ > + if (!x) > + side_effect(); // { dg-error "call to non-.constexpr. function" } > + return x; > +} > + > +struct SS { > + int y = f(1); > + int x = f(0); > + SS(); > +}; > +SS::SS(){} // { dg-error "call to consteval function" } > + > +consteval int > +f2 (int x) > +{ > + if (!__builtin_is_constant_evaluated ()) > + side_effect(); > + return x; > +} > + > +struct S2 { > + int x = f2(0); > + constexpr S2(); > +}; > + > +constexpr S2::S2(){} > +S2 s = {}; > +constinit S2 s2 = {}; > + > +struct S3 { > + int x = f2(0); > + S3(); > +}; > +S3::S3(){} > + > +consteval int undef (int x); // { dg-warning "never defined" } > + > +struct X { > + int a = sizeof(undef(0)); > + int x = undef(0); > + > + X() = default; // { dg-error "modification of .x. is not a constant expression" } > +}; > + > +void > +test () > +{ > + [[maybe_unused]] X x; // { dg-error "call to consteval function" } > +// { dg-message "promoted to an immediate function" "" { target *-*-* } .-1 } > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop7.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop7.C > new file mode 100644 > index 00000000000..118cf576f14 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop7.C > @@ -0,0 +1,76 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// The problem here was that while parsing, we first process calling > +// 'f' from 'g' but only when instantiating 'f' do we promote 'f' > +// to consteval. When the var we're initializing is marked constexpr, > +// store_init_value detects the problem that we're calling a consteval > +// function with non-const argument. > + > +consteval int id(int i) { return i; } > + > +// Don't let the instantiations confuse us, e.g. instantiating a fn > +// prior to entering 'g'. > +template > +constexpr int f1(T t) { return id (t); } > + > +template > +constexpr int f2(T t) { return id (t); } > + > +template > +constexpr int f3(T t) { return id (t); } > + > +template > +constexpr int f4(T t) { return id (t); } > + > +template > +constexpr int f5(T t) { return id (t); } > + > +template > +constexpr int f6(T t) { return id (t); } > + > +template > +constexpr int f7(T t) { return id (t); } > + > +template > +constexpr int f8(T t) { return id (t); } > + > +template > +constexpr int f9(T t) { return id (t); } > + > +template > +constexpr int f10(T t) { return id (t); } > + > +template > +constexpr int g1(T t) { auto p = id; return p (t); } > + > +int non_const; > + > +auto a1 = f1 (non_const); // { dg-error "call to consteval function|not usable" } > +constexpr auto a2 = f2 (non_const); // { dg-error "not a constant|not usable" } > +auto a3 = f3 (42); > +constexpr auto a4 = f4 (42); > + > +void > +g () > +{ > + auto a5 = f5 (non_const); // { dg-error "not a constant|not usable" } > + constexpr auto a6 = f6 (non_const); // { dg-error "not usable" } > + auto a7 = f7 (42); > + constexpr auto a8 = f8 (42); > + (void) f9 (non_const); // { dg-error "not a constant|not usable" } > + (void) f10 (42); > + (void) g1 (non_const); // { dg-error "not a constant|not usable" } > +} > + > +struct S { > + int y; > + int x = id (y); > + // Promoted to consteval. > + template > + constexpr S(T t) : y (id (t)) {} > +}; > + > +S s1(1); > +S s2(non_const); // { dg-error "call to consteval function|not usable" } > +constexpr S s3(1); > +constexpr S s4(non_const); // { dg-error "not usable" } > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop8.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop8.C > new file mode 100644 > index 00000000000..080fc76f26e > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop8.C > @@ -0,0 +1,82 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > +// { dg-options "-Wno-c++23-extensions" } > + > +consteval int zero (int) > +{ > + return 0; > +} > + > +struct A { > + // A::A(auto) promoted to consteval. > + constexpr A(auto i) { zero (i); } > +}; > + > +// 'f1' is an immediate function because its body contains a call to an > +// immediate constructor 'A' and that call is not a constant expression > +constexpr void > +f1 (auto i) > +{ > + A a{i}; > +} > + > +// 'f2' is an immediate function because its body contains a call to an > +// immediate constructor 'A' and that call is not a constant expression > +constexpr void > +f2 (auto i) > +{ > + A a{i}; > +} > + > +void > +f3 (int i) > +{ > + A a{i}; // { dg-error "not a constant expression" } > +} > + > +inline void > +f7 (int i) > +{ > + A a{i}; // { dg-error "not a constant expression" } > +} > + > +constexpr void > +f8 (int i) > +{ > + A a{i}; // { dg-error "not a constant expression" } > +} > + > +/* "An expression or conversion is immediate-escalating if it is not initially > + in an immediate function context" but this one is, so we do *not* promote > + f4 to consteval. */ > +constexpr void > +f4 (auto i) > +{ > + if consteval { > + A a{i}; > + } > +} > + > +constexpr void > +f5 (auto i) > +{ > + if not consteval { > + (void) 0; > + } else { > + A a{i}; > + } > +} > + > +void > +f6 (int x) > +{ > + f1 (0); > + f1 (x); // { dg-error "not a constant expression" } > + f2 (0); > + f2 (x); // { dg-error "not a constant expression" } > + f3 (0); > + f4 (x); > + f4 (0); > + f5 (x); > + f5 (0); > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop9.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop9.C > new file mode 100644 > index 00000000000..9c4a23389ce > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop9.C > @@ -0,0 +1,67 @@ > +// P2564R3 > +// { dg-do compile { target c++20 } } > + > +consteval int > +zero (int) > +{ > + return 0; > +} > + > +constexpr int > +f1 (auto i) > +{ > + return zero (i); > +} > + > +constexpr int > +f2 (auto i) > +{ > + return f1 (i); > +} > + > +constexpr int > +f3 (auto i) > +{ > + return f2 (i); > +} > + > +constexpr int > +f4 (auto i) > +{ > + return f3 (i); > +} > + > +constexpr int > +f5 (auto i) > +{ > + return f4 (i); > +} > + > +constexpr int > +f6 (auto) > +{ > + // This call is a constant expression, so don't promote f6. > + return f5 (42); > +} > + > +constexpr int > +f7 (auto) > +{ > + // This call is a constant expression, so don't promote f7. > + return zero (42); > +} > + > +auto p1 = &f5; // { dg-error "taking address" } > +static auto p2 = &f4; // { dg-error "taking address" } > +auto p3 = &f6; > +static auto p4 = &f6; > +auto p5 = &f7; > +static auto p6 = &f7; > + > +void > +g () > +{ > + static auto q1 = &f4; // { dg-error "taking address" } > + static auto q2 = &f6; > + static auto q3 = &f7; > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval11.C b/gcc/testsuite/g++.dg/cpp2a/consteval11.C > index 05cecea4502..c2ee3c7a82a 100644 > --- a/gcc/testsuite/g++.dg/cpp2a/consteval11.C > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval11.C > @@ -8,9 +8,11 @@ constexpr int a = bar (1); > constexpr int b = bar (2); // { dg-message "in 'constexpr' expansion of" } > constexpr int c = 0 ? bar (3) : 1; > const int d = bar (4); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > const int e = 0 ? bar (5) : 1; > int f = bar (1); > int g = bar (6); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > int h = 0 ? bar (7) : 1; > > void > @@ -20,25 +22,35 @@ foo () > constexpr int b = bar (2); // { dg-message "in 'constexpr' expansion of" } > constexpr int c = 0 ? bar (3) : 1; > const int d = bar (4); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > const int e = 0 ? bar (5) : 1; > int f = bar (1); > int g = bar (6); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > int h = 0 ? bar (7) : 1; // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > h += 0 ? bar (8) : 1; // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > if (0) > bar (9); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > else > bar (10); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > if (1) > bar (11); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > else > bar (12); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > if constexpr (0) > bar (13); > else > bar (14); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > if constexpr (1) > bar (15); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > else > bar (16); > } > @@ -121,18 +133,24 @@ quux () > { > if (0) > bar ((T) 2); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > else > bar ((T) 3); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > if (1) > bar ((T) 4); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > else > bar ((T) 5); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > if constexpr (0) > bar ((T) 6); > else > bar ((T) 7); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > if constexpr (1) > bar ((T) 8); // { dg-message "in 'constexpr' expansion of" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > else > bar ((T) 9); > } > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval3.C b/gcc/testsuite/g++.dg/cpp2a/consteval3.C > index 9efac8c8eae..1199e9db623 100644 > --- a/gcc/testsuite/g++.dg/cpp2a/consteval3.C > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval3.C > @@ -16,8 +16,8 @@ consteval auto [ b, c ] = S (); // { dg-error "structured binding declaration c > int f5 (consteval int x) { return x; } // { dg-error "a parameter cannot be declared 'consteval'" } > consteval int f6 (int x) { return x; } > int d = 6; // { dg-message "'int d' is not const" } > -int e = f6 (d); // { dg-error "the value of 'd' is not usable in a constant expression" } > -constexpr int f7 (int x) { return f6 (x); } // { dg-error "'x' is not a constant expression" } > +int e = f6 (d); // { dg-error "the value of 'd' is not usable in a constant expression|call to consteval function" } > +constexpr int f7 (int x) { return f6 (x); } // { dg-error "'x' is not a constant expression|call to consteval function" } > constexpr int f = f7 (5); > using fnptr = int (int); > fnptr *g = f6; // { dg-error "taking address of an immediate function 'consteval int f6\\(int\\)'" } > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval34.C b/gcc/testsuite/g++.dg/cpp2a/consteval34.C > index 068827ba516..7562f403f74 100644 > --- a/gcc/testsuite/g++.dg/cpp2a/consteval34.C > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval34.C > @@ -7,6 +7,7 @@ constexpr int > foo (bool b) > { > return b ? bar (3) : 2; // { dg-message "in .constexpr. expansion" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > } > > static_assert (foo (false) == 2); > @@ -22,13 +23,20 @@ void > g () > { > __extension__ int a1[bar(3)]; // { dg-message "in .constexpr. expansion" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > int a2[sizeof (bar(3))]; > > int a3 = false ? (1 + bar (8)) : 1; // { dg-message "in .constexpr. expansion" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > a3 += false ? (1 + bar (8)) : 1; // { dg-message "in .constexpr. expansion" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > > __extension__ int a4 = false ?: (1 + bar (8)); // { dg-message "in .constexpr. expansion" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > __extension__ int a5 = true ?: (1 + bar (8)); // { dg-message "in .constexpr. expansion" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > int a6 = bar (2) ? 1 : 2; // { dg-message "in .constexpr. expansion" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > int a7 = bar (2) - 1 ? 1 : 2; // { dg-message "in .constexpr. expansion" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > } > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval36.C b/gcc/testsuite/g++.dg/cpp2a/consteval36.C > index 9c470e4b7d7..8e27f2e33c6 100644 > --- a/gcc/testsuite/g++.dg/cpp2a/consteval36.C > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval36.C > @@ -6,17 +6,17 @@ consteval int id (int i) { return i; } > void > g (int i) > { > - 1 ? 1 : ((1 ? 1 : 1), id (i)); // { dg-error "'i' is not a constant expression" } > - 1 ? 1 : ((1 ? 1 : 1), id (i), 1); // { dg-error "'i' is not a constant expression" } > - 1 ? 1 : ((i ? 1 : 1), id (i), 1); // { dg-error "'i' is not a constant expression" } > - 1 ? 1 : ((1 ? i : 1), id (i), 1); // { dg-error "'i' is not a constant expression" } > - 1 ? 1 : ((1 ? 1 : i), id (i), 1); // { dg-error "'i' is not a constant expression" } > - 1 ? 1 : ((i ? -i : i), id (i), 1); // { dg-error "'i' is not a constant expression" } > - 1 ? 1 : ((1 ? 1 : id (i)), id (42), 1); // { dg-error "'i' is not a constant expression" } > - 1 ? 1 : ((1 ? 1 : id (42)), id (i)); // { dg-error "'i' is not a constant expression" } > - 1 ? 1 : ((1 ? 1 : id (42)), id (i), 1); // { dg-error "'i' is not a constant expression" } > - id (i) ? 1 : ((1 ? 1 : 1), id (i)); // { dg-error "'i' is not a constant expression" } > - 1 ? 1 : ((1 ? 1 : id (i)), id (i)); // { dg-error "'i' is not a constant expression" } > - 1 ? id (i) : ((1 ? 1 : id (i)), id (i)); // { dg-error "'i' is not a constant expression" } > - 1 ? 1 : ((id (i) ? 1 : 1), id (i)); // { dg-error "'i' is not a constant expression" } > + 1 ? 1 : ((1 ? 1 : 1), id (i)); // { dg-error "call to consteval function|'i' is not a constant expression" } > + 1 ? 1 : ((1 ? 1 : 1), id (i), 1); // { dg-error "call to consteval function|'i' is not a constant expression" } > + 1 ? 1 : ((i ? 1 : 1), id (i), 1); // { dg-error "call to consteval function|'i' is not a constant expression" } > + 1 ? 1 : ((1 ? i : 1), id (i), 1); // { dg-error "call to consteval function|'i' is not a constant expression" } > + 1 ? 1 : ((1 ? 1 : i), id (i), 1); // { dg-error "call to consteval function|'i' is not a constant expression" } > + 1 ? 1 : ((i ? -i : i), id (i), 1); // { dg-error "call to consteval function|'i' is not a constant expression" } > + 1 ? 1 : ((1 ? 1 : id (i)), id (42), 1); // { dg-error "call to consteval function|'i' is not a constant expression" } > + 1 ? 1 : ((1 ? 1 : id (42)), id (i)); // { dg-error "call to consteval function|'i' is not a constant expression" } > + 1 ? 1 : ((1 ? 1 : id (42)), id (i), 1); // { dg-error "call to consteval function|'i' is not a constant expression" } > + id (i) ? 1 : ((1 ? 1 : 1), id (i)); // { dg-error "call to consteval function|'i' is not a constant expression" } > + 1 ? 1 : ((1 ? 1 : id (i)), id (i)); // { dg-error "call to consteval function|'i' is not a constant expression" } > + 1 ? id (i) : ((1 ? 1 : id (i)), id (i)); // { dg-error "call to consteval function|'i' is not a constant expression" } > + 1 ? 1 : ((id (i) ? 1 : 1), id (i)); // { dg-error "call to consteval function|'i' is not a constant expression" } > } > diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval9.C b/gcc/testsuite/g++.dg/cpp2a/consteval9.C > index 051a3d4e355..ad882d51c9b 100644 > --- a/gcc/testsuite/g++.dg/cpp2a/consteval9.C > +++ b/gcc/testsuite/g++.dg/cpp2a/consteval9.C > @@ -14,6 +14,7 @@ template > void qux () > { > int a = bar (N); // { dg-message "in 'constexpr' expansion of 'bar\\(2\\)'" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > } > > // This function is not instantiated so NDR. > @@ -31,3 +32,4 @@ baz () > } > > int a = bar (2); // { dg-message "in 'constexpr' expansion of 'bar\\(2\\)'" } > +// { dg-error "call to consteval function" "" { target *-*-* } .-1 } > diff --git a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C > index 16bc0b85395..fc268d44e1a 100644 > --- a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C > +++ b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C > @@ -480,8 +480,8 @@ > > #ifndef __cpp_consteval > # error "__cpp_consteval" > -#elif __cpp_consteval != 201811 > -# error "__cpp_consteval != 201811" > +#elif __cpp_consteval != 202211L > +# error "__cpp_consteval != 202211L" > #endif > > #ifndef __cpp_concepts > diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth9.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth9.C > index 33b547d2b50..ecb46b016a6 100644 > --- a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth9.C > +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth9.C > @@ -22,6 +22,6 @@ struct Z: Y > int main() > { > X() == X(); // { dg-error "no match" } > - X x; x == x; // { dg-error "x' is not usable in a constant expression" } > + X x; x == x; // { dg-error "x' is not usable in a constant expression|call to consteval function" } > Y() == Y(); // { dg-warning "nodiscard" } > } > diff --git a/libstdc++-v3/testsuite/18_support/comparisons/categories/zero_neg.cc b/libstdc++-v3/testsuite/18_support/comparisons/categories/zero_neg.cc > index 9d2115b3f4f..82f7cd54fba 100644 > --- a/libstdc++-v3/testsuite/18_support/comparisons/categories/zero_neg.cc > +++ b/libstdc++-v3/testsuite/18_support/comparisons/categories/zero_neg.cc > @@ -52,3 +52,4 @@ test01() > > // { dg-prune-output "reinterpret_cast.* is not a constant expression" } > // { dg-prune-output "cast from 'void.' is not allowed" } > +// { dg-prune-output "not a constant expression" } > diff --git a/libstdc++-v3/testsuite/std/format/string_neg.cc b/libstdc++-v3/testsuite/std/format/string_neg.cc > index 7a60ef8cf0e..69bcc736cff 100644 > --- a/libstdc++-v3/testsuite/std/format/string_neg.cc > +++ b/libstdc++-v3/testsuite/std/format/string_neg.cc > @@ -2,5 +2,5 @@ > > #include > > -auto s = std::format(" {9} "); > +auto s = std::format(" {9} "); // { dg-error "call to consteval function" } > // { dg-error "invalid.arg.id" "" { target *-*-* } 0 } > > base-commit: 606f7201c066b840ea43ab62fcf47042b81e54d4 > -- > 2.43.0 >