On 8/13/25 11:54 AM, H.J. Lu wrote:
Set a tentative TLS model in grokvardecl and update DECL_TLS_MODEL with
the default TLS access model after a TLS variable has been fully processed
if the default TLS access model is stronger.

If the non-template problem is needing to recalculate the default after applying attributes, how about changing cplus_decl_attributes instead of grokvardecl/grokdeclarator/start_decl?

Adding a parameter to grok* seems neither necessary nor desirable. Since it seems we don't aim to support tls_model attributes weaker than the default, we could just set the default in grokvardecl (as before your patch) and then set it again later after applying attributes if it's stronger.

gcc/cp/

        PR c++/107393
        * decl.cc (grokvardecl): Add a pointer to bool argument to
        indicate if DECL_TLS_MODEL should be updated later.  Set a
        tentative TLS model if DECL_TLS_MODEL will be updated later.
        (start_decl): Pass a pointer to bool argument to grokdeclarator.
        Call set_decl_tls_model to update DECL_TLS_MODEL with the default
        TLS access model after calling grokdeclarator if the default TLS
        access model is stronger.
        (grokdeclarator): Add a pointer to bool argument and pass it to
        grokvardecl.
        * decl.h (grokdeclarator): Add a pointer to bool argument and
        default it to nullptr.
        * pt.cc (tsubst_decl): Call set_decl_tls_model 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>
---
  gcc/cp/decl.cc                        | 37 ++++++++++++++++++++++-----
  gcc/cp/decl.h                         |  3 ++-
  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, 81 insertions(+), 10 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 5aa8203649c..d15c709ee70 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -78,7 +78,8 @@ static bool decl_jump_unsafe (tree);
  static void require_complete_types_for_parms (tree);
  static tree grok_reference_init (tree, tree, tree, int);
  static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *,
-                        int, int, int, bool, int, tree, location_t);
+                        int, int, int, bool, int, tree, location_t,
+                        bool * = nullptr);
  static void check_static_variable_definition (tree, tree);
  static void record_unknown_type (tree, const char *);
  static int member_function_or_else (tree, tree, enum overload_flags);
@@ -5997,8 +5998,9 @@ start_decl (const cp_declarator *declarator,
    if (prefix_attributes != error_mark_node)
      attributes = attr_chainon (attributes, prefix_attributes);
+ bool tls_model_p = false;
    decl = grokdeclarator (declarator, declspecs, NORMAL, initialized,
-                        &attributes);
+                        &attributes, &tls_model_p);
if (decl == NULL_TREE || VOID_TYPE_P (decl)
        || decl == error_mark_node
@@ -6056,6 +6058,15 @@ start_decl (const cp_declarator *declarator,
       assist with attribute validation.  */
    DECL_INITIAL (decl) = initial;
+ if (tls_model_p)
+    {
+      // 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);
+    }
+
    /* Dllimported symbols cannot be defined.  Static data members (which
       can be initialized in-class and dllimported) go through grokfield,
       not here, so we don't need to exclude those decls when checking for
@@ -11959,7 +11970,8 @@ grokvardecl (tree type,
             bool conceptp,
             int template_count,
             tree scope,
-            location_t location)
+            location_t location,
+            bool *tls_model_p)
  {
    tree decl;
    tree explicit_scope;
@@ -12046,7 +12058,20 @@ grokvardecl (tree type,
        {
          CP_DECL_THREAD_LOCAL_P (decl) = true;
          if (!processing_template_decl)
-           set_decl_tls_model (decl, decl_default_tls_model (decl));
+           {
+             tls_model model;
+             if (tls_model_p)
+               {
+                 // NB: Set a tentative TLS model to avoid tls_model
+                 // attribute warnings due to lack of thread storage
+                 // duration.  It will be updated later.
+                 model = TLS_MODEL_REAL;
+                 *tls_model_p = true;
+               }
+             else
+               model = decl_default_tls_model (decl);
+             set_decl_tls_model (decl, model);
+           }
        }
        if (declspecs->gnu_thread_keyword_p)
        SET_DECL_GNU_TLS_P (decl);
@@ -13014,7 +13039,7 @@ grokdeclarator (const cp_declarator *declarator,
                cp_decl_specifier_seq *declspecs,
                enum decl_context decl_context,
                int initialized,
-               tree* attrlist)
+               tree* attrlist, bool *tls_model_p)
  {
    tree type = NULL_TREE;
    int longlong = 0;
@@ -16011,7 +16036,7 @@ grokdeclarator (const cp_declarator *declarator,
                            concept_p,
                            template_count,
                            ctype ? ctype : in_namespace,
-                           id_loc);
+                           id_loc, tls_model_p);
        if (decl == NULL_TREE)
          return error_mark_node;
diff --git a/gcc/cp/decl.h b/gcc/cp/decl.h
index d2c357f34fb..625c01b50ad 100644
--- a/gcc/cp/decl.h
+++ b/gcc/cp/decl.h
@@ -34,7 +34,8 @@ enum decl_context
  /* We need this in here to get the decl_context definition.  */
  extern tree grokdeclarator (const cp_declarator *,
                            cp_decl_specifier_seq *,
-                           enum decl_context, int, tree*);
+                           enum decl_context, int, tree*,
+                           bool * = nullptr);
  extern void name_unnamed_type (tree, tree);
/* States indicating how grokdeclarator() should handle declspecs marked
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index b6b13edd03f..5bbdcb33ccb 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -16028,9 +16028,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);
@@ -16093,6 +16090,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