On 9/6/25 3:30 PM, H.J. Lu wrote:
On Sat, Sep 6, 2025 at 6:11 AM Jason Merrill <ja...@redhat.com> wrote:

On 9/6/25 12:40 AM, H.J. Lu wrote:
Set a tentative TLS model in grokvardecl and update TLS mode with the
default TLS access model after a TLS variable has been fully processed
if the default TLS access model is stronger.

gcc/cp/

       PR c++/107393
       * decl.cc (grokvardecl): Set a tentative TLS model which will be
       updated by cplus_decl_attributes later.
       * decl2.cc (cplus_decl_attributes): Update TLS model with the
       default TLS access model if the default TLS access model is
       stronger.
       * pt.cc (tsubst_decl): Set TLS model only after processing a
       variable.

gcc/testsuite/

       PR c++/107393
       * g++.dg/tls/pr107393-1.C: New test.
       * g++.dg/tls/pr107393-2.C: Likewise.

Signed-off-by: H.J. Lu <hjl.to...@gmail.com>

Fix

Signed-off-by: H.J. Lu <hjl.to...@gmail.com>
---
   gcc/cp/decl.cc                        |  5 ++++-
   gcc/cp/decl2.cc                       |  9 +++++++++
   gcc/cp/pt.cc                          |  8 +++++---
   gcc/testsuite/g++.dg/tls/pr107393-1.C | 14 +++++++++++++
   gcc/testsuite/g++.dg/tls/pr107393-2.C | 29 +++++++++++++++++++++++++++
   5 files changed, 61 insertions(+), 4 deletions(-)
   create mode 100644 gcc/testsuite/g++.dg/tls/pr107393-1.C
   create mode 100644 gcc/testsuite/g++.dg/tls/pr107393-2.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index f088d09f51e..a6a98426ed9 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -12183,8 +12183,11 @@ grokvardecl (tree type,
         if (DECL_EXTERNAL (decl) || TREE_STATIC (decl))
       {
         CP_DECL_THREAD_LOCAL_P (decl) = true;
+       // NB: Set a tentative TLS model to avoid tls_model attribute
+       // warnings due to lack of thread storage duration.  It will
+       // be updated by cplus_decl_attributes later.
         if (!processing_template_decl)
-         set_decl_tls_model (decl, decl_default_tls_model (decl));
+         set_decl_tls_model (decl, TLS_MODEL_REAL);

Do we need any change here?  A tls_model attribute will override
whatever is set here, so it seems fine to use the default here as well
as in cplus_decl_attributes.

The issue is that decl_default_tls_model may return a wrong stronger
model since we haven't processed the tls_model attribute yet.  When
it happens, cplus_decl_attributes can't override the TLS model since
it is stronger than what decl_default_tls_model returns.

Ah, or with attribute common, where we might wrongly think the variable binds locally at this point. Then the C++ changes are OK.

       }
         if (declspecs->gnu_thread_keyword_p)
       SET_DECL_GNU_TLS_P (decl);
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 6499be1d33b..c9cca7b0270 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -2013,6 +2013,15 @@ cplus_decl_attributes (tree *decl, tree attributes, int 
flags)
       if (*decl == pattern)
         TREE_UNAVAILABLE (tmpl) = true;
         }
+
+  if (VAR_P (*decl) && CP_DECL_THREAD_LOCAL_P (*decl))
+    {
+      // tls_model attribute can set a stronger TLS access model.
+      tls_model model = DECL_TLS_MODEL (*decl);
+      tls_model default_model = decl_default_tls_model (*decl);
+      if (default_model > model)
+     set_decl_tls_model (*decl, default_model);
+    }
   }

   /* Walks through the namespace- or function-scope anonymous union
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 365a6c55a83..7f0d16f217e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -16034,9 +16034,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
                                      == TYPE_MAIN_VARIANT (type));
               SET_DECL_VALUE_EXPR (r, ve);
             }
-         if (CP_DECL_THREAD_LOCAL_P (r)
-             && !processing_template_decl)
-           set_decl_tls_model (r, decl_default_tls_model (r));
         }
       else if (DECL_SELF_REFERENCE_P (t))
         SET_DECL_SELF_REFERENCE_P (r);
@@ -16099,6 +16096,11 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain,
             register_local_specialization (r, t);
         }

+     if (VAR_P (r)
+         && CP_DECL_THREAD_LOCAL_P (r)
+         && !processing_template_decl)
+       set_decl_tls_model (r, decl_default_tls_model (r));
+
       DECL_CHAIN (r) = NULL_TREE;

       if (!apply_late_template_attributes (&r, DECL_ATTRIBUTES (r),
diff --git a/gcc/testsuite/g++.dg/tls/pr107393-1.C 
b/gcc/testsuite/g++.dg/tls/pr107393-1.C
new file mode 100644
index 00000000000..644b4f48e36
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tls/pr107393-1.C
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++11 } }
+// { dg-require-effective-target fpic }
+// { dg-require-effective-target tls }
+// { dg-options "-O2 -fno-pic -fdump-ipa-whole-program" }
+// { dg-add-options tls }
+
+struct Dtor;
+template <typename> struct X { static thread_local Dtor m; };
+template <typename T> thread_local Dtor X<T>::m;
+extern template Dtor X<char>::m;
+void *e2 = &X<char>::m;
+
+// tls_model should be tls-initial-exec due to extern template.
+// { dg-final { scan-ipa-dump "Varpool flags: tls-initial-exec" 
"whole-program" } }
diff --git a/gcc/testsuite/g++.dg/tls/pr107393-2.C 
b/gcc/testsuite/g++.dg/tls/pr107393-2.C
new file mode 100644
index 00000000000..6a69800f2a2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tls/pr107393-2.C
@@ -0,0 +1,29 @@
+// { dg-do compile }
+// { dg-require-effective-target fpic }
+// { dg-require-effective-target tls }
+// { dg-options "-O2 -fno-pic -fdump-ipa-whole-program" }
+// { dg-add-options tls }
+
+template<class T>
+struct S {
+  static __thread int i;
+};
+
+template<class T>
+__thread int S<T>::i;
+
+extern template
+__thread int S<void>::i;
+
+int &vi()
+{
+  return S<void>::i;
+}
+
+int &ci()
+{
+  return S<char>::i;
+}
+
+// tls_model should be tls-initial-exec due to extern template.
+// { dg-final { scan-ipa-dump "Varpool flags: tls-initial-exec" 
"whole-program" } }




Reply via email to