aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@markmitchell.com>1998-11-16 08:34:38 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1998-11-16 08:34:38 +0000
commitfbf1c34bfa83a4b08f9ee8651250cd989d0bd0ba (patch)
tree4e2640645217b40b287d5f8c413c905bb4a702c8
parent848b92e1cc58303988dadd22623b904697084092 (diff)
downloadgcc-fbf1c34bfa83a4b08f9ee8651250cd989d0bd0ba.zip
gcc-fbf1c34bfa83a4b08f9ee8651250cd989d0bd0ba.tar.gz
gcc-fbf1c34bfa83a4b08f9ee8651250cd989d0bd0ba.tar.bz2
cp-tree.h (DECL_TEMPLATE_INSTANTIATED): New macro.
* cp-tree.h (DECL_TEMPLATE_INSTANTIATED): New macro. * decl.c (duplicate_decls): Remove special-case code to deal with template friends, and just do the obvious thing. * pt.c (register_specialization): Tweak for clarity, and also to clear DECL_INITIAL for an instantiation before it is merged with a specialization. (check_explicit_specialization): Fix indentation. (tsubst_friend_function): Handle both definitions in friend declaration and outside friend declarations. (tsubst_decl): Don't clear DECL_INITIAL for an instantiation. (regenerate_decl_from_template): Tweak accordingly. (instantiate_decl): Likewise. From-SVN: r23674
-rw-r--r--gcc/cp/ChangeLog15
-rw-r--r--gcc/cp/cp-tree.h7
-rw-r--r--gcc/cp/decl.c9
-rw-r--r--gcc/cp/pt.c141
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/friend36.C12
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/ttp53.C6
6 files changed, 127 insertions, 63 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 86503ae..bbd8664 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,18 @@
+1998-11-16 Mark Mitchell <mark@markmitchell.com>
+
+ * cp-tree.h (DECL_TEMPLATE_INSTANTIATED): New macro.
+ * decl.c (duplicate_decls): Remove special-case code to deal with
+ template friends, and just do the obvious thing.
+ * pt.c (register_specialization): Tweak for clarity, and also to
+ clear DECL_INITIAL for an instantiation before it is merged with a
+ specialization.
+ (check_explicit_specialization): Fix indentation.
+ (tsubst_friend_function): Handle both definitions in friend
+ declaration and outside friend declarations.
+ (tsubst_decl): Don't clear DECL_INITIAL for an instantiation.
+ (regenerate_decl_from_template): Tweak accordingly.
+ (instantiate_decl): Likewise.
+
1998-11-16 Jason Merrill <jason@yorick.cygnus.com>
* decl.c (cplus_expand_expr_stmt): Promote warning about naked
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a6e2e2d..8cf5594 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -65,6 +65,7 @@ Boston, MA 02111-1307, USA. */
Usage of DECL_LANG_FLAG_?:
0: DECL_ERROR_REPORTED (in VAR_DECL).
1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
+ DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
3: DECL_IN_AGGR_P.
4: DECL_MAYBE_TEMPLATE.
@@ -1812,6 +1813,12 @@ extern int flag_new_for_scope;
/* This function may be a guiding decl for a template. */
#define DECL_MAYBE_TEMPLATE(NODE) DECL_LANG_FLAG_4 (NODE)
+
+/* Nonzero if this VAR_DECL or FUNCTION_DECL has already been
+ instantiated, i.e. its definition has been generated from the
+ pattern given in the the template. */
+#define DECL_TEMPLATE_INSTANTIATED(NODE) DECL_LANG_FLAG_1(NODE)
+
/* We know what we're doing with this decl now. */
#define DECL_INTERFACE_KNOWN(NODE) DECL_LANG_FLAG_5 (NODE)
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 33c44494..a9779f9 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2989,9 +2989,6 @@ duplicate_decls (newdecl, olddecl)
DECL_TEMPLATE_RESULT (olddecl)))
cp_error ("invalid redeclaration of %D", newdecl);
TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl));
- DECL_TEMPLATE_PARMS (olddecl) = DECL_TEMPLATE_PARMS (newdecl);
- if (DECL_TEMPLATE_INFO (newdecl))
- DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl);
DECL_TEMPLATE_SPECIALIZATIONS (olddecl)
= chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl),
DECL_TEMPLATE_SPECIALIZATIONS (newdecl));
@@ -3123,11 +3120,7 @@ duplicate_decls (newdecl, olddecl)
DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl);
DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl);
DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
- if (DECL_TEMPLATE_INFO (newdecl) == NULL_TREE)
- {
- DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
- DECL_USE_TEMPLATE (newdecl) = DECL_USE_TEMPLATE (olddecl);
- }
+ DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
olddecl_friend = DECL_FRIEND_P (olddecl);
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index fb5bb54..655a72b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -831,15 +831,22 @@ register_specialization (spec, tmpl, args)
We transform the existing DECL in place so that
any pointers to it become pointers to the
- updated declaration. */
- duplicate_decls (spec, TREE_VALUE (s));
- return TREE_VALUE (s);
+ updated declaration.
+
+ If there was a definition for the template, but
+ not for the specialization, we want this to
+ look as if there is no definition, and vice
+ versa. */
+ DECL_INITIAL (fn) = NULL_TREE;
+ duplicate_decls (spec, fn);
+
+ return fn;
}
}
else if (DECL_TEMPLATE_SPECIALIZATION (fn))
{
- duplicate_decls (spec, TREE_VALUE (s));
- return TREE_VALUE (s);
+ duplicate_decls (spec, fn);
+ return fn;
}
}
}
@@ -1369,7 +1376,7 @@ check_explicit_specialization (declarator, decl, template_count, flags)
/* This is not really a declaration of a specialization.
It's just the name of an instantiation. But, it's not
a request for an instantiation, either. */
- SET_DECL_IMPLICIT_INSTANTIATION (decl);
+ SET_DECL_IMPLICIT_INSTANTIATION (decl);
/* Register this specialization so that we can find it
again. */
@@ -4247,16 +4254,30 @@ tsubst_friend_function (decl, args)
if (DECL_NAMESPACE_SCOPE_P (new_friend))
{
tree old_decl;
- tree new_friend_args;
-
+ tree new_friend_template_info;
+ tree new_friend_result_template_info;
+ 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);
if (TREE_CODE (new_friend) == TEMPLATE_DECL)
- /* This declaration is a `primary' template. */
- DECL_PRIMARY_TEMPLATE (new_friend) = new_friend;
+ {
+ /* This declaration is a `primary' template. */
+ DECL_PRIMARY_TEMPLATE (new_friend) = new_friend;
+
+ new_friend_is_defn
+ = DECL_INITIAL (DECL_RESULT (new_friend)) != NULL_TREE;
+ new_friend_result_template_info
+ = DECL_TEMPLATE_INFO (DECL_RESULT (new_friend));
+ }
+ else
+ {
+ new_friend_is_defn = DECL_INITIAL (new_friend) != NULL_TREE;
+ new_friend_result_template_info = NULL_TREE;
+ }
- /* We must save the DECL_TI_ARGS for NEW_FRIEND here because
- pushdecl may call duplicate_decls which will free NEW_FRIEND
- if possible. */
- new_friend_args = DECL_TI_ARGS (new_friend);
old_decl = pushdecl_namespace_level (new_friend);
if (old_decl != new_friend)
@@ -4295,36 +4316,55 @@ tsubst_friend_function (decl, args)
when `C<int>' is instantiated. Now, `f(int)' is defined
in the class. */
- if (TREE_CODE (old_decl) != TEMPLATE_DECL)
- /* duplicate_decls will take care of this case. */
+ if (!new_friend_is_defn)
+ /* On the other hand, if the in-class declaration does
+ *not* provide a definition, then we don't want to alter
+ existing definitions. We can just leave everything
+ alone. */
;
- else
+ else
{
- tree t;
-
- for (t = DECL_TEMPLATE_SPECIALIZATIONS (old_decl);
- t != NULL_TREE;
- t = TREE_CHAIN (t))
+ /* Overwrite whatever template info was there before, if
+ any, with the new template information pertaining to
+ the declaration. */
+ DECL_TEMPLATE_INFO (old_decl) = new_friend_template_info;
+
+ if (TREE_CODE (old_decl) != TEMPLATE_DECL)
+ /* duplicate_decls will take care of this case. */
+ ;
+ else
{
- tree spec = TREE_VALUE (t);
+ tree t;
+ tree new_friend_args;
+
+ DECL_TEMPLATE_INFO (DECL_RESULT (old_decl))
+ = new_friend_result_template_info;
+
+ new_friend_args = TI_ARGS (new_friend_template_info);
+ for (t = DECL_TEMPLATE_SPECIALIZATIONS (old_decl);
+ t != NULL_TREE;
+ t = TREE_CHAIN (t))
+ {
+ tree spec = TREE_VALUE (t);
- DECL_TI_ARGS (spec)
- = add_outermost_template_args (new_friend_args,
- DECL_TI_ARGS (spec));
- DECL_TI_ARGS (spec)
- = copy_to_permanent (DECL_TI_ARGS (spec));
- }
-
- /* Now, since specializations are always supposed to
- hang off of the most general template, we must move
- them. */
- t = most_general_template (old_decl);
- if (t != old_decl)
- {
- DECL_TEMPLATE_SPECIALIZATIONS (t)
- = chainon (DECL_TEMPLATE_SPECIALIZATIONS (t),
- DECL_TEMPLATE_SPECIALIZATIONS (old_decl));
- DECL_TEMPLATE_SPECIALIZATIONS (old_decl) = NULL_TREE;
+ DECL_TI_ARGS (spec)
+ = add_outermost_template_args (new_friend_args,
+ DECL_TI_ARGS (spec));
+ DECL_TI_ARGS (spec)
+ = copy_to_permanent (DECL_TI_ARGS (spec));
+ }
+
+ /* Now, since specializations are always supposed to
+ hang off of the most general template, we must move
+ them. */
+ t = most_general_template (old_decl);
+ if (t != old_decl)
+ {
+ DECL_TEMPLATE_SPECIALIZATIONS (t)
+ = chainon (DECL_TEMPLATE_SPECIALIZATIONS (t),
+ DECL_TEMPLATE_SPECIALIZATIONS (old_decl));
+ DECL_TEMPLATE_SPECIALIZATIONS (old_decl) = NULL_TREE;
+ }
}
}
@@ -5312,7 +5352,6 @@ tsubst_decl (t, args, type, in_decl)
DECL_ARGUMENTS (r) = tsubst (DECL_ARGUMENTS (t), args, t);
DECL_MAIN_VARIANT (r) = r;
DECL_RESULT (r) = NULL_TREE;
- DECL_INITIAL (r) = NULL_TREE;
TREE_STATIC (r) = 0;
TREE_PUBLIC (r) = TREE_PUBLIC (t);
@@ -8285,9 +8324,13 @@ regenerate_decl_from_template (decl, tmpl)
}
if (TREE_CODE (decl) == FUNCTION_DECL)
- /* Convince duplicate_decls to use the DECL_ARGUMENTS from the
- new decl. */
- DECL_INITIAL (new_decl) = error_mark_node;
+ {
+ /* Convince duplicate_decls to use the DECL_ARGUMENTS from the
+ new decl. */
+ DECL_INITIAL (new_decl) = error_mark_node;
+ /* And don't complain about a duplicate definition. */
+ DECL_INITIAL (decl) = NULL_TREE;
+ }
/* The immediate parent of the new template is still whatever it was
before, even though tsubst sets DECL_TI_TEMPLATE up as the most
@@ -8303,9 +8346,6 @@ regenerate_decl_from_template (decl, tmpl)
/* Call duplicate decls to merge the old and new declarations. */
duplicate_decls (new_decl, decl);
- if (TREE_CODE (decl) == FUNCTION_DECL)
- DECL_INITIAL (new_decl) = NULL_TREE;
-
/* Now, re-register the specialization. */
register_specialization (decl, gen_tmpl, args);
}
@@ -8332,8 +8372,7 @@ instantiate_decl (d)
my_friendly_assert (TREE_CODE (d) == FUNCTION_DECL
|| TREE_CODE (d) == VAR_DECL, 0);
- if ((TREE_CODE (d) == FUNCTION_DECL && DECL_INITIAL (d))
- || (TREE_CODE (d) == VAR_DECL && !DECL_IN_AGGR_P (d)))
+ if (DECL_TEMPLATE_INSTANTIATED (d))
/* D has already been instantiated. It might seem reasonable to
check whether or not D is an explict instantiation, and, if so,
stop here. But when an explicit instantiation is deferred
@@ -8398,9 +8437,6 @@ instantiate_decl (d)
cannot restructure the loop to just keep going until we find
a template with a definition, since that might go too far if
a specialization was declared, but not defined. */
- my_friendly_assert (!(TREE_CODE (d) == FUNCTION_DECL
- && DECL_INITIAL (DECL_TEMPLATE_RESULT (td))),
- 0);
my_friendly_assert (!(TREE_CODE (d) == VAR_DECL
&& !DECL_IN_AGGR_P (DECL_TEMPLATE_RESULT (td))),
0);
@@ -8483,6 +8519,7 @@ instantiate_decl (d)
}
regenerate_decl_from_template (d, td);
+ DECL_TEMPLATE_INSTANTIATED (d) = 1;
/* We already set the file and line above. Reset them now in case
they changed as a result of calling regenerate_decl_from_template. */
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend36.C b/gcc/testsuite/g++.old-deja/g++.pt/friend36.C
new file mode 100644
index 0000000..4a9042a
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/friend36.C
@@ -0,0 +1,12 @@
+// Build don't link:
+
+template <class T>
+void f(T) {} // ERROR - previously defined here
+
+template <class U>
+struct S {
+ template <class T>
+ friend void f(T) {} // ERROR - redeclaration
+};
+
+S<int> si;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ttp53.C b/gcc/testsuite/g++.old-deja/g++.pt/ttp53.C
index 694635d..e5e87b4 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/ttp53.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/ttp53.C
@@ -13,7 +13,7 @@ class H{
public:
#endif
template<template<class, class> class Caster, typename Source>
- static H<Type> cast(const H<Source>& s); // gets bogus error - candidate - XFAIL *-*-*
+ static H<Type> cast(const H<Source>& s);
#ifndef OK
template <typename Target, typename Source>
@@ -26,10 +26,10 @@ template <class, class> class caster;
template <typename Target, typename Source>
H<Target> foo(const H<Source>& s){
- return H<Target>::template cast<caster, Source>(s); // gets bogus error - no match - XFAIL *-*-*
+ return H<Target>::template cast<caster, Source>(s);
}
int main(){
H<int> i;
- foo<const int>(i); // gets bogus error - instantiated from here - XFAIL *-*-*
+ foo<const int>(i);
}