From patchwork Tue Oct 5 12:39:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 45881 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 93AF5385AC1F for ; Tue, 5 Oct 2021 12:39:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 93AF5385AC1F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1633437589; bh=+8tBdTEsNSr7okeqjvYw9t5kZGV507DASw2Kt4Cc9HM=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=e2yneXk+2jmWb6au9L8hQmDBbRFxhhzt25pCMyQhV1d+F9c+H1++u7sonZseDnRUb FmYHn5UjjgtTieLPySGkJxnAUpqvTfuItL7gRFirWWJ05tCUh5YsD+1O0v1pk758iY HXlyHR8QhXwRLgP7yslf96r74Rwz8TDRFHhupKJg= 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 [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id B7D74385840B for ; Tue, 5 Oct 2021 12:39:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B7D74385840B Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-201-OZUy5feHPi6Cg_JzDvRoeQ-1; Tue, 05 Oct 2021 08:39:16 -0400 X-MC-Unique: OZUy5feHPi6Cg_JzDvRoeQ-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 416A679EDF for ; Tue, 5 Oct 2021 12:39:15 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.193.109]) by smtp.corp.redhat.com (Postfix) with ESMTPS id A02C65D9DE; Tue, 5 Oct 2021 12:39:13 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.16.1/8.16.1) with ESMTPS id 195CdBwQ036689 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Tue, 5 Oct 2021 14:39:11 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.16.1/8.16.1/Submit) id 195CdBnq036688; Tue, 5 Oct 2021 14:39:11 +0200 Date: Tue, 5 Oct 2021 14:39:10 +0200 To: Jason Merrill Subject: [PATCH] c++: Implement C++23 P2242R3 - Non-literal variables (and labels and gotos) in constexpr functions Message-ID: <20211005123910.GW304296@tucnak> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-5.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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 Cc: gcc-patches@gcc.gnu.org Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Hi! The following patch implements C++23 P2242R3 - Non-literal variables (and labels and gotos) in constexpr functions. I think it is mostly straightforward, don't diagnose certain statements/declarations just because of their presence in constexpr/consteval functions, but (except for the non-literal type var declarations which ought to be caught by e.g. constructor or destructor call during evaluation not being constexpr and for labels which are now always allowed) diagnose it during constexpr evaluation. The only unclear thing to me is "a control flow that passes through a declaration". The patch implements diagnostics when encountering a DECL_EXPR for such variables. But because constexpr/consteval functions support switch statements, another thing that can happen is jump over such a declaration. Consider e.g. following testcase (not included in the patch). When evaluating foo (12) or bar (12) the patch accepts those as constant expressions, eventhough it jumps across such declarations. For baz (12) and corge (12) it rejects them not because of jumping across such declarations, but because those static or thread_local variables aren't initialized with constant expressions and are accessed. If baz/corge is modified not to have const keyword, they are rejected because the vars aren't aren't const. If they have const keyword and are initialized by constant expression, accesses to those vars are accepted. Is that ok? So far regtested with GXX_TESTSUITE_STDS=98,11,14,17,20,2b make -j32 -k check-g++ ok for trunk if it passes full bootstrap/regtest? // { dg-do compile } // { dg-options "-std=c++2b" } int qux (); constexpr int foo (int x) { switch (x) { static int bar = qux (); case 12: return 1; } return 0; } constexpr int bar (int x) { switch (x) { thread_local int bar = qux (); case 12: return 1; } return 0; } constexpr int baz (int x) { switch (x) { static const int bar = qux (); // { dg-message "'bar' was not initialized with a constant expression" } case 12: return bar; } return 0; } constexpr int corge (int x) { switch (x) { const thread_local int bar = qux (); // { dg-message "'bar' was not initialized with a constant expression" } case 12: return bar; } return 0; } constexpr int a = foo (12); constexpr int b = bar (12); constexpr int c = baz (12); // { dg-error "the value of 'bar' is not usable in a constant expression" } constexpr int d = corge (12); // { dg-error "the value of 'bar' is not usable in a constant expression" } 2021-10-05 Jakub Jelinek gcc/c-family/ * c-cppbuiltin.c (c_cpp_builtins): For -std=c++23 predefine __cpp_constexpr to 202103L rather than 201907L. gcc/cp/ * parser.c (cp_parser_jump_statement): Implement C++23 P2242R3. Allow goto expressions in constexpr function bodies for C++23. Adjust error message for older standards to mention it. * decl.c (start_decl): Allow static and thread_local declarations in constexpr function bodies for C++23. Adjust error message for older standards to mention it. * constexpr.c (ensure_literal_type_for_constexpr_object): Allow declarations of variables with non-literal type in constexpr function bodies for C++23. Adjust error message for older standards to mention it. (cxx_eval_constant_expression) : Diagnose declarations of initialization of static or thread_local vars. (cxx_eval_constant_expression) : Diagnose goto statements for C++23. (potential_constant_expression_1) : Allow declarations of static and thread_local vars for C++23. (potential_constant_expression_1) : Allow labels for C++23. gcc/testsuite/ * g++.dg/cpp23/feat-cxx2b.C: Expect __cpp_constexpr 202103L rather than 201907L. * g++.dg/cpp23/constexpr-nonlit1.C: New test. * g++.dg/cpp23/constexpr-nonlit2.C: New test. * g++.dg/cpp23/constexpr-nonlit3.C: New test. * g++.dg/diagnostic/constexpr1.C: Only expect some diagnostics for c++20_down. * g++.dg/cpp1y/constexpr-label.C: Likewise. * g++.dg/cpp1y/constexpr-neg1.C: Likewise. * g++.dg/cpp2a/constexpr-try5.C: Likewise. Adjust some expected wording. * g++.dg/cpp2a/constexpr-dtor3.C: Likewise. * g++.dg/cpp2a/consteval3.C: Likewise. Add effective target c++20 and remove dg-options. Jakub --- gcc/c-family/c-cppbuiltin.c.jj 2021-09-21 23:31:01.016248936 +0200 +++ gcc/c-family/c-cppbuiltin.c 2021-10-05 12:54:29.898321379 +0200 @@ -1052,7 +1052,8 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_init_captures=201803L"); cpp_define (pfile, "__cpp_generic_lambdas=201707L"); cpp_define (pfile, "__cpp_designated_initializers=201707L"); - cpp_define (pfile, "__cpp_constexpr=201907L"); + if (cxx_dialect <= cxx20) + cpp_define (pfile, "__cpp_constexpr=201907L"); cpp_define (pfile, "__cpp_constexpr_in_decltype=201711L"); cpp_define (pfile, "__cpp_conditional_explicit=201806L"); cpp_define (pfile, "__cpp_consteval=201811L"); @@ -1071,6 +1072,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=202103L"); } if (flag_concepts) { --- gcc/cp/parser.c.jj 2021-10-01 18:47:58.090795589 +0200 +++ gcc/cp/parser.c 2021-10-05 12:54:29.907321254 +0200 @@ -14176,9 +14176,11 @@ cp_parser_jump_statement (cp_parser* par case RID_GOTO: if (parser->in_function_body - && DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + && DECL_DECLARED_CONSTEXPR_P (current_function_decl) + && cxx_dialect < cxx23) { - error ("% in % function"); + error ("% in % function only available with " + "%<-std=c++2b%> or %<-std=gnu++2b%>"); cp_function_chain->invalid_constexpr = true; } --- gcc/cp/decl.c.jj 2021-09-21 23:31:01.042248567 +0200 +++ gcc/cp/decl.c 2021-10-05 12:54:29.909321226 +0200 @@ -5709,17 +5709,20 @@ start_decl (const cp_declarator *declara } if (current_function_decl && VAR_P (decl) - && DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + && DECL_DECLARED_CONSTEXPR_P (current_function_decl) + && cxx_dialect < cxx23) { bool ok = false; if (CP_DECL_THREAD_LOCAL_P (decl)) error_at (DECL_SOURCE_LOCATION (decl), - "%qD declared % in %qs function", decl, + "%qD declared % 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 declared % in %qs function", decl, + "%qD declared % in %qs function only available " + "with %<-std=c++2b%> or %<-std=gnu++2b%>", decl, DECL_IMMEDIATE_FUNCTION_P (current_function_decl) ? "consteval" : "constexpr"); else --- gcc/cp/constexpr.c.jj 2021-09-22 23:19:37.498912776 +0200 +++ gcc/cp/constexpr.c 2021-10-05 13:56:02.377831320 +0200 @@ -109,14 +109,15 @@ ensure_literal_type_for_constexpr_object explain_non_literal_class (type); decl = error_mark_node; } - else + else if (cxx_dialect < cxx23) { if (!is_instantiation_of_constexpr (current_function_decl)) { auto_diagnostic_group d; error_at (DECL_SOURCE_LOCATION (decl), - "variable %qD of non-literal type %qT in " - "% function", decl, type); + "variable %qD of non-literal type %qT in " + "% function only available with " + "%<-std=c++2b%> or %<-std=gnu++2b%>", decl, type); explain_non_literal_class (type); decl = error_mark_node; } @@ -6345,6 +6346,26 @@ cxx_eval_constant_expression (const cons r = void_node; break; } + + if (VAR_P (r) + && (TREE_STATIC (r) || CP_DECL_THREAD_LOCAL_P (r)) + /* Allow __FUNCTION__ etc. */ + && !DECL_ARTIFICIAL (r)) + { + gcc_assert (cxx_dialect >= cxx23); + if (!ctx->quiet) + { + if (CP_DECL_THREAD_LOCAL_P (r)) + error_at (loc, "control passes through declaration of %qD " + "with thread storage duration", r); + else + error_at (loc, "control passes through declaration of %qD " + "with static storage duration", r); + } + *non_constant_p = true; + break; + } + if (AGGREGATE_TYPE_P (TREE_TYPE (r)) || VECTOR_TYPE_P (TREE_TYPE (r))) { @@ -7049,10 +7070,18 @@ cxx_eval_constant_expression (const cons break; case GOTO_EXPR: - *jump_target = TREE_OPERAND (t, 0); - gcc_assert (breaks (jump_target) || continues (jump_target) - /* Allow for jumping to a cdtor_label. */ - || returns (jump_target)); + if (breaks (&TREE_OPERAND (t, 0)) + || continues (&TREE_OPERAND (t, 0)) + /* Allow for jumping to a cdtor_label. */ + || returns (&TREE_OPERAND (t, 0))) + *jump_target = TREE_OPERAND (t, 0); + else + { + gcc_assert (cxx_dialect >= cxx23); + if (!ctx->quiet) + error_at (loc, "% is not a constant expression"); + *non_constant_p = true; + } break; case LOOP_EXPR: @@ -8736,14 +8765,14 @@ potential_constant_expression_1 (tree t, tmp = DECL_EXPR_DECL (t); if (VAR_P (tmp) && !DECL_ARTIFICIAL (tmp)) { - if (TREE_STATIC (tmp)) + if (TREE_STATIC (tmp) && cxx_dialect < cxx23) { if (flags & tf_error) error_at (DECL_SOURCE_LOCATION (tmp), "%qD declared " "% in % context", tmp); return false; } - else if (CP_DECL_THREAD_LOCAL_P (tmp)) + else if (CP_DECL_THREAD_LOCAL_P (tmp) && cxx_dialect < cxx23) { if (flags & tf_error) error_at (DECL_SOURCE_LOCATION (tmp), "%qD declared " @@ -9025,7 +9054,7 @@ potential_constant_expression_1 (tree t, case LABEL_EXPR: t = LABEL_EXPR_LABEL (t); - if (DECL_ARTIFICIAL (t)) + if (DECL_ARTIFICIAL (t) || cxx_dialect >= cxx23) return true; else if (flags & tf_error) error_at (loc, "label definition is not a constant expression"); --- gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C.jj 2021-06-11 23:44:55.883676082 +0200 +++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C 2021-10-05 12:54:29.910321212 +0200 @@ -134,8 +134,8 @@ #ifndef __cpp_constexpr # error "__cpp_constexpr" -#elif __cpp_constexpr != 201907 -# error "__cpp_constexpr != 201907" +#elif __cpp_constexpr != 202103 +# error "__cpp_constexpr != 202103" #endif #ifndef __cpp_decltype_auto --- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit1.C.jj 2021-10-05 12:54:29.910321212 +0200 +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit1.C 2021-10-05 13:57:09.582896213 +0200 @@ -0,0 +1,68 @@ +// P2242R3 +// { dg-do compile { target c++14 } } + +constexpr int +foo () +{ +lab: // { dg-error "label definition is not a constant expression" "" { target c++20_down } } + return 1; +} + +constexpr int +bar (int x) +{ + if (x) + goto lab; // { dg-error "'goto' in 'constexpr' function only available with" "" { target c++20_down } } + return 1; +lab: + return 0; +} + +constexpr int +baz (int x) +{ + if (!x) + return 1; + static int a; // { dg-error "'a' declared 'static' in 'constexpr' function only available with" "" { target c++20_down } } + return ++a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" "" { target c++17_down } .-1 } +} + +constexpr int +qux (int x) +{ + if (!x) + return 1; + thread_local int a; // { dg-error "'a' declared 'thread_local' in 'constexpr' function only available with" "" { target c++20_down } } + return ++a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" "" { target c++17_down } .-1 } +} + +constexpr int +garply (int x) +{ + if (!x) + return 1; + extern thread_local int a; // { dg-error "'a' declared 'thread_local' in 'constexpr' function only available with" "" { target c++20_down } } + return ++a; +} + +struct S { S (); ~S (); int s; }; // { dg-message "'S' is not literal because:" "" { target c++20_down } } + // { dg-message "'S' has a non-trivial destructor" "" { target c++17_down } .-1 } + // { dg-message "'S' does not have 'constexpr' destructor" "" { target { c++20_only } } .-2 } + +constexpr int +corge (int x) +{ + if (!x) + return 1; + S s; // { dg-error "variable 's' of non-literal type 'S' in 'constexpr' function only available with" "" { target c++20_down } } + return 0; +} + +#if __cpp_constexpr >= 202103L +static_assert (foo ()); +static_assert (bar (0)); +static_assert (baz (0)); +static_assert (qux (0)); +static_assert (garply (0)); +static_assert (corge (0)); +#endif --- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit2.C.jj 2021-10-05 12:54:29.910321212 +0200 +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit2.C 2021-10-05 12:54:29.910321212 +0200 @@ -0,0 +1,64 @@ +// P2242R3 +// { dg-do compile } +// { dg-options "-std=c++2b" } + +constexpr int +foo () +{ +lab: + return 1; +} + +constexpr int +bar (int x) +{ + if (x) + goto lab; // { dg-error "'goto' is not a constant expression" } + return 1; +lab: + return 0; +} + +constexpr int +baz (int x) +{ + if (!x) + return 1; + static int a; // { dg-error "control passes through declaration of 'a' with static storage duration" } + return ++a; +} + +constexpr int +qux (int x) +{ + if (!x) + return 1; + thread_local int a; // { dg-error "control passes through declaration of 'a' with thread storage duration" } + return ++a; +} + +constexpr int +garply (int x) +{ + if (!x) + return 1; + thread_local int a; // { dg-error "control passes through declaration of 'a' with thread storage duration" } + return ++a; +} + +struct S { S (); ~S (); int s; }; // { dg-message "'S::S\\\(\\\)' declared here" } + +constexpr int +corge (int x) +{ + if (!x) + return 1; + S s; // { dg-error "call to non-'constexpr' function 'S::S\\\(\\\)'" } + return 0; +} + +constexpr int a = bar (1); // { dg-message "in 'constexpr' expansion of" } +constexpr int b = baz (1); // { dg-message "in 'constexpr' expansion of" } +constexpr int c = qux (1); // { dg-message "in 'constexpr' expansion of" } +constexpr int d = garply (1); // { dg-message "in 'constexpr' expansion of" } +constexpr int e = corge (1); // { dg-message "in 'constexpr' expansion of" } --- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit3.C.jj 2021-10-05 12:54:29.910321212 +0200 +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit3.C 2021-10-05 13:57:21.176734894 +0200 @@ -0,0 +1,10 @@ +// P2242R3 +// { dg-do compile { target c++14 } } + +constexpr int +foo () +{ + goto lab; // { dg-error "'goto' in 'constexpr' function only available with" "" { target c++20_down } } +lab: // { dg-error "'goto' is not a constant expression" "" { target { c++23 } } .-1 } + return 1; +} --- gcc/testsuite/g++.dg/diagnostic/constexpr1.C.jj 2020-01-14 20:02:46.815609354 +0100 +++ gcc/testsuite/g++.dg/diagnostic/constexpr1.C 2021-10-05 13:56:30.249443508 +0200 @@ -1,5 +1,5 @@ // { dg-do compile { target c++11 } } -constexpr int foo() { thread_local int i __attribute__((unused)) {}; return 1; } // { dg-error "40:.i. declared .thread_local." } +constexpr int foo() { thread_local int i __attribute__((unused)) {}; return 1; } // { dg-error "40:.i. declared .thread_local." "" { target c++20_down } } -constexpr int bar() { static int i __attribute__((unused)) {}; return 1; } // { dg-error "34:.i. declared .static." } +constexpr int bar() { static int i __attribute__((unused)) {}; return 1; } // { dg-error "34:.i. declared .static." "" { target c++20_down } } --- gcc/testsuite/g++.dg/cpp1y/constexpr-label.C.jj 2020-11-22 23:21:35.866434202 +0100 +++ gcc/testsuite/g++.dg/cpp1y/constexpr-label.C 2021-10-05 13:37:37.660219970 +0200 @@ -4,6 +4,6 @@ constexpr int f () { -x: // { dg-error "label definition is not a constant expression" } +x: // { dg-error "label definition is not a constant expression" "" { target c++20_down } } return 42; } --- gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C.jj 2020-01-14 20:02:46.773609984 +0100 +++ gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C 2021-10-05 13:38:23.322583787 +0200 @@ -3,13 +3,13 @@ struct A { A(); }; constexpr int f(int i) { - static int j = i; // { dg-error "static" } - thread_local int l = i; // { dg-error "thread_local" } + static int j = i; // { dg-error "static" "" { target c++20_down } } + thread_local int l = i; // { dg-error "thread_local" "" { target c++20_down } } goto foo; // { dg-error "goto" } foo: asm("foo"); // { dg-error "asm" "" { target c++17_down } } int k; // { dg-error "uninitialized" "" { target c++17_down } } - A a; // { dg-error "non-literal" } + A a; // { dg-error "non-literal" "" { target c++20_down } } return i; } --- gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C.jj 2020-01-14 20:02:46.000000000 +0100 +++ gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C 2021-10-05 14:05:21.092057240 +0200 @@ -5,14 +5,14 @@ constexpr int foo () try { // { dg-warning "function-try-block body of 'constexpr' function only available with" "" { target c++17_down } } int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" "" { target c++17_down } } - static double b = 1.0;// { dg-error "'b' declared 'static' in 'constexpr' function" } - goto l; // { dg-error "'goto' in 'constexpr' function" } - l:; + static double b = 1.0;// { dg-error "'b' declared 'static' in 'constexpr' function only available with" "" { target c++20_down } } + goto l; // { dg-error "'goto' in 'constexpr' function only available with" "" { target c++20_down } } + l:; // { dg-error "'goto' is not a constant expression" "" { target c++23 } .-1 } return 0; } catch (...) { long int c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" "" { target c++17_down } } - static float d = 2.0f;// { dg-error "'d' declared 'static' in 'constexpr' function" } - goto l2; // { dg-error "'goto' in 'constexpr' function" } + static float d = 2.0f;// { dg-error "'d' declared 'static' in 'constexpr' function only available with" "" { target c++20_down } } + goto l2; // { dg-error "'goto' in 'constexpr' function only available with" "" { target c++20_down } } l2:; return -1; } @@ -20,20 +20,20 @@ try { // { dg-warning "function-try-bl constexpr int bar () { int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" "" { target c++17_down } } - static long double b = 3.0;// { dg-error "'b' declared 'static' in 'constexpr' function" } - goto l; // { dg-error "'goto' in 'constexpr' function" } - l:; + static long double b = 3.0;// { dg-error "'b' declared 'static' in 'constexpr' function only available with" "" { target c++20_down } } + goto l; // { dg-error "'goto' in 'constexpr' function only available with" "" { target c++20_down } } + l:; // { dg-error "'goto' is not a constant expression" "" { target c++23 } .-1 } try { // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } } short c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" "" { target c++17_down } } - static float d; // { dg-error "'d' declared 'static' in 'constexpr' function" } + static float d; // { dg-error "'d' declared 'static' in 'constexpr' function only available with" "" { target c++20_down } } // { dg-error "uninitialized variable 'd' in 'constexpr' function" "" { target c++17_down } .-1 } - goto l2; // { dg-error "'goto' in 'constexpr' function" } + goto l2; // { dg-error "'goto' in 'constexpr' function only available with" "" { target c++20_down } } l2:; return 0; } catch (int) { char e; // { dg-error "uninitialized variable 'e' in 'constexpr' function" "" { target c++17_down } } - static int f = 5; // { dg-error "'f' declared 'static' in 'constexpr' function" } - goto l3; // { dg-error "'goto' in 'constexpr' function" } + static int f = 5; // { dg-error "'f' declared 'static' in 'constexpr' function only available with" "" { target c++20_down } } + goto l3; // { dg-error "'goto' in 'constexpr' function only available with" "" { target c++20_down } } l3:; return 1; } --- gcc/testsuite/g++.dg/cpp2a/constexpr-dtor3.C.jj 2021-04-14 19:19:14.049804260 +0200 +++ gcc/testsuite/g++.dg/cpp2a/constexpr-dtor3.C 2021-10-05 13:40:48.282564167 +0200 @@ -180,6 +180,6 @@ f7 () constexpr int f8 () { - T t4; // { dg-error "variable 't4' of non-literal type 'T' in 'constexpr' function" } + T t4; // { dg-error "variable 't4' of non-literal type 'T' in 'constexpr' function only available with" "" { target c++20_down } } return 0; } --- gcc/testsuite/g++.dg/cpp2a/consteval3.C.jj 2020-02-28 23:21:00.540567921 +0100 +++ gcc/testsuite/g++.dg/cpp2a/consteval3.C 2021-10-05 13:42:17.371322962 +0200 @@ -1,5 +1,4 @@ -// { dg-do compile } -// { dg-options "-std=c++2a" } +// { dg-do compile { target c++20 } } struct S { S () : a (0), b (1) {} int a, b; }; int f1 (); // { dg-message "previous declaration 'int f1\\(\\)'" } @@ -57,7 +56,7 @@ template consteval float f12 (float x); consteval int f13 (int x) { - static int a = 5; // { dg-error "'a' declared 'static' in 'consteval' function" } - thread_local int b = 6; // { dg-error "'b' declared 'thread_local' in 'consteval' function" } + static int a = 5; // { dg-error "'a' declared 'static' in 'consteval' function only available with" "" { target c++20_only } } + thread_local int b = 6; // { dg-error "'b' declared 'thread_local' in 'consteval' function only available with" "" { target c++20_only } } return x; }