c++: Drop TREE_READONLY on vars (possibly) initialized by tls wrapper [PR109164]
The following two testcases are miscompiled, because we keep TREE_READONLY on the vars even when they are (possibly) dynamically initialized by a TLS wrapper function. Normally cp_finish_decl drops TREE_READONLY from vars which need dynamic initialization, but for TLS we do this kind of initialization upon every access to those variables. Keeping them TREE_READONLY means e.g. PRE can hoist loads from those before loops which contain the TLS wrapper calls, so we can access the TLS variables before they are initialized. 2023-03-20 Jakub Jelinek <jakub@redhat.com> PR c++/109164 * cp-tree.h (var_needs_tls_wrapper): Declare. * decl2.cc (var_needs_tls_wrapper): No longer static. * decl.cc (cp_finish_decl): Clear TREE_READONLY on TLS variables for which a TLS wrapper will be needed. * g++.dg/tls/thread_local13.C: New test. * g++.dg/tls/thread_local13-aux.cc: New file. * g++.dg/tls/thread_local14.C: New test. * g++.dg/tls/thread_local14-aux.cc: New file.
This commit is contained in:
parent
c67f312d20
commit
0a846340b9
7 changed files with 115 additions and 1 deletions
|
@ -6989,6 +6989,7 @@ extern void copy_linkage (tree, tree);
|
|||
extern tree get_guard (tree);
|
||||
extern tree get_guard_cond (tree, bool);
|
||||
extern tree set_guard (tree);
|
||||
extern bool var_needs_tls_wrapper (tree);
|
||||
extern tree maybe_get_tls_wrapper_call (tree);
|
||||
extern void mark_needed (tree);
|
||||
extern bool decl_needed_p (tree);
|
||||
|
|
|
@ -8706,6 +8706,18 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
|
|||
if (!decl_maybe_constant_destruction (decl, type))
|
||||
TREE_READONLY (decl) = 0;
|
||||
}
|
||||
else if (VAR_P (decl)
|
||||
&& CP_DECL_THREAD_LOCAL_P (decl)
|
||||
&& (!DECL_EXTERNAL (decl) || flag_extern_tls_init)
|
||||
&& (was_readonly || TREE_READONLY (decl))
|
||||
&& var_needs_tls_wrapper (decl))
|
||||
{
|
||||
/* TLS variables need dynamic initialization by the TLS wrapper
|
||||
function, we don't want to hoist accesses to it before the
|
||||
wrapper. */
|
||||
was_readonly = 0;
|
||||
TREE_READONLY (decl) = 0;
|
||||
}
|
||||
|
||||
make_rtl_for_nonlocal_decl (decl, init, asmspec);
|
||||
|
||||
|
|
|
@ -3623,7 +3623,7 @@ var_defined_without_dynamic_init (tree var)
|
|||
/* Returns true iff VAR is a variable that needs uses to be
|
||||
wrapped for possible dynamic initialization. */
|
||||
|
||||
static bool
|
||||
bool
|
||||
var_needs_tls_wrapper (tree var)
|
||||
{
|
||||
return (!error_operand_p (var)
|
||||
|
|
35
gcc/testsuite/g++.dg/tls/thread_local13-aux.cc
Normal file
35
gcc/testsuite/g++.dg/tls/thread_local13-aux.cc
Normal file
|
@ -0,0 +1,35 @@
|
|||
// PR c++/109164
|
||||
|
||||
struct S { virtual void foo (); int s; };
|
||||
extern bool baz ();
|
||||
|
||||
void
|
||||
S::foo ()
|
||||
{
|
||||
if (s != 42)
|
||||
__builtin_abort ();
|
||||
}
|
||||
|
||||
S s;
|
||||
|
||||
S &
|
||||
qux ()
|
||||
{
|
||||
s.s = 42;
|
||||
return s;
|
||||
}
|
||||
|
||||
thread_local S &t = qux ();
|
||||
|
||||
bool
|
||||
bar ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
if (baz ())
|
||||
__builtin_abort ();
|
||||
}
|
21
gcc/testsuite/g++.dg/tls/thread_local13.C
Normal file
21
gcc/testsuite/g++.dg/tls/thread_local13.C
Normal file
|
@ -0,0 +1,21 @@
|
|||
// PR c++/109164
|
||||
// { dg-do run { target c++11 } }
|
||||
// { dg-options "-O2" }
|
||||
// { dg-add-options tls }
|
||||
// { dg-require-effective-target tls_runtime }
|
||||
// { dg-additional-sources "thread_local13-aux.cc" }
|
||||
|
||||
struct S { virtual void foo (); int s; };
|
||||
extern thread_local S &t;
|
||||
bool bar ();
|
||||
|
||||
bool
|
||||
baz ()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
t.foo ();
|
||||
if (!bar ())
|
||||
return false;
|
||||
}
|
||||
}
|
26
gcc/testsuite/g++.dg/tls/thread_local14-aux.cc
Normal file
26
gcc/testsuite/g++.dg/tls/thread_local14-aux.cc
Normal file
|
@ -0,0 +1,26 @@
|
|||
// PR c++/109164
|
||||
|
||||
extern bool baz ();
|
||||
|
||||
int
|
||||
qux ()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
extern thread_local const int t = qux ();
|
||||
|
||||
bool
|
||||
bar (int x)
|
||||
{
|
||||
if (x != 42)
|
||||
__builtin_abort ();
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
if (baz ())
|
||||
__builtin_abort ();
|
||||
}
|
19
gcc/testsuite/g++.dg/tls/thread_local14.C
Normal file
19
gcc/testsuite/g++.dg/tls/thread_local14.C
Normal file
|
@ -0,0 +1,19 @@
|
|||
// PR c++/109164
|
||||
// { dg-do run { target c++11 } }
|
||||
// { dg-options "-O2" }
|
||||
// { dg-add-options tls }
|
||||
// { dg-require-effective-target tls_runtime }
|
||||
// { dg-additional-sources "thread_local14-aux.cc" }
|
||||
|
||||
extern thread_local const int t;
|
||||
bool bar (int);
|
||||
|
||||
bool
|
||||
baz ()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
if (!bar (t))
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue