From 25aab5d0addefe0e3b814a7ec540a1fa883cd11f Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Sat, 17 Apr 1999 14:15:29 +0000 Subject: [PATCH] decl.c (xref_tag): Revise handling of nested template declarations. * decl.c (xref_tag): Revise handling of nested template declarations. * pt.c (check_explicit_specialization): Tweak handling of friend templates in template classes. (tsubst_friend_class): Handle friend declarations for nested member template classes. From-SVN: r26520 --- gcc/cp/ChangeLog | 9 ++ gcc/cp/decl.c | 141 +++++++++++++++------------ gcc/cp/pt.c | 52 ++++++++-- gcc/testsuite/g++.old-deja/g++.pt/friend41.C | 21 ++++ 4 files changed, 154 insertions(+), 69 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/friend41.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 67cc7e1..ceb79ca 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +1999-04-17 Mark Mitchell + + * decl.c (xref_tag): Revise handling of nested template + declarations. + * pt.c (check_explicit_specialization): Tweak handling of friend + templates in template classes. + (tsubst_friend_class): Handle friend declarations for nested + member template classes. + 1999-04-16 Mark Mitchell * class.c (finish_struct): Remove unused variable. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 5730719..87eae50 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -12323,6 +12323,7 @@ xref_tag (code_type_node, name, globalize) struct binding_level *b = current_binding_level; int got_type = 0; tree attributes = NULL_TREE; + tree context = NULL_TREE; /* If we are called from the parser, code_type_node will sometimes be a TREE_LIST. This indicates that the user wrote @@ -12375,72 +12376,87 @@ xref_tag (code_type_node, name, globalize) } else { - if (current_class_type - && template_class_depth (current_class_type) - && PROCESSING_REAL_TEMPLATE_DECL_P ()) - /* Since GLOBALIZE is non-zero, we are not looking at a - definition of this tag. Since, in addition, we are currently - processing a (member) template declaration of a template - class, we don't want to do any lookup at all; consider: - - template - struct S1 - - template - struct S2 - { template - friend struct S1; }; - - Here, the S2::S1 declaration should not be confused with the - outer declaration. In particular, the inner version should - have a template parameter of level 2, not level 1. This - would be particularly important if the member declaration - were instead: - - template friend struct S1; - - say, when we should tsubst into `U' when instantiating S2. */ - ref = NULL_TREE; - else + if (t) { - if (t) - { - /* [dcl.type.elab] If the identifier resolves to a - typedef-name or a template type-parameter, the - elaborated-type-specifier is ill-formed. */ - if (t != TYPE_MAIN_VARIANT (t) - || (CLASS_TYPE_P (t) && TYPE_WAS_ANONYMOUS (t))) - cp_pedwarn ("using typedef-name `%D' after `%s'", - TYPE_NAME (t), tag_name (tag_code)); - else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM) - cp_error ("using template type parameter `%T' after `%s'", - t, tag_name (tag_code)); - - ref = t; - } - else - ref = lookup_tag (code, name, b, 0); + /* [dcl.type.elab] If the identifier resolves to a + typedef-name or a template type-parameter, the + elaborated-type-specifier is ill-formed. */ + if (t != TYPE_MAIN_VARIANT (t) + || (CLASS_TYPE_P (t) && TYPE_WAS_ANONYMOUS (t))) + cp_pedwarn ("using typedef-name `%D' after `%s'", + TYPE_NAME (t), tag_name (tag_code)); + else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM) + cp_error ("using template type parameter `%T' after `%s'", + t, tag_name (tag_code)); + + ref = t; + } + else + ref = lookup_tag (code, name, b, 0); - if (! ref) - { - /* Try finding it as a type declaration. If that wins, - use it. */ - ref = lookup_name (name, 1); - - if (ref != NULL_TREE - && processing_template_decl - && DECL_CLASS_TEMPLATE_P (ref) - && template_class_depth (current_class_type) == 0) - /* Since GLOBALIZE is true, we're declaring a global + if (! ref) + { + /* Try finding it as a type declaration. If that wins, + use it. */ + ref = lookup_name (name, 1); + + if (ref != NULL_TREE + && processing_template_decl + && DECL_CLASS_TEMPLATE_P (ref) + && template_class_depth (current_class_type) == 0) + /* Since GLOBALIZE is true, we're declaring a global template, so we want this type. */ - ref = DECL_RESULT (ref); + ref = DECL_RESULT (ref); - if (ref && TREE_CODE (ref) == TYPE_DECL - && TREE_CODE (TREE_TYPE (ref)) == code) - ref = TREE_TYPE (ref); - else - ref = NULL_TREE; - } + if (ref && TREE_CODE (ref) == TYPE_DECL + && TREE_CODE (TREE_TYPE (ref)) == code) + ref = TREE_TYPE (ref); + else + ref = NULL_TREE; + } + + if (ref && current_class_type + && template_class_depth (current_class_type) + && PROCESSING_REAL_TEMPLATE_DECL_P ()) + { + /* Since GLOBALIZE is non-zero, we are not looking at a + definition of this tag. Since, in addition, we are currently + processing a (member) template declaration of a template + class, we must be very careful; consider: + + template + struct S1 + + template + struct S2 + { template + friend struct S1; }; + + Here, the S2::S1 declaration should not be confused with the + outer declaration. In particular, the inner version should + have a template parameter of level 2, not level 1. This + would be particularly important if the member declaration + were instead: + + template friend struct S1; + + say, when we should tsubst into `U' when instantiating + S2. On the other hand, when presented with: + + template + struct S1 { + template + struct S2 {}; + template + friend struct S2; + }; + + we must find the inner binding eventually. We + accomplish this by making sure that the new type we + create to represent this declaration has the right + TYPE_CONTEXT. */ + context = TYPE_CONTEXT (ref); + ref = NULL_TREE; } } @@ -12487,6 +12503,7 @@ xref_tag (code_type_node, name, globalize) struct binding_level *old_b = class_binding_level; ref = make_lang_type (code); + TYPE_CONTEXT (ref) = context; if (tag_code == signature_type) { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d73f182..b26b88a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -1281,7 +1281,6 @@ check_explicit_specialization (declarator, decl, template_count, flags) if (specialization || member_specialization || explicit_instantiation) { - tree gen_tmpl; tree tmpl = NULL_TREE; tree targs = NULL_TREE; @@ -1435,13 +1434,34 @@ check_explicit_specialization (declarator, decl, template_count, flags) return error_mark_node; else { - gen_tmpl = most_general_template (tmpl); + tree gen_tmpl = most_general_template (tmpl); if (explicit_instantiation) { /* We don't set DECL_EXPLICIT_INSTANTIATION here; that - is done by do_decl_instantiation later. */ - decl = instantiate_template (tmpl, innermost_args (targs)); + is done by do_decl_instantiation later. */ + + int arg_depth = TMPL_ARGS_DEPTH (targs); + int parm_depth = TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)); + + if (arg_depth > parm_depth) + { + /* If TMPL is not the most general template (for + example, if TMPL is a friend template that is + injected into namespace scope), then there will + be too many levels fo TARGS. Remove some of them + here. */ + int i; + tree new_targs; + + new_targs = make_temp_vec (parm_depth); + for (i = arg_depth - parm_depth; i < arg_depth; ++i) + TREE_VEC_ELT (new_targs, i - (arg_depth - parm_depth)) + = TREE_VEC_ELT (targs, i); + targs = new_targs; + } + + decl = instantiate_template (tmpl, targs); return decl; } @@ -4583,11 +4603,29 @@ tsubst_friend_class (friend_tmpl, args) tree args; { tree friend_type; - tree tmpl = lookup_name (DECL_NAME (friend_tmpl), 1); + tree tmpl; - tmpl = maybe_get_template_decl_from_type_decl (tmpl); + /* First, we look for a class template. */ + tmpl = lookup_name (DECL_NAME (friend_tmpl), /*prefer_type=*/0); + + /* But, if we don't find one, it might be because we're in a + situation like this: + + template + struct S { + template + friend struct S; + }; + + Here, in the scope of (say) S, `S' is bound to a TYPE_DECL + for `S', not the TEMPLATE_DECL. */ + if (!DECL_CLASS_TEMPLATE_P (tmpl)) + { + tmpl = lookup_name (DECL_NAME (friend_tmpl), /*prefer_type=*/1); + tmpl = maybe_get_template_decl_from_type_decl (tmpl); + } - if (tmpl != NULL_TREE && DECL_CLASS_TEMPLATE_P (tmpl)) + if (tmpl && DECL_CLASS_TEMPLATE_P (tmpl)) { /* The friend template has already been declared. Just check to see that the declarations match, and install any new diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend41.C b/gcc/testsuite/g++.old-deja/g++.pt/friend41.C new file mode 100644 index 0000000..d6b74a0 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/friend41.C @@ -0,0 +1,21 @@ +// Build don't link: +// Origin: Mark Mitchell + +template +class S { +public: + template + class C { + public: + void f() { S::i = 3; } + }; + + template + friend class C; + +private: + static int i; +}; + + +template void S::C::f(); -- 2.7.4