re PR c++/60702 (thread_local initialization)
authorJakub Jelinek <jakub@redhat.com>
Fri, 22 Mar 2019 14:42:57 +0000 (15:42 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 22 Mar 2019 14:42:57 +0000 (15:42 +0100)
PR c++/60702
* cp-tree.h (get_tls_wrapper_fn): Remove declaration.
(maybe_get_tls_wrapper_call): Declare.
* decl2.c (get_tls_wrapper_fn): Make static.
(maybe_get_tls_wrapper_call): New function.
* typeck.c (build_class_member_access_expr): Handle accesses to TLS
variables.
* semantics.c (finish_qualified_id_expr): Likewise.
(finish_id_expression_1): Use maybe_get_tls_wrapper_call.
* pt.c (tsubst_copy_and_build): Likewise.

* g++.dg/tls/thread_local11.C: New test.
* g++.dg/tls/thread_local11.h: New test.
* g++.dg/tls/thread_local12a.C: New test.
* g++.dg/tls/thread_local12b.C: New test.
* g++.dg/tls/thread_local12c.C: New test.
* g++.dg/tls/thread_local12d.C: New test.
* g++.dg/tls/thread_local12e.C: New test.
* g++.dg/tls/thread_local12f.C: New test.
* g++.dg/tls/thread_local12g.C: New test.
* g++.dg/tls/thread_local12h.C: New test.
* g++.dg/tls/thread_local12i.C: New test.
* g++.dg/tls/thread_local12j.C: New test.
* g++.dg/tls/thread_local12k.C: New test.
* g++.dg/tls/thread_local12l.C: New test.

From-SVN: r269875

21 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl2.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/tls/thread_local11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local11.h [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local12a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local12b.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local12c.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local12d.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local12e.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local12f.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local12g.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local12h.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local12i.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local12j.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local12k.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local12l.C [new file with mode: 0644]

index 71f9d67..16f1b8e 100644 (file)
@@ -1,5 +1,16 @@
 2019-03-22  Jakub Jelinek  <jakub@redhat.com>
 
+       PR c++/60702
+       * cp-tree.h (get_tls_wrapper_fn): Remove declaration.
+       (maybe_get_tls_wrapper_call): Declare.
+       * decl2.c (get_tls_wrapper_fn): Make static.
+       (maybe_get_tls_wrapper_call): New function.
+       * typeck.c (build_class_member_access_expr): Handle accesses to TLS
+       variables.
+       * semantics.c (finish_qualified_id_expr): Likewise.
+       (finish_id_expression_1): Use maybe_get_tls_wrapper_call.
+       * pt.c (tsubst_copy_and_build): Likewise.
+
        PR c++/87481
        * constexpr.c (struct constexpr_ctx): Add constexpr_ops_count member.
        (cxx_eval_constant_expression): When not skipping, not constant class
index 15e39e1..3fe91ad 100644 (file)
@@ -6513,7 +6513,7 @@ extern tree cp_build_parm_decl                    (tree, tree, tree);
 extern tree get_guard                          (tree);
 extern tree get_guard_cond                     (tree, bool);
 extern tree set_guard                          (tree);
-extern tree get_tls_wrapper_fn                 (tree);
+extern tree maybe_get_tls_wrapper_call         (tree);
 extern void mark_needed                                (tree);
 extern bool decl_needed_p                      (tree);
 extern void note_vague_linkage_fn              (tree);
index f8637da..6f23ee1 100644 (file)
@@ -3442,7 +3442,7 @@ get_tls_init_fn (tree var)
    VAR and then returns a reference to VAR.  The wrapper function is used
    in place of VAR everywhere VAR is mentioned.  */
 
-tree
+static tree
 get_tls_wrapper_fn (tree var)
 {
   /* Only C++11 TLS vars need this wrapper fn.  */
@@ -3496,6 +3496,22 @@ get_tls_wrapper_fn (tree var)
   return fn;
 }
 
+/* If EXPR is a thread_local variable that should be wrapped by init
+   wrapper function, return a call to that function, otherwise return
+   NULL.  */
+
+tree
+maybe_get_tls_wrapper_call (tree expr)
+{
+  if (VAR_P (expr)
+      && !processing_template_decl
+      && !cp_unevaluated_operand
+      && CP_DECL_THREAD_LOCAL_P (expr))
+    if (tree wrap = get_tls_wrapper_fn (expr))
+      return build_cxx_call (wrap, 0, NULL, tf_warning_or_error);
+  return NULL;
+}
+
 /* At EOF, generate the definition for the TLS wrapper function FN:
 
    T& var_wrapper() {
index 6c15419..afb7ece 100644 (file)
@@ -19403,17 +19403,10 @@ tsubst_copy_and_build (tree t,
       {
        tree r = tsubst_copy (t, args, complain, in_decl);
        /* ??? We're doing a subset of finish_id_expression here.  */
-       if (VAR_P (r)
-           && !processing_template_decl
-           && !cp_unevaluated_operand
-           && (TREE_STATIC (r) || DECL_EXTERNAL (r))
-           && CP_DECL_THREAD_LOCAL_P (r))
-         {
-           if (tree wrap = get_tls_wrapper_fn (r))
-             /* Replace an evaluated use of the thread_local variable with
-                a call to its wrapper.  */
-             r = build_cxx_call (wrap, 0, NULL, tf_warning_or_error);
-         }
+       if (tree wrap = maybe_get_tls_wrapper_call (r))
+         /* Replace an evaluated use of the thread_local variable with
+            a call to its wrapper.  */
+         r = wrap;
        else if (outer_automatic_var_p (r))
          r = process_outer_var_ref (r, complain);
 
index 599e0e3..15b766d 100644 (file)
@@ -2143,6 +2143,8 @@ finish_qualified_id_expr (tree qualifying_class,
        expr = build_qualified_name (TREE_TYPE (expr),
                                     qualifying_class, expr,
                                     template_p);
+      else if (tree wrap = maybe_get_tls_wrapper_call (expr))
+       expr = wrap;
 
       expr = convert_from_reference (expr);
     }
@@ -3788,18 +3790,10 @@ finish_id_expression_1 (tree id_expression,
          *non_integral_constant_expression_p = true;
        }
 
-      tree wrap;
-      if (VAR_P (decl)
-         && !cp_unevaluated_operand
-         && !processing_template_decl
-         && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
-         && CP_DECL_THREAD_LOCAL_P (decl)
-         && (wrap = get_tls_wrapper_fn (decl)))
-       {
-         /* Replace an evaluated use of the thread_local variable with
-            a call to its wrapper.  */
-         decl = build_cxx_call (wrap, 0, NULL, tf_warning_or_error);
-       }
+      if (tree wrap = maybe_get_tls_wrapper_call (decl))
+       /* Replace an evaluated use of the thread_local variable with
+          a call to its wrapper.  */
+       decl = wrap;
       else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
               && !dependent_p
               && variable_template_p (TREE_OPERAND (decl, 0)))
index f77e9c6..e2c5fc2 100644 (file)
@@ -2443,6 +2443,12 @@ build_class_member_access_expr (cp_expr object, tree member,
       /* A static data member.  */
       result = member;
       mark_exp_read (object);
+
+      if (tree wrap = maybe_get_tls_wrapper_call (result))
+       /* Replace an evaluated use of the thread_local variable with
+          a call to its wrapper.  */
+       result = wrap;
+
       /* If OBJECT has side-effects, they are supposed to occur.  */
       if (TREE_SIDE_EFFECTS (object))
        result = build2 (COMPOUND_EXPR, TREE_TYPE (result), object, result);
index febe7b3..8324702 100644 (file)
@@ -1,5 +1,21 @@
 2019-03-22  Jakub Jelinek  <jakub@redhat.com>
 
+       PR c++/60702
+       * g++.dg/tls/thread_local11.C: New test.
+       * g++.dg/tls/thread_local11.h: New test.
+       * g++.dg/tls/thread_local12a.C: New test.
+       * g++.dg/tls/thread_local12b.C: New test.
+       * g++.dg/tls/thread_local12c.C: New test.
+       * g++.dg/tls/thread_local12d.C: New test.
+       * g++.dg/tls/thread_local12e.C: New test.
+       * g++.dg/tls/thread_local12f.C: New test.
+       * g++.dg/tls/thread_local12g.C: New test.
+       * g++.dg/tls/thread_local12h.C: New test.
+       * g++.dg/tls/thread_local12i.C: New test.
+       * g++.dg/tls/thread_local12j.C: New test.
+       * g++.dg/tls/thread_local12k.C: New test.
+       * g++.dg/tls/thread_local12l.C: New test.
+
        PR c++/87481
        * g++.dg/cpp1y/constexpr-87481.C: New test.
 
diff --git a/gcc/testsuite/g++.dg/tls/thread_local11.C b/gcc/testsuite/g++.dg/tls/thread_local11.C
new file mode 100644 (file)
index 0000000..036d91a
--- /dev/null
@@ -0,0 +1,48 @@
+// PR c++/60702
+// { dg-do compile { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+// { dg-additional-options "-fdump-tree-gimple" }
+// { dg-final { scan-tree-dump-times "_ZTW2s1" 2 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTW2s2" 2 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTW2s3" 2 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTW2s4" 2 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTWN1T2u1E" 2 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTWN1T2u2E" 2 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTWN1T2u3E" 2 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTWN1T2u4E" 2 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTWN1T2u5E" 2 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTWN1T2u6E" 2 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTWN1T2u7E" 2 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTWN1T2u8E" 2 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTH2s1" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTH2s2" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTH2s3" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTH2s4" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTHN1T2u1E" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTHN1T2u2E" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTHN1T2u3E" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTHN1T2u4E" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTHN1T2u5E" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTHN1T2u6E" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTHN1T2u7E" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times "_ZTHN1T2u8E" 1 "gimple" } }
+
+#include "thread_local11.h"
+
+void
+foo ()
+{
+  f1 ();
+  f2 ();
+  f3 ();
+  f4 ();
+  f5 ();
+  f6 ();
+  f7<0> ();
+  f8<0> ();
+  f9<0> ();
+  f10<0> ();
+  f11<0> ();
+  f12<0> ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local11.h b/gcc/testsuite/g++.dg/tls/thread_local11.h
new file mode 100644 (file)
index 0000000..761b42d
--- /dev/null
@@ -0,0 +1,26 @@
+// PR c++/60702
+
+extern "C" void abort ();
+struct S { S () { i = 42; }; int i; };
+thread_local S s1, s2, s3, s4;
+struct T { static thread_local S u1, u2, u3, u4, u5, u6, u7, u8; int i; } t;
+thread_local S T::u1, T::u2, T::u3, T::u4, T::u5, T::u6, T::u7, T::u8;
+
+S *f1 () { return &s1; }
+int *f2 () { return &s2.i; }
+S *f3 () { return &t.u1; }
+int *f4 () { return &t.u2.i; }
+S *f5 () { return &T::u3; }
+int *f6 () { return &T::u4.i; }
+template <int N>
+S *f7 () { return &s3; }
+template <int N>
+int *f8 () { return &s4.i; }
+template <int N>
+S *f9 () { return &t.u5; }
+template <int N>
+int *f10 () { return &t.u6.i; }
+template <int N>
+S *f11 () { return &T::u7; }
+template <int N>
+int *f12 () { return &T::u8.i; }
diff --git a/gcc/testsuite/g++.dg/tls/thread_local12a.C b/gcc/testsuite/g++.dg/tls/thread_local12a.C
new file mode 100644 (file)
index 0000000..87a1716
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/60702
+// { dg-do run { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+
+#include "thread_local11.h"
+
+int
+main ()
+{
+  if (f1 ()->i != 42) abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local12b.C b/gcc/testsuite/g++.dg/tls/thread_local12b.C
new file mode 100644 (file)
index 0000000..498bace
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/60702
+// { dg-do run { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+
+#include "thread_local11.h"
+
+int
+main ()
+{
+  if (*f2 () != 42) abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local12c.C b/gcc/testsuite/g++.dg/tls/thread_local12c.C
new file mode 100644 (file)
index 0000000..92add8f
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/60702
+// { dg-do run { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+
+#include "thread_local11.h"
+
+int
+main ()
+{
+  if (f3 ()->i != 42) abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local12d.C b/gcc/testsuite/g++.dg/tls/thread_local12d.C
new file mode 100644 (file)
index 0000000..7863136
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/60702
+// { dg-do run { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+
+#include "thread_local11.h"
+
+int
+main ()
+{
+  if (*f4 () != 42) abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local12e.C b/gcc/testsuite/g++.dg/tls/thread_local12e.C
new file mode 100644 (file)
index 0000000..95c44f7
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/60702
+// { dg-do run { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+
+#include "thread_local11.h"
+
+int
+main ()
+{
+  if (f5 ()->i != 42) abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local12f.C b/gcc/testsuite/g++.dg/tls/thread_local12f.C
new file mode 100644 (file)
index 0000000..e7795dc
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/60702
+// { dg-do run { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+
+#include "thread_local11.h"
+
+int
+main ()
+{
+  if (*f6 () != 42) abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local12g.C b/gcc/testsuite/g++.dg/tls/thread_local12g.C
new file mode 100644 (file)
index 0000000..c7c964a
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/60702
+// { dg-do run { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+
+#include "thread_local11.h"
+
+int
+main ()
+{
+  if (f7<0> ()->i != 42) abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local12h.C b/gcc/testsuite/g++.dg/tls/thread_local12h.C
new file mode 100644 (file)
index 0000000..32b6841
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/60702
+// { dg-do run { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+
+#include "thread_local11.h"
+
+int
+main ()
+{
+  if (*f8<0> () != 42) abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local12i.C b/gcc/testsuite/g++.dg/tls/thread_local12i.C
new file mode 100644 (file)
index 0000000..815e14e
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/60702
+// { dg-do run { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+
+#include "thread_local11.h"
+
+int
+main ()
+{
+  if (f9<0> ()->i != 42) abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local12j.C b/gcc/testsuite/g++.dg/tls/thread_local12j.C
new file mode 100644 (file)
index 0000000..0009de1
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/60702
+// { dg-do run { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+
+#include "thread_local11.h"
+
+int
+main ()
+{
+  if (*f10<0> () != 42) abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local12k.C b/gcc/testsuite/g++.dg/tls/thread_local12k.C
new file mode 100644 (file)
index 0000000..589e872
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/60702
+// { dg-do run { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+
+#include "thread_local11.h"
+
+int
+main ()
+{
+  if (f11<0> ()->i != 42) abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local12l.C b/gcc/testsuite/g++.dg/tls/thread_local12l.C
new file mode 100644 (file)
index 0000000..273e1be
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/60702
+// { dg-do run { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+
+#include "thread_local11.h"
+
+int
+main ()
+{
+  if (*f12<0> () != 42) abort ();
+}