This PR points out an ICE caused by thread_local on static data members, which we weren't handling properly at all. There is still the issue that calling set_decl_tls_model on a template variable adds it to the symbol table, causing problems later on, but this patch fixes the front end handling.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit ccf3f3b41516b34d7d564bed1b3f4e3cf270e43a
Author: Jason Merrill <ja...@redhat.com>
Date:   Tue Aug 26 13:56:17 2014 -0400

    	PR c++/58624
    	* pt.c (tsubst_decl) [VAR_DECL]: Copy TLS model.
    	(tsubst_copy_and_build) [VAR_DECL]: Use TLS wrapper.
    	* semantics.c (finish_id_expression): Don't call TLS wrapper in a
    	template.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 59df387..eac837f 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11225,6 +11225,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 		  }
 		SET_DECL_VALUE_EXPR (r, ve);
 	      }
+	    if (TREE_STATIC (r) || DECL_EXTERNAL (r))
+	      set_decl_tls_model (r, decl_tls_model (t));
 	  }
 	else if (DECL_SELF_REFERENCE_P (t))
 	  SET_DECL_SELF_REFERENCE_P (r);
@@ -15410,6 +15412,17 @@ tsubst_copy_and_build (tree t,
     case PARM_DECL:
       {
 	tree r = tsubst_copy (t, args, complain, in_decl);
+	if (VAR_P (r)
+	    && !processing_template_decl
+	    && !cp_unevaluated_operand
+	    && (TREE_STATIC (r) || DECL_EXTERNAL (r))
+	    && 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_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)
 	  /* If the original type was a reference, we'll be wrapped in
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 16abad0..9c9fc1c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3500,6 +3500,7 @@ finish_id_expression (tree id_expression,
       tree wrap;
       if (VAR_P (decl)
 	  && !cp_unevaluated_operand
+	  && !processing_template_decl
 	  && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
 	  && DECL_THREAD_LOCAL_P (decl)
 	  && (wrap = get_tls_wrapper_fn (decl)))
diff --git a/gcc/testsuite/g++.dg/tls/thread_local10.C b/gcc/testsuite/g++.dg/tls/thread_local10.C
new file mode 100644
index 0000000..48c1b86
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tls/thread_local10.C
@@ -0,0 +1,23 @@
+// PR c++/58624
+
+// { dg-do run { target c++11 } }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+
+int i;
+
+template <typename> struct A
+{
+  static thread_local int s;
+
+  A () { i = s; }
+};
+
+int f() { return 42; }
+template <typename T> thread_local int A<T>::s = f();
+
+int main () {
+  A<void> a;
+  if (i != 42)
+    __builtin_abort();
+}

Reply via email to