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
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);
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. */
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() {
{
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);
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);
}
*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)))
/* 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);
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.
--- /dev/null
+// 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> ();
+}
--- /dev/null
+// 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; }
--- /dev/null
+// 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 ();
+}
--- /dev/null
+// 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 ();
+}
--- /dev/null
+// 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 ();
+}
--- /dev/null
+// 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 ();
+}
--- /dev/null
+// 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 ();
+}
--- /dev/null
+// 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 ();
+}
--- /dev/null
+// 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 ();
+}
--- /dev/null
+// 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 ();
+}
--- /dev/null
+// 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 ();
+}
--- /dev/null
+// 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 ();
+}
--- /dev/null
+// 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 ();
+}
--- /dev/null
+// 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 ();
+}