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