Pushed this bunch of simplifications to the template machinery. As
ever, discovered when implementing modules and figuring out how it worked.
inst-friend.diff
tsubst_friend_function's control flow was a little complicated. This
simplifies it, primarily by using more RAII.
lkp-class.diff
We were checking TYPE_NAME and then copying it if not null. Just copy
it, and then see if we got null.
push-tpl.diff
Push_template_decl_real's friend-pushing logic was confusing me. This
is more understandable. Fix a latent type bug I disovered.
nathan
--
Nathan Sidwell
diff --git i/gcc/cp/pt.c w/gcc/cp/pt.c
index 837644f8e6c..5ca659e9f28 100644
--- i/gcc/cp/pt.c
+++ w/gcc/cp/pt.c
@@ -10893,6 +10900,8 @@ tsubst_friend_function (tree decl, tree args)
}
new_friend = tsubst (decl, args, tf_warning_or_error, NULL_TREE);
+ if (new_friend == error_mark_node)
+ return error_mark_node;
/* The NEW_FRIEND will look like an instantiation, to the
compiler, but is not an instantiation from the point of view of
@@ -10904,11 +10913,9 @@ tsubst_friend_function (tree decl, tree args)
Then, in S<int>, template <class U> void f(int, U) is not an
instantiation of anything. */
- if (new_friend == error_mark_node)
- return error_mark_node;
DECL_USE_TEMPLATE (new_friend) = 0;
- if (TREE_CODE (decl) == TEMPLATE_DECL)
+ if (TREE_CODE (new_friend) == TEMPLATE_DECL)
{
DECL_USE_TEMPLATE (DECL_TEMPLATE_RESULT (new_friend)) = 0;
DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (new_friend))
@@ -10935,29 +10942,27 @@ tsubst_friend_function (tree decl, tree args)
if (DECL_NAMESPACE_SCOPE_P (new_friend))
{
tree old_decl;
- tree new_friend_template_info;
- tree new_friend_result_template_info;
tree ns;
- int new_friend_is_defn;
/* We must save some information from NEW_FRIEND before calling
duplicate decls since that function will free NEW_FRIEND if
possible. */
- new_friend_template_info = DECL_TEMPLATE_INFO (new_friend);
- new_friend_is_defn =
- (DECL_INITIAL (DECL_TEMPLATE_RESULT
- (template_for_substitution (new_friend)))
- != NULL_TREE);
+ tree new_friend_template_info = DECL_TEMPLATE_INFO (new_friend);
+ tree new_friend_result_template_info = NULL_TREE;
+ bool new_friend_is_defn =
+ (DECL_INITIAL (DECL_TEMPLATE_RESULT
+ (template_for_substitution (new_friend)))
+ != NULL_TREE);
+ tree not_tmpl = new_friend;
+
if (TREE_CODE (new_friend) == TEMPLATE_DECL)
{
/* This declaration is a `primary' template. */
DECL_PRIMARY_TEMPLATE (new_friend) = new_friend;
- new_friend_result_template_info
- = DECL_TEMPLATE_INFO (DECL_TEMPLATE_RESULT (new_friend));
+ not_tmpl = DECL_TEMPLATE_RESULT (new_friend);
+ new_friend_result_template_info = DECL_TEMPLATE_INFO (not_tmpl);
}
- else
- new_friend_result_template_info = NULL_TREE;
/* Inside pushdecl_namespace_level, we will push into the
current namespace. However, the friend function should go
2020-05-14 Nathan Sidwell <nat...@acm.org>
* pt.c (push_template_decl_real): Adjust friend pushing logic.
Reinit template type.
diff --git i/gcc/cp/pt.c w/gcc/cp/pt.c
index 837644f8e6c..5ca659e9f28 100644
--- i/gcc/cp/pt.c
+++ w/gcc/cp/pt.c
@@ -5979,24 +5979,32 @@ push_template_decl_real (tree decl, bool is_friend)
gcc_checking_assert (DECL_TEMPLATE_RESULT (tmpl) == decl);
- /* Push template declarations for global functions and types. Note
- that we do not try to push a global template friend declared in a
- template class; such a thing may well depend on the template
- parameters of the class. */
- if (new_template_p && !ctx
- && !(is_friend && template_class_depth (current_class_type) > 0))
- {
- tmpl = pushdecl_namespace_level (tmpl, is_friend);
- if (tmpl == error_mark_node)
- return error_mark_node;
- /* Hide template friend classes that haven't been declared yet. */
- if (is_friend && TREE_CODE (decl) == TYPE_DECL)
+ if (new_template_p)
+ {
+ /* Push template declarations for global functions and types.
+ Note that we do not try to push a global template friend
+ declared in a template class; such a thing may well depend on
+ the template parameters of the class and we'll push it when
+ instantiating the befriending class. */
+ if (!ctx
+ && !(is_friend && template_class_depth (current_class_type) > 0))
{
- DECL_ANTICIPATED (tmpl) = 1;
- DECL_FRIEND_P (tmpl) = 1;
+ tmpl = pushdecl_namespace_level (tmpl, is_friend);
+ if (tmpl == error_mark_node)
+ return error_mark_node;
+
+ /* Hide template friend classes that haven't been declared yet. */
+ if (is_friend && TREE_CODE (decl) == TYPE_DECL)
+ {
+ DECL_ANTICIPATED (tmpl) = 1;
+ DECL_FRIEND_P (tmpl) = 1;
+ }
}
}
+ else
+ /* The type may have been completed, or (erroneously) changed. */
+ TREE_TYPE (tmpl) = TREE_TYPE (decl);
if (is_primary)
{
2020-05-14 Nathan Sidwell <nat...@acm.org>
* pt.c (lookup_template_class_1): Remove unnecessary else by
simply grabbing TYPE_NAME earlier.
diff --git i/gcc/cp/pt.c w/gcc/cp/pt.c
index 837644f8e6c..5ca659e9f28 100644
--- i/gcc/cp/pt.c
+++ w/gcc/cp/pt.c
@@ -9911,7 +9919,8 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
/* If we called start_enum or pushtag above, this information
will already be set up. */
- if (!TYPE_NAME (t))
+ type_decl = TYPE_NAME (t);
+ if (!type_decl)
{
TYPE_CONTEXT (t) = FROB_CONTEXT (context);
@@ -9920,8 +9929,6 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
DECL_SOURCE_LOCATION (type_decl)
= DECL_SOURCE_LOCATION (TYPE_STUB_DECL (template_type));
}
- else
- type_decl = TYPE_NAME (t);
if (CLASS_TYPE_P (template_type))
{