[gcc r11-4529] c++: Stop (most) function-scope entities having a template header
Nathan Sidwell
nathan@gcc.gnu.org
Thu Oct 29 14:16:58 GMT 2020
https://gcc.gnu.org/g:9703b8d98c116e7abb01e6d261d64458dda9c08c
commit r11-4529-g9703b8d98c116e7abb01e6d261d64458dda9c08c
Author: Nathan Sidwell <nathan@acm.org>
Date: Thu Oct 29 04:56:27 2020 -0700
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.
Diff:
---
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
More information about the Gcc-cvs
mailing list