From 9703b8d98c116e7abb01e6d261d64458dda9c08c Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Thu, 29 Oct 2020 04:56:27 -0700 Subject: [PATCH] c++: Stop (most) function-scope entities having a template header Currently push_template_decl (mostly) decides whether to add a template header to an entity by seeing if it has DECL_LANG_SPECIFIC. That might have been a useful predicate at one time, but basing semantic implications on how we've decided to represent decls is bound to be brittle. And indeed it is, as more decls grow a use for lang-specific. In particular I discovered that function-scope VAR_DECLs couild grow lang-specific, and thereby get a template header. There's no need for that, and it breaks an invariant modules was expected. This patch changes that, and bases the descision on the properties of the decl. In particular the only function-scope decl that gets a template header is an implicit-typedef. I also cleaned up the behaviour of it building a template-info only to ignore it. gcc/cp/ * pt.c (push_template_decl): Do not give function-scope entities other than implicit typedefs a template header. Do not readd template info to a redeclared template. --- gcc/cp/pt.c | 143 +++++++++++++++++++++++++++++----------------------- 1 file changed, 80 insertions(+), 63 deletions(-) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b0344ac2506..f31a1a70473 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5682,11 +5682,6 @@ template_parm_outer_level (tree t, void *data) tree push_template_decl (tree decl, bool is_friend) { - int new_template_p = 0; - /* True if the template is a member template, in the sense of - [temp.mem]. */ - bool member_template_p = false; - if (decl == error_mark_node || !current_template_parms) return error_mark_node; @@ -5739,12 +5734,17 @@ push_template_decl (tree decl, bool is_friend) else is_primary = template_parm_scope_p (); + /* True if the template is a member template, in the sense of + [temp.mem]. */ + bool member_template_p = false; + if (is_primary) { warning (OPT_Wtemplates, "template %qD declared", decl); if (DECL_CLASS_SCOPE_P (decl)) member_template_p = true; + if (TREE_CODE (decl) == TYPE_DECL && IDENTIFIER_ANON_P (DECL_NAME (decl))) { @@ -5812,11 +5812,16 @@ push_template_decl (tree decl, bool is_friend) } } + bool local_p = (!DECL_IMPLICIT_TYPEDEF_P (decl) + && ((ctx && TREE_CODE (ctx) == FUNCTION_DECL) + || (VAR_OR_FUNCTION_DECL_P (decl) + && DECL_LOCAL_DECL_P (decl)))); + /* Check to see that the rules regarding the use of default arguments are not being violated. We check args for a friend functions when we know whether it's a definition, introducing declaration or re-declaration. */ - if (!is_friend || TREE_CODE (decl) != FUNCTION_DECL) + if (!local_p && (!is_friend || TREE_CODE (decl) != FUNCTION_DECL)) check_default_tmpl_args (decl, current_template_parms, is_primary, is_partial, is_friend); @@ -5869,14 +5874,20 @@ push_template_decl (tree decl, bool is_friend) return process_partial_specialization (decl); tree args = current_template_args (); - - tree tmpl; - if (!ctx - || TREE_CODE (ctx) == FUNCTION_DECL - || (CLASS_TYPE_P (ctx) && TYPE_BEING_DEFINED (ctx)) - || (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (TREE_TYPE (decl))) - || (is_friend && !(DECL_LANG_SPECIFIC (decl) - && DECL_TEMPLATE_INFO (decl)))) + tree tmpl = NULL_TREE; + bool new_template_p = false; + if (local_p) + { + /* Does not get a template head. */ + tmpl = NULL_TREE; + gcc_checking_assert (!is_primary); + } + else if (!ctx + || TREE_CODE (ctx) == FUNCTION_DECL + || (CLASS_TYPE_P (ctx) && TYPE_BEING_DEFINED (ctx)) + || (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (TREE_TYPE (decl))) + || (is_friend && !(DECL_LANG_SPECIFIC (decl) + && DECL_TEMPLATE_INFO (decl)))) { if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl) @@ -5903,7 +5914,7 @@ push_template_decl (tree decl, bool is_friend) { tmpl = build_template_decl (decl, current_template_parms, member_template_p); - new_template_p = 1; + new_template_p = true; if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_SPECIALIZATION (decl)) @@ -5935,8 +5946,6 @@ push_template_decl (tree decl, bool is_friend) && DECL_TEMPLATE_SPECIALIZATION (decl) && DECL_MEMBER_TEMPLATE_P (tmpl)) { - tree new_tmpl; - /* The declaration is a specialization of a member template, declared outside the class. Therefore, the innermost template arguments will be NULL, so we @@ -5944,7 +5953,7 @@ push_template_decl (tree decl, bool is_friend) earlier call to check_explicit_specialization. */ args = DECL_TI_ARGS (decl); - new_tmpl + tree new_tmpl = build_template_decl (decl, current_template_parms, member_template_p); DECL_TI_TEMPLATE (decl) = new_tmpl; @@ -6016,7 +6025,7 @@ push_template_decl (tree decl, bool is_friend) } } - gcc_checking_assert (DECL_TEMPLATE_RESULT (tmpl) == decl); + gcc_checking_assert (!tmpl || DECL_TEMPLATE_RESULT (tmpl) == decl); if (new_template_p) { @@ -6028,65 +6037,71 @@ push_template_decl (tree decl, bool is_friend) if (!ctx && !(is_friend && template_class_depth (current_class_type) > 0)) { - tmpl = pushdecl_namespace_level (tmpl, /*hiding=*/is_friend); - if (tmpl == error_mark_node) + tree pushed = pushdecl_namespace_level (tmpl, /*hiding=*/is_friend); + if (pushed == error_mark_node) return error_mark_node; + + /* pushdecl may have found an existing template. */ + if (pushed != tmpl) + { + decl = DECL_TEMPLATE_RESULT (pushed); + tmpl = NULL_TREE; + } } } - else + else if (tmpl) /* The type may have been completed, or (erroneously) changed. */ TREE_TYPE (tmpl) = TREE_TYPE (decl); - if (is_primary) + if (tmpl) { - tree parms = DECL_TEMPLATE_PARMS (tmpl); + if (is_primary) + { + tree parms = DECL_TEMPLATE_PARMS (tmpl); - DECL_PRIMARY_TEMPLATE (tmpl) = tmpl; + DECL_PRIMARY_TEMPLATE (tmpl) = tmpl; - /* Give template template parms a DECL_CONTEXT of the template - for which they are a parameter. */ - parms = INNERMOST_TEMPLATE_PARMS (parms); - for (int i = TREE_VEC_LENGTH (parms) - 1; i >= 0; --i) - { - tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i)); - if (TREE_CODE (parm) == TEMPLATE_DECL) - DECL_CONTEXT (parm) = tmpl; - } + /* Give template template parms a DECL_CONTEXT of the template + for which they are a parameter. */ + parms = INNERMOST_TEMPLATE_PARMS (parms); + for (int i = TREE_VEC_LENGTH (parms) - 1; i >= 0; --i) + { + tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i)); + if (TREE_CODE (parm) == TEMPLATE_DECL) + DECL_CONTEXT (parm) = tmpl; + } - if (TREE_CODE (decl) == TYPE_DECL - && TYPE_DECL_ALIAS_P (decl)) - { - if (tree constr - = TEMPLATE_PARMS_CONSTRAINTS (DECL_TEMPLATE_PARMS (tmpl))) + if (TREE_CODE (decl) == TYPE_DECL + && TYPE_DECL_ALIAS_P (decl)) { - /* ??? Why don't we do this here for all templates? */ - constr = build_constraints (constr, NULL_TREE); - set_constraints (decl, constr); + if (tree constr + = TEMPLATE_PARMS_CONSTRAINTS (DECL_TEMPLATE_PARMS (tmpl))) + { + /* ??? Why don't we do this here for all templates? */ + constr = build_constraints (constr, NULL_TREE); + set_constraints (decl, constr); + } + if (complex_alias_template_p (tmpl)) + TEMPLATE_DECL_COMPLEX_ALIAS_P (tmpl) = true; } - if (complex_alias_template_p (tmpl)) - TEMPLATE_DECL_COMPLEX_ALIAS_P (tmpl) = true; } - } - /* The DECL_TI_ARGS of DECL contains full set of arguments referring - back to its most general template. If TMPL is a specialization, - ARGS may only have the innermost set of arguments. Add the missing - argument levels if necessary. */ - if (DECL_TEMPLATE_INFO (tmpl)) - args = add_outermost_template_args (DECL_TI_ARGS (tmpl), args); + /* The DECL_TI_ARGS of DECL contains full set of arguments + referring wback to its most general template. If TMPL is a + specialization, ARGS may only have the innermost set of + arguments. Add the missing argument levels if necessary. */ + if (DECL_TEMPLATE_INFO (tmpl)) + args = add_outermost_template_args (DECL_TI_ARGS (tmpl), args); - tree info = build_template_info (tmpl, args); + tree info = build_template_info (tmpl, args); - if (DECL_IMPLICIT_TYPEDEF_P (decl)) - SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info); - else - { - if (is_primary) - retrofit_lang_decl (decl); - if (DECL_LANG_SPECIFIC (decl) - && !(VAR_OR_FUNCTION_DECL_P (decl) - && DECL_LOCAL_DECL_P (decl))) - DECL_TEMPLATE_INFO (decl) = info; + if (DECL_IMPLICIT_TYPEDEF_P (decl)) + SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info); + else + { + retrofit_lang_decl (decl); + DECL_TEMPLATE_INFO (decl) = info; + } } if (flag_implicit_templates @@ -6098,7 +6113,9 @@ push_template_decl (tree decl, bool is_friend) mark_needed will tell cgraph to do the right thing. */ DECL_COMDAT (decl) = true; - return DECL_TEMPLATE_RESULT (tmpl); + gcc_checking_assert (!tmpl || DECL_TEMPLATE_RESULT (tmpl) == decl); + + return decl; } /* FN is an inheriting constructor that inherits from the constructor -- 2.30.2