From patchwork Tue Oct 5 22:24:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 45912 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 D6A513858036 for ; Tue, 5 Oct 2021 22:25:35 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D6A513858036 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1633472735; bh=LKPNFkFuw5GHrQuWxs7yLE4fPCuHjgwbYZszCd7k+sE=; h=Date:To:Subject:References:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=GnVhD9cGGA67y74xornavz+a8NPsD/YEih7wndluAhHI4OC92I5x/dMqGAzT6lXw3 jN5La7NlQIXwXtBE4qkLs3J6CsGm29hdYB43HSR/kHta3mbIFKrbKZwYjyGfr++fqZ w97ciWt/pJ1aNoM9fbtjZ6yAyZwCq/xvasQxfVE8= 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.129.124]) by sourceware.org (Postfix) with ESMTP id A24693858433 for ; Tue, 5 Oct 2021 22:25:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org A24693858433 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-45-bvkORjoWMbi9BWMydbqYOQ-1; Tue, 05 Oct 2021 18:25:01 -0400 X-MC-Unique: bvkORjoWMbi9BWMydbqYOQ-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 3C1431084681 for ; Tue, 5 Oct 2021 22:25:00 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.193.109]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 9F3539AA2F; Tue, 5 Oct 2021 22:24:59 +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 195MOvZ14125416 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Wed, 6 Oct 2021 00:24:57 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.16.1/8.16.1/Submit) id 195MOuen4124527; Wed, 6 Oct 2021 00:24:56 +0200 Date: Wed, 6 Oct 2021 00:24:56 +0200 To: Jason Merrill Subject: [PATCH, v2] c++: Implement C++23 P2242R3 - Non-literal variables (and labels and gotos) in constexpr functions Message-ID: <20211005222456.GC304296@tucnak> References: <20211005123910.GW304296@tucnak> <10d91c01-590c-1c38-6503-9acbf72d241c@redhat.com> MIME-Version: 1.0 In-Reply-To: <10d91c01-590c-1c38-6503-9acbf72d241c@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 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_H4, RCVD_IN_MSPIKE_WL, 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" On Tue, Oct 05, 2021 at 05:24:09PM -0400, Jason Merrill wrote: > That seems correct to me. If they have static initialization, they are > initialized. Ok, I've included those tests in the patch now too. > > @@ -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 " > > Hmm, I wouldn't expect this hunk to be needed; if there's a control path > that doesn't include these declarations, we shouldn't hit these errors. You're right, that is unnecessary, if the static/thread_local declaration is unconditional, we can (but aren't required to) diagnose it even when the constexpr function is never evaluated in constant expressions. But, I had to swap the TREE_STATIC and CP_DECL_THREAD_LOCAL_P checks because the latter implies the former and so static would be always printed instead of thread_local for thread_local declarations. > > @@ -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"); > > Let's change this message to "only available with..." like the others. Changed too. Here is an updated patch (also after IRC chat with Jonathan changed the __cpp_constexpr value from 202103L that was in the paper to 202110L). Passes the tests that are modified so far, full bootstrap/regtest queued after my current one finishes. 2021-10-06 Jakub Jelinek gcc/c-family/ * c-cppbuiltin.c (c_cpp_builtins): For -std=c++23 predefine __cpp_constexpr to 202110L 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) : Swap the CP_DECL_THREAD_LOCAL_P and TREE_STATIC checks. (potential_constant_expression_1) : Allow labels for C++23. Adjust error message for older standards to mention it. gcc/testsuite/ * g++.dg/cpp23/feat-cxx2b.C: Expect __cpp_constexpr 202110L 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/cpp23/constexpr-nonlit4.C: New test. * g++.dg/cpp23/constexpr-nonlit5.C: New test. * g++.dg/cpp23/constexpr-nonlit6.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-10-05 22:27:39.387959561 +0200 +++ gcc/c-family/c-cppbuiltin.c 2021-10-05 23:47:13.865054265 +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=202110L"); } if (flag_concepts) { --- gcc/cp/parser.c.jj 2021-10-05 22:27:39.551957300 +0200 +++ gcc/cp/parser.c 2021-10-05 23:47:13.895053851 +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-10-05 22:27:39.502957976 +0200 +++ gcc/cp/decl.c 2021-10-05 23:47:13.916053561 +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-10-05 22:27:48.009840663 +0200 +++ gcc/cp/constexpr.c 2021-10-06 00:08:16.809608246 +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); + "% 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,18 +8765,18 @@ potential_constant_expression_1 (tree t, tmp = DECL_EXPR_DECL (t); if (VAR_P (tmp) && !DECL_ARTIFICIAL (tmp)) { - if (TREE_STATIC (tmp)) + if (CP_DECL_THREAD_LOCAL_P (tmp)) { if (flags & tf_error) error_at (DECL_SOURCE_LOCATION (tmp), "%qD declared " - "% in % context", tmp); + "% in % context", tmp); return false; } - else if (CP_DECL_THREAD_LOCAL_P (tmp)) + else if (TREE_STATIC (tmp)) { if (flags & tf_error) error_at (DECL_SOURCE_LOCATION (tmp), "%qD declared " - "% in % context", tmp); + "% in % context", tmp); return false; } else if (!check_for_uninitialized_const_var @@ -9025,10 +9054,11 @@ 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"); + error_at (loc, "label definition in % function only " + "available with %<-std=c++2b%> or %<-std=gnu++2b%>"); return false; case ANNOTATE_EXPR: --- gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C.jj 2021-10-05 22:27:39.594956707 +0200 +++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C 2021-10-06 00:02:37.480296129 +0200 @@ -134,8 +134,8 @@ #ifndef __cpp_constexpr # error "__cpp_constexpr" -#elif __cpp_constexpr != 201907 -# error "__cpp_constexpr != 201907" +#elif __cpp_constexpr != 202110 +# error "__cpp_constexpr != 202110" #endif #ifndef __cpp_decltype_auto --- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit1.C.jj 2021-10-05 23:47:13.934053312 +0200 +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit1.C 2021-10-05 23:52:09.879965662 +0200 @@ -0,0 +1,68 @@ +// P2242R3 +// { dg-do compile { target c++14 } } + +constexpr int +foo () +{ +lab: // { dg-error "label definition in 'constexpr' function only available with" "" { 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 >= 202110L +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 23:47:13.934053312 +0200 +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit2.C 2021-10-06 00:14:12.586693301 +0200 @@ -0,0 +1,54 @@ +// 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; +} + +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 = corge (1); // { dg-message "in 'constexpr' expansion of" } --- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit3.C.jj 2021-10-05 23:47:13.934053312 +0200 +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit3.C 2021-10-05 23:47:13.934053312 +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/cpp23/constexpr-nonlit4.C.jj 2021-10-05 23:58:42.437543278 +0200 +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit4.C 2021-10-05 23:55:57.699818980 +0200 @@ -0,0 +1,57 @@ +// { dg-do compile } +// { dg-options "-std=c++2b" } + +int qux (); + +constexpr int +foo (int x) +{ + switch (x) + { + static int v = qux (); + case 12: + return 1; + } + return 0; +} + +constexpr int +bar (int x) +{ + switch (x) + { + thread_local int v = qux (); + case 12: + return 1; + } + return 0; +} + +constexpr int +baz (int x) +{ + switch (x) + { + static const int v = qux (); // { dg-message "'v' was not initialized with a constant expression" } + case 12: + return v; + } + return 0; +} + +constexpr int +corge (int x) +{ + switch (x) + { + const thread_local int v = qux (); // { dg-message "'v' was not initialized with a constant expression" } + case 12: + return v; + } + return 0; +} + +constexpr int a = foo (12); +constexpr int b = bar (12); +constexpr int c = baz (12); // { dg-error "the value of 'v' is not usable in a constant expression" } +constexpr int d = corge (12); // { dg-error "the value of 'v' is not usable in a constant expression" } --- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit5.C.jj 2021-10-05 23:58:47.250476787 +0200 +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit5.C 2021-10-05 23:58:12.130961967 +0200 @@ -0,0 +1,57 @@ +// { dg-do compile } +// { dg-options "-std=c++2b" } + +int qux (); + +constexpr int +foo (int x) +{ + switch (x) + { + static const int v = 6; + case 12: + return v; + } + return 0; +} + +constexpr int +bar (int x) +{ + switch (x) + { + thread_local const int v = 7; + case 12: + return 7; + } + return 0; +} + +constexpr int +baz (int x) +{ + switch (x) + { + static int v = 6; // { dg-message "int v' is not const" } + case 12: + return v; + } + return 0; +} + +constexpr int +corge (int x) +{ + switch (x) + { + thread_local int v = 6; // { dg-message "int v' is not const" } + case 12: + return v; + } + return 0; +} + +constexpr int a = foo (12); +constexpr int b = bar (12); +constexpr int c = baz (12); // { dg-error "the value of 'v' is not usable in a constant expression" } +constexpr int d = corge (12); // { dg-error "the value of 'v' is not usable in a constant expression" } --- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit6.C.jj 2021-10-06 00:12:19.927249541 +0200 +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit6.C 2021-10-06 00:15:32.680587909 +0200 @@ -0,0 +1,25 @@ +// P2242R3 +// { dg-do compile } +// { dg-options "-std=c++2b" } + +constexpr int +foo () +{ + goto lab; // { dg-error "'goto' is not a constant expression" } +lab: + return 1; +} + +constexpr int +bar () +{ + static int a; // { dg-error "'a' declared 'static' in 'constexpr' context" } + return ++a; +} + +constexpr int +baz (int x) +{ + thread_local int a; // { dg-error "'a' declared 'thread_local' in 'constexpr' context" } + return ++a; +} --- gcc/testsuite/g++.dg/diagnostic/constexpr1.C.jj 2020-01-12 11:54:37.155402214 +0100 +++ gcc/testsuite/g++.dg/diagnostic/constexpr1.C 2021-10-06 00:08:47.990177482 +0200 @@ -1,5 +1,7 @@ // { 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 } } +// { dg-error "40:.i. declared .thread_local. in .constexpr. context" "" { target c++23 } .-1 } -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 } } +// { dg-error "34:.i. declared .static. in .constexpr. context" "" { target c++23 } .-1 } --- gcc/testsuite/g++.dg/cpp1y/constexpr-label.C.jj 2020-11-22 19:11:44.103588521 +0100 +++ gcc/testsuite/g++.dg/cpp1y/constexpr-label.C 2021-10-05 23:52:09.879965662 +0200 @@ -4,6 +4,6 @@ constexpr int f () { -x: // { dg-error "label definition is not a constant expression" } +x: // { dg-error "label definition in 'constexpr' function only available with" "" { target c++20_down } } return 42; } --- gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C.jj 2020-01-12 11:54:37.115402818 +0100 +++ gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C 2021-10-06 00:01:48.736969524 +0200 @@ -4,12 +4,12 @@ struct A { A(); }; constexpr int f(int i) { static int j = i; // { dg-error "static" } - thread_local int l = i; // { dg-error "thread_local" } - goto foo; // { dg-error "goto" } + thread_local int l = i; // { dg-error "thread_local" "" { target c++20_down } } + goto foo; // { dg-error "goto" "" { target c++20_down } } 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-12 11:54:37.141402425 +0100 +++ gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C 2021-10-06 00:11:41.897774924 +0200 @@ -5,14 +5,15 @@ 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" } + static double b = 1.0;// { dg-error "'b' declared 'static' in 'constexpr' function only available with" "" { target c++20_down } } + // { dg-error "'b' declared 'static' in 'constexpr' context" "" { target c++23 } .-1 } + goto l; // { dg-error "'goto' in 'constexpr' function only available with" "" { target c++20_down } } l:; 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 +21,21 @@ 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" } + static long double b = 3.0;// { dg-error "'b' declared 'static' in 'constexpr' function only available with" "" { target c++20_down } } + // { dg-error "'b' declared 'static' in 'constexpr' context" "" { target c++23 } .-1 } + goto l; // { dg-error "'goto' in 'constexpr' function only available with" "" { target c++20_down } } l:; 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 10:48:41.330103579 +0200 +++ gcc/testsuite/g++.dg/cpp2a/constexpr-dtor3.C 2021-10-05 23:47:13.970052815 +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 17:34:56.393567559 +0100 +++ gcc/testsuite/g++.dg/cpp2a/consteval3.C 2021-10-06 00:10:50.161489668 +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,8 @@ 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 } } + // { dg-error "'a' declared 'static' in 'constexpr' context" "" { target c++23 } .-1 } + thread_local int b = 6; // { dg-error "'b' declared 'thread_local' in 'consteval' function only available with" "" { target c++20_only } } return x; }