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.

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                          |  6 ++++-
 gcc/testsuite/g++.dg/tls/pr107393-1.C | 14 ++++++++++
 gcc/testsuite/g++.dg/tls/pr107393-2.C | 29 +++++++++++++++++++++
 5 files changed, 81 insertions(+), 8 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 cb3ebfff429..05869bdfdd5 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
@@ -11742,7 +11753,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;
@@ -11829,7 +11841,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);
@@ -12797,7 +12822,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;
@@ -15794,7 +15819,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 acfeb816592..e053f2453ab 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -15934,6 +15934,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
        if (type == error_mark_node && !(complain & tf_error))
          RETURN (error_mark_node);
        r = copy_decl (t);
+       bool need_tls_model = false;
        if (VAR_P (r))
          {
            DECL_INITIALIZED_P (r) = 0;
@@ -15994,7 +15995,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
              }
            if (CP_DECL_THREAD_LOCAL_P (r)
                && !processing_template_decl)
-             set_decl_tls_model (r, decl_default_tls_model (r));
+             need_tls_model = true;
          }
        else if (DECL_SELF_REFERENCE_P (t))
          SET_DECL_SELF_REFERENCE_P (r);
@@ -16057,6 +16058,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
              register_local_specialization (r, t);
          }
 
+       if (need_tls_model)
+         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" } }
-- 
2.50.1

Reply via email to