From patchwork Thu Nov 17 20:42:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 60804 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3F6B4385221B for ; Thu, 17 Nov 2022 20:43:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3F6B4385221B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1668717803; bh=1TV55b4MJaUUE9Zxy9fTL/dM5x5J4wFh4humsturJEI=; h=Date:To:Subject:References:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=XqCP47lNb5fFGKmIC8zfB2xEMFnD506FRBh1UARqi/8Tt17NYpsuGnvFpmmt1Tas7 GnZKIDWUpehCkijANZ6FgEbHJfEzKl1bjYZ18Ee44vf9s7Gb+8Tzwi/2uf6esCju0C t6hpTeXbZ9Pf7QUX4YNDVVMe3dllBZnOrTeXTDjA= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id B60D1385220E for ; Thu, 17 Nov 2022 20:42:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B60D1385220E Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-350-g668ZUcEOFusJxneFbDslQ-1; Thu, 17 Nov 2022 15:42:24 -0500 X-MC-Unique: g668ZUcEOFusJxneFbDslQ-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C104E185A792 for ; Thu, 17 Nov 2022 20:42:23 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.192.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 5955B4A9254; Thu, 17 Nov 2022 20:42:23 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 2AHKgI6g016862 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Thu, 17 Nov 2022 21:42:19 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 2AHKgIfs016861; Thu, 17 Nov 2022 21:42:18 +0100 Date: Thu, 17 Nov 2022 21:42:17 +0100 To: Jason Merrill , Jonathan Wakely , gcc-patches@gcc.gnu.org, Marek Polacek Subject: [PATCH] c++, v4: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions Message-ID: References: <016f168b-f143-baff-5f71-c48d4611ae11@redhat.com> <740b5e1e-7143-c291-5594-af937867fbc3@redhat.com> MIME-Version: 1.0 In-Reply-To: X-Scanned-By: MIMEDefang 3.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-3.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Jakub Jelinek via Gcc-patches From: Jakub Jelinek Reply-To: Jakub Jelinek Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" On Thu, Nov 17, 2022 at 07:42:40PM +0100, Jakub Jelinek via Gcc-patches wrote: > I thought for older C++ this is to catch > void > foo () > { > constexpr int a = ({ static constexpr int b = 2; b; }); > } > and for C++23 the only 3 spots that diagnose those. > But perhaps for C++20 or older we can check if the var has a context > of a constexpr function (then assume cp_finish_decl errored or pedwarned > already) and only error or pedwarn otherwise. So, here is an updated patch, which in constexpr.cc will accept DECL_EXPR of decl_*constant_var_p static/thread_local non-extern vars for C++23 or if they are not declared in constexpr/consteval function. So, the statement expression case will remain hard error for C++ <= 20 rather than pedwarn, because due to the ctx->quiet vs. !ctx->quiet case I don't see what else we could do, either something is a constant expression, or it is not, but whether it is or is not shouldn't depend on -Wpedantic/-Wno-pedantic/-Werror=pedantic. 2022-11-17 Jakub Jelinek gcc/c-family/ * c-cppbuiltin.cc (c_cpp_builtins): Bump __cpp_constexpr value from 202207L to 202211L. gcc/cp/ * constexpr.cc (cxx_eval_constant_expression): Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions. Allow decl_constant_var_p static or thread_local vars for C++23 and later or if they are declared inside of constexpr or consteval function. (potential_constant_expression_1): Similarly, except use decl_maybe_constant_var_p instead of decl_constant_var_p if processing_template_decl. * decl.cc (diagnose_static_in_constexpr): New function. (start_decl): Remove diagnostics of static or thread_local vars in constexpr or consteval functions. (cp_finish_decl): Call diagnose_static_in_constexpr. gcc/testsuite/ * g++.dg/cpp23/constexpr-nonlit17.C: New test. * g++.dg/cpp23/constexpr-nonlit18.C: New test. * g++.dg/cpp23/constexpr-nonlit19.C: New test. * g++.dg/cpp23/constexpr-nonlit20.C: New test. * g++.dg/cpp23/feat-cxx2b.C: Adjust expected __cpp_constexpr value. * g++.dg/ext/stmtexpr19.C: Don't expect an error for C++20 or later. Jakub --- gcc/c-family/c-cppbuiltin.cc.jj 2022-11-17 09:00:42.106249011 +0100 +++ gcc/c-family/c-cppbuiltin.cc 2022-11-17 09:01:49.286320527 +0100 @@ -1074,7 +1074,7 @@ c_cpp_builtins (cpp_reader *pfile) /* Set feature test macros for C++23. */ cpp_define (pfile, "__cpp_size_t_suffix=202011L"); cpp_define (pfile, "__cpp_if_consteval=202106L"); - cpp_define (pfile, "__cpp_constexpr=202207L"); + cpp_define (pfile, "__cpp_constexpr=202211L"); cpp_define (pfile, "__cpp_multidimensional_subscript=202211L"); cpp_define (pfile, "__cpp_named_character_escapes=202207L"); cpp_define (pfile, "__cpp_static_call_operator=202207L"); --- gcc/cp/constexpr.cc.jj 2022-11-17 08:48:30.530357181 +0100 +++ gcc/cp/constexpr.cc 2022-11-17 20:53:15.432408015 +0100 @@ -7100,17 +7100,35 @@ cxx_eval_constant_expression (const cons /* Allow __FUNCTION__ etc. */ && !DECL_ARTIFICIAL (r)) { - if (!ctx->quiet) + bool ok = decl_constant_var_p (r); + /* Since P2647R1 control can pass through definitions of static + or thread_local vars usable in constant expressions. + In C++20 or older, if such vars are declared inside of + constexpr or consteval function, diagnose_static_in_constexpr + should have already pedwarned on those. Otherwise they could + be e.g. in a statement expression, reject those before + C++23. */ + if (ok && cxx_dialect < cxx23) { - if (CP_DECL_THREAD_LOCAL_P (r)) - error_at (loc, "control passes through definition of %qD " - "with thread storage duration", r); - else - error_at (loc, "control passes through definition of %qD " - "with static storage duration", r); + tree fnctx = decl_function_context (r); + if (fnctx == NULL_TREE + || !DECL_DECLARED_CONSTEXPR_P (fnctx)) + ok = false; + } + if (!ok) + { + if (!ctx->quiet) + { + if (CP_DECL_THREAD_LOCAL_P (r)) + error_at (loc, "control passes through definition of " + "%qD with thread storage duration", r); + else + error_at (loc, "control passes through definition of " + "%qD with static storage duration", r); + } + *non_constant_p = true; + break; } - *non_constant_p = true; - break; } if (AGGREGATE_TYPE_P (TREE_TYPE (r)) @@ -9588,21 +9606,41 @@ potential_constant_expression_1 (tree t, tmp = DECL_EXPR_DECL (t); if (VAR_P (tmp) && !DECL_ARTIFICIAL (tmp)) { - if (CP_DECL_THREAD_LOCAL_P (tmp) && !DECL_REALLY_EXTERN (tmp)) - { - if (flags & tf_error) - constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p, - "%qD defined % in " - "% context", tmp); - return false; - } - else if (TREE_STATIC (tmp)) + if (TREE_STATIC (tmp) + || (CP_DECL_THREAD_LOCAL_P (tmp) && !DECL_REALLY_EXTERN (tmp))) { - if (flags & tf_error) - constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p, - "%qD defined % in % " - "context", tmp); - return false; + bool ok = (processing_template_decl + ? decl_maybe_constant_var_p (tmp) + : decl_constant_var_p (tmp)); + /* Since P2647R1 control can pass through definitions of static + or thread_local vars usable in constant expressions. + In C++20 or older, if such vars are declared inside of + constexpr or consteval function, diagnose_static_in_constexpr + should have already pedwarned on those. Otherwise they could + be e.g. in a statement expression, reject those before + C++23. */ + if (ok && cxx_dialect < cxx23) + { + tree fnctx = decl_function_context (tmp); + if (fnctx == NULL_TREE + || !DECL_DECLARED_CONSTEXPR_P (fnctx)) + ok = false; + } + if (!ok) + { + if (flags & tf_error) + { + if (CP_DECL_THREAD_LOCAL_P (tmp)) + constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p, + "%qD defined % in " + "% context", tmp); + else + constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p, + "%qD defined % in " + "% context", tmp); + } + return false; + } } else if (!check_for_uninitialized_const_var (tmp, /*constexpr_context_p=*/true, flags)) --- gcc/cp/decl.cc.jj 2022-11-16 14:44:43.692339668 +0100 +++ gcc/cp/decl.cc 2022-11-17 20:53:44.102011594 +0100 @@ -5600,6 +5600,57 @@ groktypename (cp_decl_specifier_seq *typ return type; } +/* For C++17 and older diagnose static or thread_local decls in constexpr + or consteval functions. For C++20 similarly, except if they are + usable in constant expressions. */ + +static void +diagnose_static_in_constexpr (tree decl) +{ + if (cxx_dialect >= cxx23) + return; + if (current_function_decl + && VAR_P (decl) + && DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + { + bool ok = false; + if (processing_template_decl + ? decl_maybe_constant_var_p (decl) + : decl_constant_var_p (decl)) + { + if (CP_DECL_THREAD_LOCAL_P (decl) && !DECL_REALLY_EXTERN (decl)) + pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic, + "%qD defined % in %qs function only " + "available with %<-std=c++2b%> or %<-std=gnu++2b%>", decl, + DECL_IMMEDIATE_FUNCTION_P (current_function_decl) + ? "consteval" : "constexpr"); + else if (TREE_STATIC (decl)) + pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic, + "%qD defined % in %qs function only available " + "with %<-std=c++2b%> or %<-std=gnu++2b%>", decl, + DECL_IMMEDIATE_FUNCTION_P (current_function_decl) + ? "consteval" : "constexpr"); + ok = true; + } + else if (CP_DECL_THREAD_LOCAL_P (decl) && !DECL_REALLY_EXTERN (decl)) + error_at (DECL_SOURCE_LOCATION (decl), + "%qD defined % in %qs function only " + "available with %<-std=c++2b%> or %<-std=gnu++2b%>", decl, + DECL_IMMEDIATE_FUNCTION_P (current_function_decl) + ? "consteval" : "constexpr"); + else if (TREE_STATIC (decl)) + error_at (DECL_SOURCE_LOCATION (decl), + "%qD defined % in %qs function only available " + "with %<-std=c++2b%> or %<-std=gnu++2b%>", decl, + DECL_IMMEDIATE_FUNCTION_P (current_function_decl) + ? "consteval" : "constexpr"); + else + ok = true; + if (!ok) + cp_function_chain->invalid_constexpr = true; + } +} + /* Process a DECLARATOR for a function-scope or namespace-scope variable or function declaration. (Function definitions go through start_function; class member @@ -5860,29 +5911,6 @@ start_decl (const cp_declarator *declara DECL_THIS_STATIC (decl) = 1; } - if (current_function_decl && VAR_P (decl) - && DECL_DECLARED_CONSTEXPR_P (current_function_decl) - && cxx_dialect < cxx23) - { - bool ok = false; - if (CP_DECL_THREAD_LOCAL_P (decl) && !DECL_REALLY_EXTERN (decl)) - error_at (DECL_SOURCE_LOCATION (decl), - "%qD defined % in %qs function only " - "available with %<-std=c++2b%> or %<-std=gnu++2b%>", decl, - DECL_IMMEDIATE_FUNCTION_P (current_function_decl) - ? "consteval" : "constexpr"); - else if (TREE_STATIC (decl)) - error_at (DECL_SOURCE_LOCATION (decl), - "%qD defined % in %qs function only available " - "with %<-std=c++2b%> or %<-std=gnu++2b%>", decl, - DECL_IMMEDIATE_FUNCTION_P (current_function_decl) - ? "consteval" : "constexpr"); - else - ok = true; - if (!ok) - cp_function_chain->invalid_constexpr = true; - } - if (!processing_template_decl && VAR_P (decl)) start_decl_1 (decl, initialized); @@ -8424,6 +8452,9 @@ cp_finish_decl (tree decl, tree init, bo set_user_assembler_name (decl, asmspec); DECL_HARD_REGISTER (decl) = 1; } + + diagnose_static_in_constexpr (decl); + return; } @@ -8749,6 +8780,8 @@ cp_finish_decl (tree decl, tree init, bo && !DECL_HARD_REGISTER (decl)) targetm.lower_local_decl_alignment (decl); + diagnose_static_in_constexpr (decl); + invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl); } --- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C.jj 2022-11-17 09:00:42.108248984 +0100 +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C 2022-11-17 20:55:33.550498209 +0100 @@ -0,0 +1,12 @@ +// P2647R1 - Permitting static constexpr variables in constexpr functions +// { dg-do compile { target c++23 } } + +constexpr char +test () +{ + static const int x = 5; + static constexpr char c[] = "Hello World"; + return *(c + x); +} + +static_assert (test () == ' '); --- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C.jj 2022-11-17 09:29:45.776136195 +0100 +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C 2022-11-17 21:02:20.852865509 +0100 @@ -0,0 +1,49 @@ +// P2647R1 - Permitting static constexpr variables in constexpr functions +// { dg-do compile { target c++14 } } + +constexpr int +f1 (int x) +{ + if (x) + throw 1; + return 0; +} + +constexpr int +f2 () +{ + static const int a = f1 (1); // { dg-error "'a' defined 'static' in 'constexpr' function only available with" "" { target c++20_down } } + return 0; +} + +constexpr int +f3 () +{ + static const int a = 5; // { dg-error "'a' defined 'static' in 'constexpr' function only available with" "" { target c++20_down } } + return 0; +} + +constexpr int +f4 () // { dg-message "declared here" "" { target c++20_down } } +{ // { dg-message "is not usable as a 'constexpr' function because:" "" { target c++23 } .-1 } + static const int a = f1 (1); // { dg-error "'a' defined 'static' in 'constexpr' function only available with" "" { target c++20_down } } + return 0; // { dg-error "'a' defined 'static' in 'constexpr' context" "" { target c++23 } .-1 } +} + +constexpr int a4 = f4 (); // { dg-error "called in a constant expression" } + +constexpr int +f5 () +{ + static const int a = f1 (0); // { dg-error "'a' defined 'static' in 'constexpr' function only available with" "" { target c++20_down } } + return 0; +} + +constexpr int +f6 () +{ + static const int a = f1 (0); // { dg-error "'a' defined 'static' in 'constexpr' function only available with" "" { target c++20_down } } + return 0; +} + +constexpr int a6 = f6 (); --- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit19.C.jj 2022-11-17 20:56:07.887023431 +0100 +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit19.C 2022-11-17 21:04:12.618319027 +0100 @@ -0,0 +1,50 @@ +// P2647R1 - Permitting static constexpr variables in constexpr functions +// { dg-do compile { target c++14 } } +// { dg-options "-pedantic" } + +constexpr int +f1 (int x) +{ + if (x) + throw 1; + return 0; +} + +constexpr int +f2 () +{ + static const int a = f1 (1); // { dg-error "'a' defined 'static' in 'constexpr' function only available with" "" { target c++20_down } } + return 0; +} + +constexpr int +f3 () +{ + static const int a = 5; // { dg-warning "'a' defined 'static' in 'constexpr' function only available with" "" { target c++20_down } } + return 0; +} + +constexpr int +f4 () // { dg-message "declared here" "" { target c++20_down } } +{ // { dg-message "is not usable as a 'constexpr' function because:" "" { target c++23 } .-1 } + static const int a = f1 (1); // { dg-error "'a' defined 'static' in 'constexpr' function only available with" "" { target c++20_down } } + return 0; // { dg-error "'a' defined 'static' in 'constexpr' context" "" { target c++23 } .-1 } +} + +constexpr int a4 = f4 (); // { dg-error "called in a constant expression" } + +constexpr int +f5 () +{ + static const int a = f1 (0); // { dg-warning "'a' defined 'static' in 'constexpr' function only available with" "" { target c++20_down } } + return 0; +} + +constexpr int +f6 () +{ + static const int a = f1 (0); // { dg-warning "'a' defined 'static' in 'constexpr' function only available with" "" { target c++20_down } } + return 0; +} + +constexpr int a6 = f6 (); --- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit20.C.jj 2022-11-17 20:56:28.527738024 +0100 +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit20.C 2022-11-17 21:31:25.209729268 +0100 @@ -0,0 +1,50 @@ +// P2647R1 - Permitting static constexpr variables in constexpr functions +// { dg-do compile { target c++14 } } +// { dg-options "-Wno-pedantic" } + +constexpr int +f1 (int x) +{ + if (x) + throw 1; + return 0; +} + +constexpr int +f2 () +{ + static const int a = f1 (1); // { dg-error "'a' defined 'static' in 'constexpr' function only available with" "" { target c++20_down } } + return 0; +} + +constexpr int +f3 () +{ + static const int a = 5; + return 0; +} + +constexpr int +f4 () // { dg-message "declared here" "" { target c++20_down } } +{ // { dg-message "is not usable as a 'constexpr' function because:" "" { target c++23 } .-1 } + static const int a = f1 (1); // { dg-error "'a' defined 'static' in 'constexpr' function only available with" "" { target c++20_down } } + return 0; // { dg-error "'a' defined 'static' in 'constexpr' context" "" { target c++23 } .-1 } +} + +constexpr int a4 = f4 (); // { dg-error "called in a constant expression" } + +constexpr int +f5 () +{ + static const int a = f1 (0); + return 0; +} + +constexpr int +f6 () +{ + static const int a = f1 (0); + return 0; +} + +constexpr int a6 = f6 (); --- gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C.jj 2022-11-17 08:48:30.561356753 +0100 +++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C 2022-11-17 09:00:42.108248984 +0100 @@ -134,8 +134,8 @@ #ifndef __cpp_constexpr # error "__cpp_constexpr" -#elif __cpp_constexpr != 202207 -# error "__cpp_constexpr != 202207" +#elif __cpp_constexpr != 202211 +# error "__cpp_constexpr != 202211" #endif #ifndef __cpp_decltype_auto --- gcc/testsuite/g++.dg/ext/stmtexpr19.C.jj 2022-11-17 08:48:02.730741221 +0100 +++ gcc/testsuite/g++.dg/ext/stmtexpr19.C 2022-11-17 20:57:06.936206927 +0100 @@ -8,7 +8,7 @@ const test* setup() { static constexpr test atest = { - ({ static const int inner = 123; &inner; }) // { dg-error "static" } + ({ static const int inner = 123; &inner; }) // { dg-error "static" "" { target c++20_down } } }; return &atest;