aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@markmitchell.com>1998-07-31 15:01:21 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1998-07-31 15:01:21 +0000
commit39c01e4c532100e8e5239591146eec1b20593547 (patch)
treecde82810bdca623c7d1ae0769916edf5170cd355
parent5f97de0ac982f8439ca78db6652fb722fe4fafe9 (diff)
downloadgcc-39c01e4c532100e8e5239591146eec1b20593547.zip
gcc-39c01e4c532100e8e5239591146eec1b20593547.tar.gz
gcc-39c01e4c532100e8e5239591146eec1b20593547.tar.bz2
cp-tree.h (PROCESSING_REAL_TEMPLATE_DECL_P): New macro.
1998-07-31 Mark Mitchell <mark@markmitchell.com> * cp-tree.h (PROCESSING_REAL_TEMPLATE_DECL_P): New macro. (maybe_check_template_type): New function. * decl.c (maybe_process_template_type_declaration): New function, split out from pushtag Call maybe_check_template_type. (pushtag): Use it. Use PROCESSING_REAL_TEMPLATE_DECL_P. (xref_tag): Use PROCESSING_REAL_TEMPLATE_DECL_P. * friend.c (do_friend): Use PROCESSING_REAL_TEMPLATE_DECL_P. * pt.c (template_class_depth_real): Generalization of ... (template_class_depth): Use it. (register_specialization): Use duplicate_decls for duplicate declarations of specializations. (maybe_check_template_type): New function. (push_template_decl_real): Fix comment. (convert_nontype_argument): Likewise. (lookup_template_class): Likewise. Avoid an infinite loop on erroneous code. (tsubst_friend_function): Fix comment. (tsubst, case FUNCTION_DECL): Deal with a DECL_TI_TEMPLATE that is an IDENTIFIER_NODE. * semantics.c (begin_function_definition): Use reset_specialization to note that template headers don't apply directly to declarations after the opening curly for a function. From-SVN: r21505
-rw-r--r--gcc/cp/ChangeLog25
-rw-r--r--gcc/cp/cp-tree.h7
-rw-r--r--gcc/cp/decl.c145
-rw-r--r--gcc/cp/friend.c3
-rw-r--r--gcc/cp/pt.c134
-rw-r--r--gcc/cp/semantics.c4
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/crash15.C10
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/enum5.C4
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/explicit34.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/friend28.C22
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/friend29.C16
11 files changed, 284 insertions, 88 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 69c8447..3feeaac 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,28 @@
+1998-07-31 Mark Mitchell <mark@markmitchell.com>
+
+ * cp-tree.h (PROCESSING_REAL_TEMPLATE_DECL_P): New macro.
+ (maybe_check_template_type): New function.
+ * decl.c (maybe_process_template_type_declaration): New function,
+ split out from pushtag Call maybe_check_template_type.
+ (pushtag): Use it. Use PROCESSING_REAL_TEMPLATE_DECL_P.
+ (xref_tag): Use PROCESSING_REAL_TEMPLATE_DECL_P.
+ * friend.c (do_friend): Use PROCESSING_REAL_TEMPLATE_DECL_P.
+ * pt.c (template_class_depth_real): Generalization of ...
+ (template_class_depth): Use it.
+ (register_specialization): Use duplicate_decls for duplicate
+ declarations of specializations.
+ (maybe_check_template_type): New function.
+ (push_template_decl_real): Fix comment.
+ (convert_nontype_argument): Likewise.
+ (lookup_template_class): Likewise. Avoid an infinite loop on
+ erroneous code.
+ (tsubst_friend_function): Fix comment.
+ (tsubst, case FUNCTION_DECL): Deal with a DECL_TI_TEMPLATE that is
+ an IDENTIFIER_NODE.
+ * semantics.c (begin_function_definition): Use
+ reset_specialization to note that template headers don't apply
+ directly to declarations after the opening curly for a function.
+
1998-07-29 Jason Merrill <jason@yorick.cygnus.com>
* decl.c (push_overloaded_decl): Use current_namespace instead of
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index be97c1b..4e1d1bd 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1692,6 +1692,12 @@ extern int flag_new_for_scope;
#define SET_CLASSTYPE_EXPLICIT_INSTANTIATION(NODE) \
(CLASSTYPE_USE_TEMPLATE(NODE) = 3)
+/* Non-zero iff we are currently processing a declaration for an
+ entity with its own template parameter list, and which is not a
+ full specialization. */
+#define PROCESSING_REAL_TEMPLATE_DECL_P() \
+ (processing_template_decl > template_class_depth (current_class_type))
+
/* This function may be a guiding decl for a template. */
#define DECL_MAYBE_TEMPLATE(NODE) DECL_LANG_FLAG_4 (NODE)
/* We know what we're doing with this decl now. */
@@ -2794,6 +2800,7 @@ extern int template_class_depth PROTO((tree));
extern int is_specialization_of PROTO((tree, tree));
extern int comp_template_args PROTO((tree, tree));
extern void maybe_process_partial_specialization PROTO((tree));
+extern void maybe_check_template_type PROTO((tree));
extern int processing_specialization;
extern int processing_explicit_instantiation;
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 2558386..0b32a3d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -176,6 +176,7 @@ static int member_function_or_else PROTO((tree, tree, char *));
static void bad_specifiers PROTO((tree, char *, int, int, int, int,
int));
static void lang_print_error_function PROTO((char *));
+static tree maybe_process_template_type_declaration PROTO((tree, int, struct binding_level*));
#if defined (DEBUG_CP_BINDING_LEVELS)
static void indent PROTO((void));
@@ -2223,6 +2224,88 @@ pop_everything ()
#endif
}
+/* The type TYPE is being declared. If it is a class template, or a
+ specialization of a class template, do any processing required and
+ perform error-checking. If IS_FRIEND is non-zero, this TYPE is
+ being declared a friend. B is the binding level at which this TYPE
+ should be bound.
+
+ Returns the TYPE_DECL for TYPE, which may have been altered by this
+ processing. */
+
+static tree
+maybe_process_template_type_declaration (type, globalize, b)
+ tree type;
+ int globalize;
+ struct binding_level* b;
+{
+ tree decl = TYPE_NAME (type);
+
+ if (processing_template_parmlist)
+ /* You can't declare a new template type in a template parameter
+ list. But, you can declare a non-template type:
+
+ template <class A*> struct S;
+
+ is a forward-declaration of `A'. */
+ ;
+ else
+ {
+ maybe_check_template_type (type);
+
+ if (IS_AGGR_TYPE (type)
+ && (/* If !GLOBALIZE then we are looking at a definition.
+ It may not be a primary template. (For example, in:
+
+ template <class T>
+ struct S1 { class S2 {}; }
+
+ we have to push_template_decl for S2.) */
+ (processing_template_decl && !globalize)
+ /* If we are declaring a friend template class, we will
+ have GLOBALIZE set, since something like:
+
+ template <class T>
+ struct S1 {
+ template <class U>
+ friend class S2;
+ };
+
+ declares S2 to be at global scope. */
+ || PROCESSING_REAL_TEMPLATE_DECL_P ()))
+ {
+ /* This may change after the call to
+ push_template_decl_real, but we want the original value. */
+ tree name = DECL_NAME (decl);
+
+ decl = push_template_decl_real (decl, globalize);
+ /* If the current binding level is the binding level for the
+ template parameters (see the comment in
+ begin_template_parm_list) and the enclosing level is a class
+ scope, and we're not looking at a friend, push the
+ declaration of the member class into the class scope. In the
+ friend case, push_template_decl will already have put the
+ friend into global scope, if appropriate. */
+ if (!globalize && b->pseudo_global
+ && b->level_chain->parm_flag == 2)
+ {
+ pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type),
+ b->level_chain);
+ /* Put this tag on the list of tags for the class, since
+ that won't happen below because B is not the class
+ binding level, but is instead the pseudo-global level. */
+ b->level_chain->tags =
+ saveable_tree_cons (name, type, b->level_chain->tags);
+ TREE_NONLOCAL_FLAG (type) = 1;
+ if (TYPE_SIZE (current_class_type) == NULL_TREE)
+ CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags;
+ }
+ }
+ }
+
+ return decl;
+}
+
/* Push a tag name NAME for struct/class/union/enum type TYPE.
Normally put it into the inner-most non-tag-transparent scope,
but if GLOBALIZE is true, put it in the inner-most non-class scope.
@@ -2298,63 +2381,8 @@ pushtag (name, type, globalize)
TYPE_NAME (type) = d;
DECL_CONTEXT (d) = FROB_CONTEXT (context);
- if (processing_template_parmlist)
- /* You can't declare a new template type in a template
- parameter list. But, you can declare a non-template
- type:
-
- template <class A*> struct S;
-
- is a forward-declaration of `A'. */
- ;
- else if (IS_AGGR_TYPE (type)
- && (/* If !GLOBALIZE then we are looking at a
- definition. It may not be a primary template.
- (For example, in:
-
- template <class T>
- struct S1 { class S2 {}; }
-
- we have to push_template_decl for S2.) */
- (processing_template_decl && !globalize)
- /* If we are declaring a friend template class, we
- will have GLOBALIZE set, since something like:
-
- template <class T>
- struct S1 {
- template <class U>
- friend class S2;
- };
-
- declares S2 to be at global scope. */
- || (processing_template_decl >
- template_class_depth (current_class_type))))
- {
- d = push_template_decl_real (d, globalize);
- /* If the current binding level is the binding level for
- the template parameters (see the comment in
- begin_template_parm_list) and the enclosing level is
- a class scope, and we're not looking at a friend,
- push the declaration of the member class into the
- class scope. In the friend case, push_template_decl
- will already have put the friend into global scope,
- if appropriate. */
- if (!globalize && b->pseudo_global
- && b->level_chain->parm_flag == 2)
- {
- pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type),
- b->level_chain);
- /* Put this tag on the list of tags for the class,
- since that won't happen below because B is not
- the class binding level, but is instead the
- pseudo-global level. */
- b->level_chain->tags =
- saveable_tree_cons (name, type, b->level_chain->tags);
- TREE_NONLOCAL_FLAG (type) = 1;
- if (TYPE_SIZE (current_class_type) == NULL_TREE)
- CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags;
- }
- }
+ d = maybe_process_template_type_declaration (type,
+ globalize, b);
if (b->parm_flag == 2)
d = pushdecl_class_level (d);
@@ -11349,8 +11377,7 @@ xref_tag (code_type_node, name, binfo, globalize)
{
if (current_class_type
&& template_class_depth (current_class_type)
- && (processing_template_decl
- > 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
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 5a97766..db50258 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -354,8 +354,7 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
}
if (TREE_CODE (decl) == FUNCTION_DECL)
- is_friend_template = processing_template_decl >
- template_class_depth (current_class_type);
+ is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
if (ctype)
{
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 07174a0..9e13916 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -121,6 +121,7 @@ static tree most_specialized PROTO((tree, tree, tree));
static tree most_specialized_class PROTO((tree, tree));
static tree most_general_template PROTO((tree));
static void set_mangled_name_for_template_decl PROTO((tree));
+static int template_class_depth_real PROTO((tree, int));
/* We use TREE_VECs to hold template arguments. If there is only one
level of template arguments, then the TREE_VEC contains the
@@ -234,12 +235,19 @@ finish_member_template_decl (template_parameters, decl)
struct B {};
};
- A<T>::B<U> has depth two, while A<T> has depth one. Also,
- both A<T>::B<int> and A<int>::B<U> have depth one. */
+ A<T>::B<U> has depth two, while A<T> has depth one.
+ Both A<T>::B<int> and A<int>::B<U> have depth one, if
+ COUNT_SPECIALIZATIONS is 0 or if they are instantiations, not
+ specializations.
+
+ This function is guaranteed to return 0 if passed NULL_TREE so
+ that, for example, `template_class_depth (current_class_type)' is
+ always safe. */
int
-template_class_depth (type)
+template_class_depth_real (type, count_specializations)
tree type;
+ int count_specializations;
{
int depth;
@@ -249,12 +257,25 @@ template_class_depth (type)
type = TYPE_CONTEXT (type))
if (CLASSTYPE_TEMPLATE_INFO (type)
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))
- && uses_template_parms (CLASSTYPE_TI_ARGS (type)))
+ && ((count_specializations
+ && CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
+ || uses_template_parms (CLASSTYPE_TI_ARGS (type))))
++depth;
return depth;
}
+/* Returns the template nesting level of the indicated class TYPE.
+ Like template_class_depth_real, but instantiations do not count in
+ the depth. */
+
+int
+template_class_depth (type)
+ tree type;
+{
+ return template_class_depth_real (type, /*count_specializations=*/0);
+}
+
/* Returns 1 if processing DECL as part of do_pending_inlines
needs us to push template parms. */
@@ -742,11 +763,8 @@ register_specialization (spec, tmpl, args)
}
else if (DECL_TEMPLATE_SPECIALIZATION (fn))
{
- if (DECL_INITIAL (fn))
- cp_error ("duplicate specialization of %D", fn);
-
- TREE_VALUE (s) = spec;
- return spec;
+ duplicate_decls (spec, TREE_VALUE (s));
+ return TREE_VALUE (s);
}
}
}
@@ -1300,6 +1318,50 @@ check_explicit_specialization (declarator, decl, template_count, flags)
return decl;
}
+/* TYPE is being declared. Verify that the use of template headers
+ and such is reasonable. Issue error messages if not. */
+
+void
+maybe_check_template_type (type)
+ tree type;
+{
+ if (template_header_count)
+ {
+ /* We are in the scope of some `template <...>' header. */
+
+ int context_depth
+ = template_class_depth_real (TYPE_CONTEXT (type),
+ /*count_specializations=*/1);
+
+ if (template_header_count <= context_depth)
+ /* This is OK; the template headers are for the context. We
+ are actually too lenient here; like
+ check_explicit_specialization we should consider the number
+ of template types included in the actual declaration. For
+ example,
+
+ template <class T> struct S {
+ template <class U> template <class V>
+ struct I {};
+ };
+
+ is illegal, but:
+
+ template <class T> struct S {
+ template <class U> struct I;
+ };
+
+ template <class T> template <class U.
+ struct S<T>::I {};
+
+ is not. */
+ ;
+ else if (template_header_count > context_depth + 1)
+ /* There are two many template parameter lists. */
+ cp_error ("too many template parameter lists in declaration of `%T'", type);
+ }
+}
+
/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
parameters. These are represented in the same format used for
DECL_TEMPLATE_PARMS. */
@@ -1951,9 +2013,7 @@ push_template_decl_real (decl, is_friend)
/* 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. With guiding declarations, however, we
- push the template so that subsequent declarations of the template
- will match this one. */
+ parameters of the class. */
if (! ctx
&& !(is_friend && template_class_depth (current_class_type) > 0))
tmpl = pushdecl_namespace_level (tmpl);
@@ -2278,10 +2338,10 @@ convert_nontype_argument (type, expr)
if (TREE_CODE (type_referred_to) == FUNCTION_TYPE)
{
/* For a non-type template-parameter of type reference to
- function, no conversions apply. If the
- template-argument represents a set of overloaded
- functions, the matching function is selected from the
- set (_over.over_). */
+ function, no conversions apply. If the
+ template-argument represents a set of overloaded
+ functions, the matching function is selected from the
+ set (_over.over_). */
tree fns = expr;
tree fn;
@@ -3096,7 +3156,7 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope)
if (arg_depth == 1 && parm_depth > 1)
{
- /* We've been with an incomplete set of template arguments.
+ /* We've been given an incomplete set of template arguments.
For example, given:
template <class T> struct S1 {
@@ -3109,8 +3169,28 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope)
<class U> struct S1<T>::S2'. We must fill in the missing
arguments. */
my_friendly_assert (context != NULL_TREE, 0);
- while (!IS_AGGR_TYPE_CODE (TREE_CODE (context)))
+ while (!IS_AGGR_TYPE_CODE (TREE_CODE (context))
+ && context != global_namespace)
context = DECL_REAL_CONTEXT (context);
+
+ if (context == global_namespace)
+ /* This is bad. We cannot get enough arguments, even from
+ the surrounding context, to resolve this class. One
+ case where this might happen is (illegal) code like:
+
+ template <class U>
+ template <class T>
+ struct S {
+ A(const A<T>& a) {}
+ };
+
+ We should catch this error sooner (at the opening curly
+ for `S', but it is better to be safe than sorry here. */
+ {
+ cp_error ("invalid use of `%D'", template);
+ return error_mark_node;
+ }
+
arglist = add_to_template_args (CLASSTYPE_TI_ARGS (context),
arglist);
arg_depth = TMPL_ARGS_DEPTH (arglist);
@@ -3667,8 +3747,8 @@ tsubst_friend_function (decl, args)
args, NULL_TREE),
tsubst (DECL_TI_ARGS (decl),
args, NULL_TREE));
- /* FIXME: The decl we create via the next tsubst be created on a
- temporary obstack. */
+ /* FIXME: The decl we create via the next tsubst could be
+ created on a temporary obstack. */
new_friend = tsubst (decl, args, NULL_TREE);
tmpl = determine_specialization (template_id, new_friend,
&new_args,
@@ -4833,12 +4913,14 @@ tsubst (t, args, in_decl)
};
Here, the DECL_TI_TEMPLATE for the friend declaration
- will be a LOOKUP_EXPR. We are being called from
- tsubst_friend_function, and we want only to create a
- new decl (R) with appropriate types so that we can call
- determine_specialization. */
- my_friendly_assert (TREE_CODE (DECL_TI_TEMPLATE (t))
- == LOOKUP_EXPR, 0);
+ will be a LOOKUP_EXPR or an IDENTIFIER_NODE. We are
+ being called from tsubst_friend_function, and we want
+ only to create a new decl (R) with appropriate types so
+ that we can call determine_specialization. */
+ my_friendly_assert ((TREE_CODE (DECL_TI_TEMPLATE (t))
+ == LOOKUP_EXPR)
+ || (TREE_CODE (DECL_TI_TEMPLATE (t))
+ == IDENTIFIER_NODE), 0);
gen_tmpl = NULL_TREE;
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index a6d03e1..fa3dd49 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1098,6 +1098,10 @@ begin_function_definition (decl_specs, declarator)
return 0;
reinit_parse_for_function ();
+ /* The things we're about to see are not directly qualified by any
+ template headers we've seen thus far. */
+ reset_specialization ();
+
return 1;
}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash15.C b/gcc/testsuite/g++.old-deja/g++.pt/crash15.C
new file mode 100644
index 0000000..75b1054
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/crash15.C
@@ -0,0 +1,10 @@
+// Build don't link:
+
+template <class T>
+template <class U>
+struct A { // ERROR - too many template parameter lists
+public:
+ A() {}
+
+ A(const A<T>& b) {} // ERROR - invalid use of template
+};
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/enum5.C b/gcc/testsuite/g++.old-deja/g++.pt/enum5.C
new file mode 100644
index 0000000..f6feefb
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/enum5.C
@@ -0,0 +1,4 @@
+// Build don't link:
+
+template <>
+enum E {e}; // ERROR - template declaration of enum
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit34.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit34.C
index 487525e..0aede38 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/explicit34.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit34.C
@@ -4,7 +4,7 @@ template <class T>
void foo(T t);
template <>
-void foo(int) {};
+void foo(int) {}; // ERROR - previously defined here.
template <>
void foo<int>(int) {} // ERROR - duplicate specialization.
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend28.C b/gcc/testsuite/g++.old-deja/g++.pt/friend28.C
new file mode 100644
index 0000000..f86d0b6
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/friend28.C
@@ -0,0 +1,22 @@
+// Build don't link:
+
+class mystream;
+
+template <class T> class a {
+public:
+ friend mystream& operator>> <>( mystream&, a<T>& thea );
+private:
+ T amember;
+};
+
+template <class T> mystream& operator>>( mystream& s, a<T>& thea );
+
+template<> mystream& operator>> <int>( mystream& s, a<int>& thea );
+
+template class a<int>;
+
+template<> mystream& operator>> <int>( mystream& s, a<int>& thea )
+{
+ thea.amember = 0;
+ return s;
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend29.C b/gcc/testsuite/g++.old-deja/g++.pt/friend29.C
new file mode 100644
index 0000000..e141aaa
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/friend29.C
@@ -0,0 +1,16 @@
+// Build don't link:
+
+template <class T> class a {
+public:
+ friend void foo<>( a<T>& thea );
+private:
+ T amember;
+};
+
+template <class T> void foo( a<T>& thea )
+{
+ thea.amember = 0;
+}
+
+template class a<int>;
+