[v2] c++: Implement C++23 P2242R3 - Non-literal variables (and labels and gotos) in constexpr functions
Commit Message
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 "
> > "%<static%> in %<constexpr%> 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 <jakub@redhat.com>
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) <case DECL_EXPR>: Diagnose declarations
of initialization of static or thread_local vars.
(cxx_eval_constant_expression) <case GOTO_EXPR>: Diagnose goto
statements for C++23.
(potential_constant_expression_1) <case DECL_EXPR>: Swap the
CP_DECL_THREAD_LOCAL_P and TREE_STATIC checks.
(potential_constant_expression_1) <case LABEL_EXPR>: 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
Comments
On 10/5/21 18:24, Jakub Jelinek wrote:
> 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 "
>>> "%<static%> in %<constexpr%> 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.
OK.
> 2021-10-06 Jakub Jelinek <jakub@redhat.com>
>
> 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) <case DECL_EXPR>: Diagnose declarations
> of initialization of static or thread_local vars.
> (cxx_eval_constant_expression) <case GOTO_EXPR>: Diagnose goto
> statements for C++23.
> (potential_constant_expression_1) <case DECL_EXPR>: Swap the
> CP_DECL_THREAD_LOCAL_P and TREE_STATIC checks.
> (potential_constant_expression_1) <case LABEL_EXPR>: 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.
>
> --- 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 ("%<goto%> in %<constexpr%> function");
> + error ("%<goto%> in %<constexpr%> 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 %<thread_local%> in %qs function", decl,
> + "%qD declared %<thread_local%> 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 %<static%> in %qs function", decl,
> + "%qD declared %<static%> 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 "
> - "%<constexpr%> function", decl, type);
> + "%<constexpr%> 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, "%<goto%> 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 "
> - "%<static%> in %<constexpr%> context", tmp);
> + "%<thread_local%> in %<constexpr%> 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 "
> - "%<thread_local%> in %<constexpr%> context", tmp);
> + "%<static%> in %<constexpr%> 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 %<constexpr%> 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;
> }
>
> Jakub
>
@@ -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)
{
@@ -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 ("%<goto%> in %<constexpr%> function");
+ error ("%<goto%> in %<constexpr%> function only available with "
+ "%<-std=c++2b%> or %<-std=gnu++2b%>");
cp_function_chain->invalid_constexpr = true;
}
@@ -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 %<thread_local%> in %qs function", decl,
+ "%qD declared %<thread_local%> 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 %<static%> in %qs function", decl,
+ "%qD declared %<static%> in %qs function only available "
+ "with %<-std=c++2b%> or %<-std=gnu++2b%>", decl,
DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
? "consteval" : "constexpr");
else
@@ -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 "
- "%<constexpr%> function", decl, type);
+ "%<constexpr%> 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, "%<goto%> 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 "
- "%<static%> in %<constexpr%> context", tmp);
+ "%<thread_local%> in %<constexpr%> 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 "
- "%<thread_local%> in %<constexpr%> context", tmp);
+ "%<static%> in %<constexpr%> 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 %<constexpr%> function only "
+ "available with %<-std=c++2b%> or %<-std=gnu++2b%>");
return false;
case ANNOTATE_EXPR:
@@ -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
@@ -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
@@ -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" }
@@ -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;
+}
@@ -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" }
@@ -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" }
@@ -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;
+}
@@ -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 }
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}