]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Implement C++23 P2242R3 - Non-literal variables (and labels and gotos) in conste...
authorJakub Jelinek <jakub@redhat.com>
Wed, 6 Oct 2021 08:28:31 +0000 (10:28 +0200)
committerJakub Jelinek <jakub@redhat.com>
Wed, 6 Oct 2021 08:28:31 +0000 (10:28 +0200)
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.

2021-10-06  Jakub Jelinek  <jakub@redhat.com>

PR c++/102612
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.

17 files changed:
gcc/c-family/c-cppbuiltin.c
gcc/cp/constexpr.c
gcc/cp/decl.c
gcc/cp/parser.c
gcc/testsuite/g++.dg/cpp1y/constexpr-label.C
gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C
gcc/testsuite/g++.dg/cpp23/constexpr-nonlit1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/constexpr-nonlit2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/constexpr-nonlit3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/constexpr-nonlit4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/constexpr-nonlit5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/constexpr-nonlit6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C
gcc/testsuite/g++.dg/cpp2a/consteval3.C
gcc/testsuite/g++.dg/cpp2a/constexpr-dtor3.C
gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C
gcc/testsuite/g++.dg/diagnostic/constexpr1.C

index a2992733114e56b697a0bf6fcb48128dccaef131..60e9e05206289fe7ef2d7cf7096eb0581f28197d 100644 (file)
@@ -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)
         {
index e95ff00774fce83743e3a56ebe977001eaeb839d..66d5221692ab6adb980e3f1e8a06d59dbbaa3d64 100644 (file)
@@ -109,14 +109,15 @@ ensure_literal_type_for_constexpr_object (tree decl)
              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 constexpr_ctx *ctx, tree t,
            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 constexpr_ctx *ctx, tree t,
       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, bool want_rval, bool strict, bool now,
       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, bool want_rval, bool strict, bool now,
 
     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:
index 722e540babaf4d649877efc10a7a08a4231a4dfc..2d30c790b930dd089e9d8b7e37f6c0156325e287 100644 (file)
@@ -5709,17 +5709,20 @@ start_decl (const cp_declarator *declarator,
     }
 
   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
index c6f1a9796c5be9f6de1b3a9aa45eb5d56623d8e3..d285a45bf7dfad18611cf98462220ff874a2fa4d 100644 (file)
@@ -14176,9 +14176,11 @@ cp_parser_jump_statement (cp_parser* parser)
 
     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;
        }
 
index a2d113c186fc6216462f79c5594036d2eefef2e4..4994008a77b412032f68216401634293a25e84b3 100644 (file)
@@ -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;
 }
index 53f0f1f7a2bf032daa2f4f3522f0bad30f773501..8e9d1ea494376b4bbb6fceee4da57383fa7fbc3f 100644 (file)
@@ -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;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit1.C b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit1.C
new file mode 100644 (file)
index 0000000..c80ea38
--- /dev/null
@@ -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
diff --git a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit2.C b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit2.C
new file mode 100644 (file)
index 0000000..0f7b229
--- /dev/null
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit3.C b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit3.C
new file mode 100644 (file)
index 0000000..3b5585d
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit4.C b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit4.C
new file mode 100644 (file)
index 0000000..e4ed2e3
--- /dev/null
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit5.C b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit5.C
new file mode 100644 (file)
index 0000000..838f282
--- /dev/null
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit6.C b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit6.C
new file mode 100644 (file)
index 0000000..11cb518
--- /dev/null
@@ -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;
+}
index 7070f598d395fe1bf863894ee6530b79a3c04a4d..8bb3bf1f00f412a577d82cdce71414b4398fa451 100644 (file)
 
 #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
index 9fb1f1a0b12520aaea31bdaed297dc3c78a7ead4..8f9316411b5ad40d87304d8a3de30857cfc6da91 100644 (file)
@@ -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); // { dg-error "explicit instantiation sh
 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;
 }
index 7700bb7b03658a908365d2aa25bb4cd7d3848f34..69fe9e26654f83983d5ce9d47074ee5e440396d4 100644 (file)
@@ -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;
 }
index 3b51bf7c9019f5fa52e21b7b2d6b9a167862f9bc..ed5e40dff955479542ad90b1fe3e509826e62b78 100644 (file)
@@ -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-block body of 'constexpr' function only av
 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;
   }
index f029e86e076b9dd9e8af6cdbc8634b83b84892be..f2bcec6e4e16a6d7cff9a8acda6cf4a14c97f277 100644 (file)
@@ -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 }