aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>1999-04-17 14:15:29 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1999-04-17 14:15:29 +0000
commit25aab5d0addefe0e3b814a7ec540a1fa883cd11f (patch)
treea0691edea065b47d3afc29a947078d78f4039179 /gcc
parent4e6a144034de387e9ff11a6ae78d6af86f0dc228 (diff)
downloadgcc-25aab5d0addefe0e3b814a7ec540a1fa883cd11f.zip
gcc-25aab5d0addefe0e3b814a7ec540a1fa883cd11f.tar.gz
gcc-25aab5d0addefe0e3b814a7ec540a1fa883cd11f.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog9
-rw-r--r--gcc/cp/decl.c141
-rw-r--r--gcc/cp/pt.c52
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/friend41.C21
4 files changed, 154 insertions, 69 deletions
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 <mark@codesourcery.com>
+
+ * 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 <mark@codesourcery.com>
* 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 <class X>
- struct S1
-
- template <class U>
- struct S2
- { template <class V>
- 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 <class V = U> 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 <class X>
+ struct S1
+
+ template <class U>
+ struct S2
+ { template <class V>
+ 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 <class V = U> friend struct S1;
+
+ say, when we should tsubst into `U' when instantiating
+ S2. On the other hand, when presented with:
+
+ template <class T>
+ struct S1 {
+ template <class U>
+ struct S2 {};
+ template <class U>
+ 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 <class T>
+ struct S {
+ template <class U>
+ friend struct S;
+ };
+
+ Here, in the scope of (say) S<int>, `S' is bound to a TYPE_DECL
+ for `S<int>', 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 <mark@codesourcery.com>
+
+template <class T>
+class S {
+public:
+ template <class U>
+ class C {
+ public:
+ void f() { S::i = 3; }
+ };
+
+ template <class U>
+ friend class C;
+
+private:
+ static int i;
+};
+
+
+template void S<int>::C<double>::f();