From 39c01e4c532100e8e5239591146eec1b20593547 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Fri, 31 Jul 1998 15:01:21 +0000 Subject: cp-tree.h (PROCESSING_REAL_TEMPLATE_DECL_P): New macro. 1998-07-31 Mark Mitchell * 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 --- gcc/cp/ChangeLog | 25 +++++ gcc/cp/cp-tree.h | 7 ++ gcc/cp/decl.c | 145 +++++++++++++++---------- gcc/cp/friend.c | 3 +- gcc/cp/pt.c | 134 ++++++++++++++++++----- gcc/cp/semantics.c | 4 + gcc/testsuite/g++.old-deja/g++.pt/crash15.C | 10 ++ gcc/testsuite/g++.old-deja/g++.pt/enum5.C | 4 + gcc/testsuite/g++.old-deja/g++.pt/explicit34.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/friend28.C | 22 ++++ gcc/testsuite/g++.old-deja/g++.pt/friend29.C | 16 +++ 11 files changed, 284 insertions(+), 88 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/crash15.C create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/enum5.C create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/friend28.C create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/friend29.C 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 + + * 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 * 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 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 + 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 + struct S1 { + template + 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 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 - 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 - struct S1 { - template - 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::B has depth two, while A has depth one. Also, - both A::B and A::B have depth one. */ + A::B has depth two, while A has depth one. + Both A::B and A::B 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 struct S { + template template + struct I {}; + }; + + is illegal, but: + + template struct S { + template struct I; + }; + + template template ::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 struct S1 { @@ -3109,8 +3169,28 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope) struct S1::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 + template + struct S { + A(const A& 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 +template +struct A { // ERROR - too many template parameter lists +public: + A() {} + + A(const A& 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 void foo(T t); template <> -void foo(int) {}; +void foo(int) {}; // ERROR - previously defined here. template <> void foo(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 a { +public: + friend mystream& operator>> <>( mystream&, a& thea ); +private: + T amember; +}; + +template mystream& operator>>( mystream& s, a& thea ); + +template<> mystream& operator>> ( mystream& s, a& thea ); + +template class a; + +template<> mystream& operator>> ( mystream& s, a& 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 a { +public: + friend void foo<>( a& thea ); +private: + T amember; +}; + +template void foo( a& thea ) +{ + thea.amember = 0; +} + +template class a; + -- cgit v1.1