OSDN Git Service

1998-07-31 Mark Mitchell <mark@markmitchell.com>
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 31 Jul 1998 15:01:21 +0000 (15:01 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 31 Jul 1998 15:01:21 +0000 (15:01 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@21505 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/friend.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/testsuite/g++.old-deja/g++.pt/crash15.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/enum5.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/explicit34.C
gcc/testsuite/g++.old-deja/g++.pt/friend28.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/friend29.C [new file with mode: 0644]

index 69c8447..3feeaac 100644 (file)
@@ -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
index be97c1b..4e1d1bd 100644 (file)
@@ -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;
index 2558386..0b32a3d 100644 (file)
@@ -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
index 5a97766..db50258 100644 (file)
@@ -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)
     {
index 07174a0..9e13916 100644 (file)
@@ -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;
          }
 
index a6d03e1..fa3dd49 100644 (file)
@@ -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 (file)
index 0000000..75b1054
--- /dev/null
@@ -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 (file)
index 0000000..f6feefb
--- /dev/null
@@ -0,0 +1,4 @@
+// Build don't link:
+
+template <>
+enum E {e}; // ERROR - template declaration of enum
index 487525e..0aede38 100644 (file)
@@ -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 (file)
index 0000000..f86d0b6
--- /dev/null
@@ -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 (file)
index 0000000..e141aaa
--- /dev/null
@@ -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>;
+