On 3/22/22 03:35, Jakub Jelinek wrote:
Hi!

C++14 to C++20 apparently should allow extern thread_local declarations in
constexpr functions, however useless they are there (because accessing
such vars is not valid in a constant expression, perhaps sizeof/decltype).
P2242 changed that for C++23 to passing through declaration but
https://cplusplus.github.io/CWG/issues/2552.html
has been filed for it yesterday.

The following patch implements the proposed wording of CWG 2552 in addition
to fixing the C++14 - C++20 handling bug.
If you'd like instead to keep the current pedantic C++23 wording for now,
that would mean taking out the first hunk (cxx_eval_constant_expression) and
g++.dg/cpp23/constexpr-nonlit2.C hunk.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk
(or ok without those 2 hunks for now)?

OK as a whole.

2022-03-22  Jakub Jelinek  <ja...@redhat.com>

        PR c++/104994
        * constexpr.cc (cxx_eval_constant_expression): Don't diagnose passing
        through extern thread_local declarations.  Change wording from
        declaration to definition.
        (potential_constant_expression_1): Don't diagnose extern thread_local
        declarations.  Change wording from declared to defined.
        * decl.cc (start_decl): Likewise.

        * g++.dg/diagnostic/constexpr1.C: Change expected diagnostic wording
        from declared to defined.
        * g++.dg/cpp23/constexpr-nonlit1.C: Likewise.
        (garply): Change dg-error into dg-bogus.
        * g++.dg/cpp23/constexpr-nonlit2.C: Change expected diagnostic wording
        from declaration to definition.
        * g++.dg/cpp23/constexpr-nonlit6.C: Change expected diagnostic wording
        from declared to defined.
        * g++.dg/cpp23/constexpr-nonlit7.C: New test.
        * g++.dg/cpp2a/constexpr-try5.C: Change expected diagnostic wording
        from declared to defined.
        * g++.dg/cpp2a/consteval3.C: Likewise.

--- gcc/cp/constexpr.cc.jj      2022-03-18 19:02:18.964688873 +0100
+++ gcc/cp/constexpr.cc 2022-03-21 15:52:09.000602363 +0100
@@ -6723,17 +6723,18 @@ cxx_eval_constant_expression (const cons
          }
if (VAR_P (r)
-           && (TREE_STATIC (r) || CP_DECL_THREAD_LOCAL_P (r))
+           && (TREE_STATIC (r)
+               || (CP_DECL_THREAD_LOCAL_P (r) && !DECL_REALLY_EXTERN (r)))
            /* Allow __FUNCTION__ etc.  */
            && !DECL_ARTIFICIAL (r))
          {
            if (!ctx->quiet)
              {
                if (CP_DECL_THREAD_LOCAL_P (r))
-                 error_at (loc, "control passes through declaration of %qD "
+                 error_at (loc, "control passes through definition of %qD "
                                 "with thread storage duration", r);
                else
-                 error_at (loc, "control passes through declaration of %qD "
+                 error_at (loc, "control passes through definition of %qD "
                                 "with static storage duration", r);
              }
            *non_constant_p = true;
@@ -9188,17 +9189,17 @@ potential_constant_expression_1 (tree t,
        tmp = DECL_EXPR_DECL (t);
        if (VAR_P (tmp) && !DECL_ARTIFICIAL (tmp))
        {
-         if (CP_DECL_THREAD_LOCAL_P (tmp))
+         if (CP_DECL_THREAD_LOCAL_P (tmp) && !DECL_REALLY_EXTERN (tmp))
            {
              if (flags & tf_error)
-               error_at (DECL_SOURCE_LOCATION (tmp), "%qD declared "
+               error_at (DECL_SOURCE_LOCATION (tmp), "%qD defined "
                          "%<thread_local%> in %<constexpr%> context", tmp);
              return false;
            }
          else if (TREE_STATIC (tmp))
            {
              if (flags & tf_error)
-               error_at (DECL_SOURCE_LOCATION (tmp), "%qD declared "
+               error_at (DECL_SOURCE_LOCATION (tmp), "%qD defined "
                          "%<static%> in %<constexpr%> context", tmp);
              return false;
            }
--- gcc/cp/decl.cc.jj   2022-03-14 10:34:34.246922669 +0100
+++ gcc/cp/decl.cc      2022-03-21 15:51:17.053317191 +0100
@@ -5774,15 +5774,15 @@ start_decl (const cp_declarator *declara
        && cxx_dialect < cxx23)
      {
        bool ok = false;
-      if (CP_DECL_THREAD_LOCAL_P (decl))
+      if (CP_DECL_THREAD_LOCAL_P (decl) && !DECL_REALLY_EXTERN (decl))
        error_at (DECL_SOURCE_LOCATION (decl),
-                 "%qD declared %<thread_local%> in %qs function only "
+                 "%qD defined %<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 only available "
+                 "%qD defined %<static%> in %qs function only available "
                  "with %<-std=c++2b%> or %<-std=gnu++2b%>", decl,
                  DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
                  ? "consteval" : "constexpr");
--- gcc/testsuite/g++.dg/diagnostic/constexpr1.C.jj     2021-12-30 
15:12:43.263149870 +0100
+++ gcc/testsuite/g++.dg/diagnostic/constexpr1.C        2022-03-21 
16:02:53.017740314 +0100
@@ -1,7 +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." "" { target c++20_down } }
-// { dg-error "40:.i. declared .thread_local. in .constexpr. context" "" { 
target c++23 } .-1 }
+constexpr int foo() { thread_local int i __attribute__((unused)) {}; return 1; }  // { dg-error 
"40:.i. defined .thread_local." "" { target c++20_down } }
+// { dg-error "40:.i. defined .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." "" { target c++20_down } }
-// { dg-error "34:.i. declared .static. in .constexpr. context" "" { target 
c++23 } .-1 }
+constexpr int bar() { static int i __attribute__((unused)) {}; return 1; }  // { dg-error 
"34:.i. defined .static." "" { target c++20_down } }
+// { dg-error "34:.i. defined .static. in .constexpr. context" "" { target 
c++23 } .-1 }
--- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit1.C.jj   2021-12-30 
15:12:43.260149912 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit1.C      2022-03-21 
15:30:09.210796311 +0100
@@ -23,7 +23,7 @@ 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 } }
+  static int a;        // { dg-error "'a' defined '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 }
  }
@@ -32,7 +32,7 @@ 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 } }
+  thread_local int a;  // { dg-error "'a' defined '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 }
  }
@@ -41,7 +41,7 @@ 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 } }
+  extern thread_local int a;   // { dg-bogus "'thread_local' in 'constexpr' function only 
available with" "" { target c++20_down } }
    return ++a;
  }
--- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit2.C.jj 2021-12-30 15:12:43.260149912 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit2.C      2022-03-21 
15:30:41.759347320 +0100
@@ -24,7 +24,7 @@ baz (int x)
  {
    if (!x)
      return 1;
-  static int a;                // { dg-error "control passes through declaration of 
'a' with static storage duration" }
+  static int a;                // { dg-error "control passes through definition of 
'a' with static storage duration" }
    return ++a;
  }
@@ -33,7 +33,7 @@ qux (int x)
  {
    if (!x)
      return 1;
-  thread_local int a;  // { dg-error "control passes through declaration of 'a' 
with thread storage duration" }
+  thread_local int a;  // { dg-error "control passes through definition of 'a' with 
thread storage duration" }
    return ++a;
  }
--- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit6.C.jj 2021-12-30 15:12:43.260149912 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit6.C      2022-03-21 
15:36:56.993172539 +0100
@@ -13,13 +13,13 @@ lab:
  constexpr int
  bar ()
  {
-  static int a;                // { dg-error "'a' declared 'static' in 'constexpr' 
context" }
+  static int a;                // { dg-error "'a' defined 'static' in 'constexpr' 
context" }
    return ++a;
  }
constexpr int
  baz (int x)
  {
-  thread_local int a;  // { dg-error "'a' declared 'thread_local' in 'constexpr' 
context" }
+  thread_local int a;  // { dg-error "'a' defined 'thread_local' in 'constexpr' 
context" }
    return ++a;
  }
--- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit7.C.jj   2022-03-21 
16:05:28.992594010 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit7.C      2022-03-21 
16:20:06.291535273 +0100
@@ -0,0 +1,6 @@
+// PR c++/104994
+// CWG2552
+// { dg-do compile { target c++14 } }
+
+constexpr bool foo () { extern thread_local int t; return true; }
+static constexpr bool a = foo ();
--- gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C.jj      2021-12-30 
15:12:43.262149884 +0100
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C 2022-03-21 16:02:07.512366493 
+0100
@@ -5,14 +5,14 @@
  constexpr int foo ()
  try {                 // { dg-warning "function-try-block body of 'constexpr' function only 
available with" "" { target c++17_down } }
    int a;              // { dg-error "uninitialized variable 'a' in 'constexpr' 
function" "" { target c++17_down } }
-  static double b = 1.0;// { dg-error "'b' declared 'static' in 'constexpr' function only 
available with" "" { target c++20_down } }
-                       // { dg-error "'b' declared 'static' in 'constexpr' context" 
"" { target c++23 } .-1 }
+  static double b = 1.0;// { dg-error "'b' defined 'static' in 'constexpr' function only 
available with" "" { target c++20_down } }
+                       // { dg-error "'b' defined '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 only 
available with" "" { target c++20_down } }
+  static float d = 2.0f;// { dg-error "'d' defined '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;
@@ -21,20 +21,20 @@ try {                       // { dg-warning "function-try-bl
  constexpr int bar ()
  {
    int a;              // { dg-error "uninitialized variable 'a' in 'constexpr' 
function" "" { target c++17_down } }
-  static long double b = 3.0;// { dg-error "'b' declared 'static' in 'constexpr' function 
only available with" "" { target c++20_down } }
-                       // { dg-error "'b' declared 'static' in 'constexpr' context" 
"" { target c++23 } .-1 }
+  static long double b = 3.0;// { dg-error "'b' defined 'static' in 'constexpr' function only 
available with" "" { target c++20_down } }
+                       // { dg-error "'b' defined '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 only 
available with" "" { target c++20_down } }
+    static float d;    // { dg-error "'d' defined '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 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 only 
available with" "" { target c++20_down } }
+    static int f = 5;  // { dg-error "'f' defined '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/consteval3.C.jj  2021-12-30 15:12:43.262149884 
+0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval3.C     2022-03-21 16:01:26.477931150 
+0100
@@ -56,8 +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 
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 } }
+  static int a = 5;            // { dg-error "'a' defined 'static' in 'consteval' function 
only available with" "" { target c++20_only } }
+                               // { dg-error "'a' defined 'static' in 'constexpr' 
context" "" { target c++23 } .-1 }
+  thread_local int b = 6;      // { dg-error "'b' defined 'thread_local' in 'consteval' 
function only available with" "" { target c++20_only } }
    return x;
  }


        Jakub


Reply via email to