cp-tree.h (IDENTIFIER_TYPENAME_P): Use OPERATOR_TYPENAME_FORMAT here.
authorMark Mitchell <mark@markmitchell.com>
Wed, 6 Jan 1999 23:38:05 +0000 (23:38 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Wed, 6 Jan 1999 23:38:05 +0000 (23:38 +0000)
        * cp-tree.h (IDENTIFIER_TYPENAME_P): Use OPERATOR_TYPENAME_FORMAT
here.
(lang_type): Add is_partial_instantiation.  Decrease width of
dummy.
(PARTIAL_INSTANTIATION_P): New macro.
(OPERATOR_TYPENAME_P): Remove.
* decl.c (unary_op_p): Use IDENTIFIER_TYPENAME_P, not
OPERATOR_TYPENAME_P.
(grok_op_properties): Likewise.
* friend.c (do_friend): Handle friends that are member functions
correctly.
* lex.c (init_parse): Use OPERATOR_TYPENAME_FORMAT.
* pt.c (instantiate_class_template): Rework for clarity.  Avoid
leaving TYPE_BEING_DEFINED set in obscure cases.  Don't do
any more partial instantiation than is absolutely necessary for
implicit typename.  Set PARTIAL_INSTANTIATION_P.
(tsubst_decl): Use IDENTIFIER_TYPENAME_P.
* semantics.c (begin_class_definition): Handle partial
specializations of a type that was previously partially
instantiated.

From-SVN: r24548

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/friend.c
gcc/cp/lex.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/testsuite/g++.old-deja/g++.pt/friend39.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/spec27.C [new file with mode: 0644]

index 7e1567b489c59fdc736d64efd7a02702be93988a..478180ab80ea5cf4883973883a655ed7d0f29ebe 100644 (file)
@@ -1,3 +1,26 @@
+1999-01-06  Mark Mitchell  <mark@markmitchell.com>
+
+       * cp-tree.h (IDENTIFIER_TYPENAME_P): Use OPERATOR_TYPENAME_FORMAT
+       here. 
+       (lang_type): Add is_partial_instantiation.  Decrease width of
+       dummy. 
+       (PARTIAL_INSTANTIATION_P): New macro.
+       (OPERATOR_TYPENAME_P): Remove.
+       * decl.c (unary_op_p): Use IDENTIFIER_TYPENAME_P, not
+       OPERATOR_TYPENAME_P. 
+       (grok_op_properties): Likewise.
+       * friend.c (do_friend): Handle friends that are member functions
+       correctly. 
+       * lex.c (init_parse): Use OPERATOR_TYPENAME_FORMAT.
+       * pt.c (instantiate_class_template): Rework for clarity.  Avoid
+       leaving TYPE_BEING_DEFINED set in obscure cases.  Don't do
+       any more partial instantiation than is absolutely necessary for
+       implicit typename.  Set PARTIAL_INSTANTIATION_P.
+       (tsubst_decl): Use IDENTIFIER_TYPENAME_P.
+       * semantics.c (begin_class_definition): Handle partial
+       specializations of a type that was previously partially
+       instantiated. 
+       
 Wed Jan  6 03:18:53 1999  Mark Elbrecht  <snowball3@usa.net.
 
        * g++spec.c (LIBSTDCXX): Provide default definition.
index b255933a1ce0f4c7fee694e384db5c23f1c23cf4..db6e2281577340f17e16916dd0d8db33ee85ea4b 100644 (file)
@@ -1,5 +1,5 @@
 /* Definitions for C++ parsing and type checking.
-   Copyright (C) 1987, 92-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 92-97, 1998, 1999 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -293,10 +293,12 @@ struct tree_srcloc
 /* Nonzero if this identifier is the prefix for a mangled C++ operator name.  */
 #define IDENTIFIER_OPNAME_P(NODE) TREE_LANG_FLAG_2(NODE)
 
-#define IDENTIFIER_TYPENAME_P(NODE)    \
-  (! strncmp (IDENTIFIER_POINTER (NODE),                       \
-             IDENTIFIER_POINTER (ansi_opname[(int) TYPE_EXPR]),        \
-             IDENTIFIER_LENGTH (ansi_opname[(int) TYPE_EXPR])))
+/* Nonzero if this identifier is the name of a type-conversion
+   operator.  */
+#define IDENTIFIER_TYPENAME_P(NODE)                    \
+  (! strncmp (IDENTIFIER_POINTER (NODE),               \
+              OPERATOR_TYPENAME_FORMAT,                        \
+             strlen (OPERATOR_TYPENAME_FORMAT)))
 
 /* Nonzero means reject anything that ANSI standard C forbids.  */
 extern int pedantic;
@@ -723,11 +725,12 @@ struct lang_type
       unsigned has_complex_assign_ref : 1;
       unsigned has_abstract_assign_ref : 1;
       unsigned non_aggregate : 1;
+      unsigned is_partial_instantiation : 1;
 
       /* The MIPS compiler gets it wrong if this struct also
         does not fill out to a multiple of 4 bytes.  Add a
         member `dummy' with new bits if you go over the edge.  */
-      unsigned dummy : 12;
+      unsigned dummy : 11;
     } type_flags;
 
   int n_ancestors;
@@ -1913,6 +1916,12 @@ extern int flag_new_for_scope;
 #define DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION(DECL) \
   (DECL_TEMPLATE_INFO (DECL) && !DECL_USE_TEMPLATE (DECL))
 
+/* Non-zero if TYPE is a partial instantiation of a template class,
+   i.e., an instantiation whose instantiation arguments involve
+   template types.  */
+#define PARTIAL_INSTANTIATION_P(TYPE) \
+  (TYPE_LANG_SPECIFIC (TYPE)->type_flags.is_partial_instantiation)
+
 /* 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.  */
@@ -2189,12 +2198,6 @@ extern int current_function_parms_stored;
 #define OPERATOR_ASSIGN_FORMAT "__a%s"
 #define OPERATOR_FORMAT "__%s"
 #define OPERATOR_TYPENAME_FORMAT "__op"
-#define OPERATOR_TYPENAME_P(ID_NODE) \
-  (IDENTIFIER_POINTER (ID_NODE)[0] == '_'      \
-   && IDENTIFIER_POINTER (ID_NODE)[1] == '_'   \
-   && IDENTIFIER_POINTER (ID_NODE)[2] == 'o'   \
-   && IDENTIFIER_POINTER (ID_NODE)[3] == 'p')
-
 
 /* Cannot use '$' up front, because this confuses gdb
    (names beginning with '$' are gdb-local identifiers).
index 8dc8008ba98c3eee284cc2c9300be733ff03940d..edad0a980974c3ae29463ae89206e21c1b25463d 100644 (file)
@@ -11653,7 +11653,7 @@ unary_op_p (name)
   return (name == ansi_opname [(int) TRUTH_NOT_EXPR]
          || name == ansi_opname [(int) BIT_NOT_EXPR]
          || name == ansi_opname [(int) COMPONENT_REF]
-         || OPERATOR_TYPENAME_P (name));
+         || IDENTIFIER_TYPENAME_P (name));
 }
 
 /* Do a little sanity-checking on how they declared their operator.  */
@@ -11744,7 +11744,7 @@ grok_op_properties (decl, virtualp, friendp)
         an enumeration, or a reference to an enumeration.  13.4.0.6 */
       if (! methodp || DECL_STATIC_FUNCTION_P (decl))
        {
-         if (OPERATOR_TYPENAME_P (name)
+         if (IDENTIFIER_TYPENAME_P (name)
              || name == ansi_opname[(int) CALL_EXPR]
              || name == ansi_opname[(int) MODIFY_EXPR]
              || name == ansi_opname[(int) COMPONENT_REF]
index 98991ea452b29cbf4580307f004c11bb45176c81..c26d6956c116175c2ec795d85de91ef9f2c13f49 100644 (file)
@@ -1,5 +1,5 @@
 /* Help friends in C++.
-   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -370,16 +370,20 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
 
          if (is_friend_template)
            decl = DECL_TI_TEMPLATE (push_template_decl (decl));
-
+         else if (template_class_depth (current_class_type))
+           decl = push_template_decl_real (decl, /*is_friend=*/1);
+
+         /* We can't do lookup in a type that involves template
+            parameters.  Instead, we rely on tsubst_friend_function
+            to check the validity of the declaration later.  */
+         if (uses_template_parms (ctype))
+           add_friend (current_class_type, decl);
          /* A nested class may declare a member of an enclosing class
             to be a friend, so we do lookup here even if CTYPE is in
             the process of being defined.  */
-         if (TYPE_SIZE (ctype) != 0 || TYPE_BEING_DEFINED (ctype))
+         else if (TYPE_SIZE (ctype) != 0 || TYPE_BEING_DEFINED (ctype))
            {
-             /* But, we defer looup in template specializations until
-                they are fully specialized.  */
-             if (template_class_depth (ctype) == 0)
-               decl = check_classfn (ctype, decl);
+             decl = check_classfn (ctype, decl);
 
              if (decl)
                add_friend (current_class_type, decl);
index 0d8996f6eb282641c0a01bad04a07e660da701f4..505fbba5fed47f31e08231d7ace2b4bb114ad760 100644 (file)
@@ -1,5 +1,5 @@
 /* Separate lexical analyzer for GNU C++.
-   Copyright (C) 1987, 89, 92-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 89, 92-97, 1998, 1999 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -650,7 +650,7 @@ init_parse (filename)
   IDENTIFIER_OPNAME_P (ansi_opname[(int) VEC_NEW_EXPR]) = 1;
   ansi_opname[(int) VEC_DELETE_EXPR] = get_identifier ("__vd");
   IDENTIFIER_OPNAME_P (ansi_opname[(int) VEC_DELETE_EXPR]) = 1;
-  ansi_opname[(int) TYPE_EXPR] = get_identifier ("__op");
+  ansi_opname[(int) TYPE_EXPR] = get_identifier (OPERATOR_TYPENAME_FORMAT);
   IDENTIFIER_OPNAME_P (ansi_opname[(int) TYPE_EXPR]) = 1;
 
   /* This is not true: these operators are not defined in ANSI,
index e27286789bac170679ec3c4041bc7fdc87001f76..9a0545ecd9f3a331b4a66e126fe94a26c2899899 100644 (file)
@@ -1,5 +1,5 @@
 /* Handle parameterized types (templates) for GNU C++.
-   Copyright (C) 1992, 93-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1992, 93-97, 1998, 1999 Free Software Foundation, Inc.
    Written by Ken Raeburn (raeburn@cygnus.com) while at Watchmaker Computing.
    Rewritten by Jason Merrill (jason@cygnus.com).
 
@@ -4436,7 +4436,6 @@ instantiate_class_template (type)
 {
   tree template, args, pattern, t;
   tree typedecl;
-  int is_partial_instantiation;
 
   if (type == error_mark_node)
     return error_mark_node;
@@ -4457,9 +4456,33 @@ instantiate_class_template (type)
   /* Figure out which arguments are being used to do the
      instantiation.  */
   args = CLASSTYPE_TI_ARGS (type);
-  is_partial_instantiation = uses_template_parms (args);
+  PARTIAL_INSTANTIATION_P (type) = uses_template_parms (args);
 
-  if (is_partial_instantiation)
+  if (pedantic && PARTIAL_INSTANTIATION_P (type))
+    /* If this is a partial instantiation, then we can't instantiate
+       the type; there's no telling whether or not one of the
+       template parameters might eventually be instantiated to some
+       value that results in a specialization being used.  For
+       example, consider:
+
+         template <class T>
+         struct S {};
+
+         template <class U> 
+         void f(S<U>);
+            
+         template <> 
+         struct S<int> {};
+
+       Now, the `S<U>' in `f<int>' is the specialization, not an
+       instantiation of the original template.  Mark the type as
+       complete, in the same way that we do for a definition of a
+       template class.  */
+    goto end;
+
+  /* Determine what specialization of the original template to
+     instantiate.  */
+  if (PARTIAL_INSTANTIATION_P (type))
     /* There's no telling which specialization is appropriate at this
        point.  Since all peeking at the innards of this partial
        instantiation are extensions (like the "implicit typename"
@@ -4500,9 +4523,39 @@ instantiate_class_template (type)
   else
     pattern = TREE_TYPE (template);
 
+  /* If the template we're instantiating is incomplete, then clearly
+     there's nothing we can do.  */
   if (TYPE_SIZE (pattern) == NULL_TREE)
     goto end;
 
+  /* If this is a partial instantiation, don't tsubst anything.  We will
+     only use this type for implicit typename, so the actual contents don't
+     matter.  All that matters is whether a particular name is a type.  */
+  if (PARTIAL_INSTANTIATION_P (type))
+    {
+      /* The fields set here must be kept in sync with those cleared
+        in begin_class_definition.  */
+      TYPE_BINFO_BASETYPES (type) = TYPE_BINFO_BASETYPES (pattern);
+      TYPE_FIELDS (type) = TYPE_FIELDS (pattern);
+      TYPE_METHODS (type) = TYPE_METHODS (pattern);
+      CLASSTYPE_TAGS (type) = CLASSTYPE_TAGS (pattern);
+      /* Pretend that the type is complete, so that we will look
+        inside it during name lookup and such.  */
+      TYPE_SIZE (type) = integer_zero_node;
+      goto end;
+    }
+
+  /* If we've recursively instantiated too many templates, stop.  */
+  if (! push_tinst_level (type))
+    goto end;
+
+  /* Now we're really doing the instantiation.  Mark the type as in
+     the process of being defined.  */
+  TYPE_BEING_DEFINED (type) = 1;
+
+  maybe_push_to_top_level (uses_template_parms (type));
+  pushclass (type, 0);
+
   if (t)
     {
       /* This TYPE is actually a instantiation of of a partial
@@ -4531,31 +4584,6 @@ instantiate_class_template (type)
        args = inner_args;
     }
 
-  if (pedantic && is_partial_instantiation)
-    {
-      /* If this is a partial instantiation, then we can't instantiate
-        the type; there's no telling whether or not one of the
-        template parameters might eventually be instantiated to some
-        value that results in a specialization being used.  We do
-        mark the type as complete so that, for example, declaring one
-        of its members to be a friend will not be rejected.  */
-      TYPE_SIZE (type) = integer_zero_node;
-      goto end;
-    }
-
-  TYPE_BEING_DEFINED (type) = 1;
-
-  if (! push_tinst_level (type))
-    goto end;
-
-  maybe_push_to_top_level (uses_template_parms (type));
-  pushclass (type, 0);
-
-  /* We must copy the arguments to the permanent obstack since
-     during the tsubst'ing below they may wind up in the
-     DECL_TI_ARGS of some instantiated member template.  */
-  args = copy_to_permanent (args);
-
   if (flag_external_templates)
     {
       if (flag_alt_external_templates)
@@ -4608,18 +4636,10 @@ instantiate_class_template (type)
   TYPE_ALIGN (type) = TYPE_ALIGN (pattern);
   TYPE_FOR_JAVA (type) = TYPE_FOR_JAVA (pattern); /* For libjava's JArray<T> */
 
-  /* If this is a partial instantiation, don't tsubst anything.  We will
-     only use this type for implicit typename, so the actual contents don't
-     matter.  All that matters is whether a particular name is a type.  */
-  if (is_partial_instantiation)
-    {
-      TYPE_BINFO_BASETYPES (type) = TYPE_BINFO_BASETYPES (pattern);
-      TYPE_FIELDS (type) = TYPE_FIELDS (pattern);
-      TYPE_METHODS (type) = TYPE_METHODS (pattern);
-      CLASSTYPE_TAGS (type) = CLASSTYPE_TAGS (pattern);
-      TYPE_SIZE (type) = integer_zero_node;
-      goto done_with_instantiation;
-    }
+  /* We must copy the arguments to the permanent obstack since
+     during the tsubst'ing below they may wind up in the
+     DECL_TI_ARGS of some instantiated member template.  */
+  args = copy_to_permanent (args);
 
   {
     tree binfo = TYPE_BINFO (type);
@@ -4850,10 +4870,7 @@ instantiate_class_template (type)
   TYPE_BEING_DEFINED (type) = 0;
   repo_template_used (type);
 
- done_with_instantiation:
-  TYPE_BEING_DEFINED (type) = 0;
   popclass (0);
-
   pop_from_top_level ();
   pop_tinst_level ();
 
@@ -5382,9 +5399,7 @@ tsubst_decl (t, args, type, in_decl)
          = tsubst_aggr_type (DECL_CONTEXT (t), args, t, /*entering_scope=*/1);
        DECL_CLASS_CONTEXT (r) = ctx;
 
-       if (member && !strncmp (OPERATOR_TYPENAME_FORMAT,
-                               IDENTIFIER_POINTER (DECL_NAME (r)),
-                               sizeof (OPERATOR_TYPENAME_FORMAT) - 1))
+       if (member && IDENTIFIER_TYPENAME_P (DECL_NAME (r)))
          /* Type-conversion operator.  Reconstruct the name, in
             case it's the name of one of the template's parameters.  */
          DECL_NAME (r) = build_typename_overload (TREE_TYPE (type));
index b1278dcbb1d47e1e9e2724236c27c997b858ab6d..4bd997df447406ee7ad5f27fa0d267ade4e49ab8 100644 (file)
@@ -3,7 +3,7 @@
    building RTL.  These routines are used both during actual parsing
    and during the instantiation of template functions. 
 
-   Copyright (C) 1998 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999 Free Software Foundation, Inc.
    Written by Mark Mitchell (mmitchell@usa.net) based on code found
    formerly in parse.y and pt.c.  
 
@@ -1222,10 +1222,58 @@ begin_class_definition (t)
      implicit typename, a TYPENAME_TYPE with a type.  */
   if (TREE_CODE (t) == TYPENAME_TYPE)
     t = TREE_TYPE (t);
+  
+  /* If we generated a partial instantiation of this type, but now
+     we're seeing a real definition, we're actually looking at a
+     partial specialization.  Consider:
+
+       template <class T, class U>
+       struct Y {};
+
+       template <class T>
+       struct X {};
+
+       template <class T, class U>
+       void f()
+       {
+        typename X<Y<T, U> >::A a;
+       }
+
+       template <class T, class U>
+       struct X<Y<T, U> >
+       {
+       };
+
+     We have to undo the effects of the previous partial
+     instantiation.  */
+  if (PARTIAL_INSTANTIATION_P (t))
+    {
+      if (!pedantic) 
+       {
+         /* Unfortunately, when we're not in pedantic mode, we
+            attempt to actually fill in some of the fields of the
+            partial instantiation, in order to support the implicit
+            typename extension.  Clear those fields now, in
+            preparation for the definition here.  The fields cleared
+            here must match those set in instantiate_class_template.
+            Look for a comment mentioning begin_class_definition
+            there.  */
+         TYPE_BINFO_BASETYPES (t) = NULL_TREE;
+         TYPE_FIELDS (t) = NULL_TREE;
+         TYPE_METHODS (t) = NULL_TREE;
+         CLASSTYPE_TAGS (t) = NULL_TREE;
+         TYPE_SIZE (t) = NULL_TREE;
+       }
 
-  if (TYPE_SIZE (t))
+      /* This isn't a partial instantiation any more.  */
+      PARTIAL_INSTANTIATION_P (t) = 0;
+    }
+  /* If this type was already complete, and we see another definition,
+     that's an error.  */
+  else if (TYPE_SIZE (t))
     duplicate_tag_error (t);
-  if (TYPE_SIZE (t) || TYPE_BEING_DEFINED (t))
+
+  if (TYPE_BEING_DEFINED (t))
     {
       t = make_lang_type (TREE_CODE (t));
       pushtag (TYPE_IDENTIFIER (t), t, 0);
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend39.C b/gcc/testsuite/g++.old-deja/g++.pt/friend39.C
new file mode 100644 (file)
index 0000000..836c830
--- /dev/null
@@ -0,0 +1,23 @@
+// Build don't link:
+
+template <class T>
+struct S;
+
+template <class T>
+class C
+{
+  friend void S<T>::f();
+  
+  int i;
+};
+
+template <class T>
+struct S
+{
+  void f() {
+    C<T> c;
+    c.i = 3;
+  }
+};
+
+template void S<int>::f();
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec27.C b/gcc/testsuite/g++.old-deja/g++.pt/spec27.C
new file mode 100644 (file)
index 0000000..63aae4c
--- /dev/null
@@ -0,0 +1,18 @@
+// Build don't link:
+
+template <class T, class U>
+struct Y {};
+
+template <class T>
+struct X {};
+
+template <class T, class U>
+void f()
+{
+  typename X<Y<T, U> >::A a;
+}
+
+template <class T, class U>
+struct X<Y<T, U> >
+{
+};