cp-tree.h (ANON_UNION_TYPE_P): Robustify.
authorMark Mitchell <mark@markmitchell.com>
Fri, 5 Mar 1999 16:38:54 +0000 (16:38 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Fri, 5 Mar 1999 16:38:54 +0000 (16:38 +0000)
* cp-tree.h (ANON_UNION_TYPE_P): Robustify.
* decl.c (make_typename_type): Don't issue an error if an
immediate lookup fails; it migt be resolved later.
* friend.c (is_friend): Add comment.
* search.c (breadth_first_search): Add POSTFN and DATA
parameters.  Tidy.  All callers changed.
(lookup_field_queue_p): New function.
(lookup_field_r): Likewise.
(lookup_field_post): Likewise.
(lookup_field): Use them, via breadth_first_search, instead of
duplicating logic.
(compute_access): Robustify.
(lookup_fnfield_info): New structure.

From-SVN: r25607

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/friend.c
gcc/cp/search.c
gcc/testsuite/g++.old-deja/g++.other/crash7.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/typename15.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/typename16.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/typename17.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/typename3.C

index 2c51faa7fac8afe8db51d8e9464a537b7888598c..2a493ddb1d2e08432f679a710610fec36daf08db 100644 (file)
@@ -1,3 +1,19 @@
+1999-03-05  Mark Mitchell  <mark@markmitchell.com>
+
+       * cp-tree.h (ANON_UNION_TYPE_P): Robustify.
+       * decl.c (make_typename_type): Don't issue an error if an
+       immediate lookup fails; it migt be resolved later.
+       * friend.c (is_friend): Add comment.
+       * search.c (breadth_first_search): Add POSTFN and DATA
+       parameters.  Tidy.  All callers changed.
+       (lookup_field_queue_p): New function.
+       (lookup_field_r): Likewise.
+       (lookup_field_post): Likewise.
+       (lookup_field): Use them, via breadth_first_search, instead of
+       duplicating logic.
+       (compute_access): Robustify.
+       (lookup_fnfield_info): New structure.
+       
 1999-03-05  Jason Merrill  <jason@yorick.cygnus.com>
 
        * pt.c (tsubst, case ARRAY_REF): Use tsubst_expr again.
index 935f8f9ff4aa41243011df35ab26befb639e4db0..ab33fad0e9da97625de864ce945c8ca82265552a 100644 (file)
@@ -1708,9 +1708,12 @@ extern int flag_new_for_scope;
 
 #define ANON_UNION_P(NODE) (DECL_NAME (NODE) == 0)
 
-/* Nonzero if TYPE is an anonymous union type.  */
+/* Nonzero if TYPE is an anonymous union type.  We're careful
+   accessing TYPE_IDENTIFIER because some built-in types, like
+   pointer-to-member types, do not have TYPE_NAME.  */
 #define ANON_UNION_TYPE_P(TYPE) \
   (TREE_CODE (TYPE) == UNION_TYPE \
+   && TYPE_NAME (TYPE) \
    && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TYPE)))
 
 #define UNKNOWN_TYPE LANG_TYPE
index f7580bac4e862d3e3f27992eba3c13c0b27c132e..cf7ce61463509e2862d7d3553b720a700267eb7a 100644 (file)
@@ -5192,34 +5192,29 @@ make_typename_type (context, name)
          if (IS_AGGR_TYPE (context))
            t = lookup_field (context, name, 0, 0);
          else
-           t = NULL_TREE;
-
-         if (t == NULL_TREE || TREE_CODE (t) != TEMPLATE_DECL
-             || TREE_CODE (DECL_RESULT (t)) != TYPE_DECL)
            {
              cp_error ("no class template named `%#T' in `%#T'",
                        name, context);
              return error_mark_node;
            }
 
-         return lookup_template_class (t, TREE_OPERAND (fullname, 1),
-                                       NULL_TREE, context, 
-                                       /*entering_scope=*/0);
+         if (t && DECL_CLASS_TEMPLATE_P (t))
+           return lookup_template_class (t, TREE_OPERAND (fullname, 1),
+                                         NULL_TREE, context, 
+                                         /*entering_scope=*/0);
        }
       else
        {
          if (IS_AGGR_TYPE (context))
            t = lookup_field (context, name, 0, 1);
          else
-           t = NULL_TREE;
-
-         if (t == NULL_TREE)
            {
              cp_error ("no type named `%#T' in `%#T'", name, context);
              return error_mark_node;
            }
 
-         return TREE_TYPE (t);
+         if (t)
+           return TREE_TYPE (t);
        }
     }
   
index c26d6956c116175c2ec795d85de91ef9f2c13f49..8bcdcc40a2eb34b71540af9a29968d8b6688e883 100644 (file)
@@ -32,6 +32,8 @@ static void add_friends PROTO((tree, tree, tree));
 
 /* Friend data structures are described in cp-tree.h.  */
 
+/* Returns non-zero if SUPPLICANT is a friend of TYPE.  */
+
 int
 is_friend (type, supplicant)
      tree type, supplicant;
index 3b88c400197b688fbdf84cb99172f2c8810768e8..907c9d34c592f0c2ad0a399ca0fe7a862a721a1c 100644 (file)
@@ -110,17 +110,21 @@ static void dfs_get_vbase_types PROTO((tree));
 static void dfs_pushdecls PROTO((tree));
 static void dfs_compress_decls PROTO((tree));
 static void dfs_unuse_fields PROTO((tree));
-static tree add_conversions PROTO((tree));
+static tree add_conversions PROTO((tree, void *));
 static tree get_virtuals_named_this PROTO((tree));
-static tree get_virtual_destructor PROTO((tree));
-static int tree_has_any_destructor_p PROTO((tree));
+static tree get_virtual_destructor PROTO((tree, void *));
+static int tree_has_any_destructor_p PROTO((tree, void *));
 static int covariant_return_p PROTO((tree, tree));
 static struct search_level *push_search_level
        PROTO((struct stack_level *, struct obstack *));
 static struct search_level *pop_search_level
        PROTO((struct stack_level *));
 static tree breadth_first_search
-       PROTO((tree, tree (*) (tree), int (*) (tree)));
+       PROTO((tree, tree (*) (tree, void *), int (*) (tree, void *),
+              void (*) (tree *, tree *, void *), void *));
+static int lookup_field_queue_p PROTO((tree, void *));
+static tree lookup_field_r PROTO((tree, void *));
+static void lookup_field_post PROTO((tree *, tree *, void *));
 
 static tree vbase_types;
 static tree vbase_decl_ptr_intermediate, vbase_decl_ptr;
@@ -673,7 +677,7 @@ compute_access (basetype_path, field)
     {
       /* Are we (or an enclosing scope) friends with the class that has
          FIELD? */
-      if (is_friend (context, previous_scope))
+      if (TYPE_P (context) && is_friend (context, previous_scope))
        PUBLIC_RETURN;
 
       /* If it's private, it's private, you letch.  */
@@ -689,6 +693,7 @@ compute_access (basetype_path, field)
        {
          if (current_class_type
              && (static_mem || DECL_CONSTRUCTOR_P (field))
+             && TYPE_P (context)
              && ACCESSIBLY_DERIVED_FROM_P (context, current_class_type))
            PUBLIC_RETURN;
          else
@@ -750,7 +755,7 @@ compute_access (basetype_path, field)
 
   if (access == access_default_node)
     {
-      if (is_friend (context, previous_scope))
+      if (TYPE_P (context) && is_friend (context, previous_scope))
        access = access_public_node;
       else if (TREE_PRIVATE (field))
        access = access_private_node;
@@ -849,6 +854,270 @@ lookup_fnfields_here (type, name)
   return -1;
 }
 
+struct lookup_field_info {
+  /* The name of the field for which we're looking.  */
+  tree name;
+  /* If non-NULL, the current result of the lookup.  */
+  tree rval;
+  /* The path to RVAL.  */
+  tree rval_binfo;
+  /* If non-NULL, a list of the possible candidates.  */
+  tree ambiguous;
+  /* The access computed for RVAL.  */
+  tree access;
+  /* If non-zero, we must check access.  */
+  int protect;
+  /* If non-zero, we are looking for types, not data members.  */
+  int want_type;
+  /* If something went wrong, a message indicating what.  */
+  char *errstr;
+};
+
+/* Returns non-zero if BINFO is not hidden by the value found by the
+   lookup so far.  If BINFO is hidden, then there's no need to look in
+   it.  DATA is really a struct lookup_field_info.  Called from
+   lookup_field via breadth_first_search.  */
+
+static int
+lookup_field_queue_p (binfo, data)
+     tree binfo;
+     void *data;
+{
+  struct lookup_field_info *lfi = (struct lookup_field_info *) data;
+  
+  return !(lfi->rval_binfo && hides (lfi->rval_binfo, binfo));
+}
+
+/* DATA is really a struct lookup_field_info.  Look for a field with
+   the name indicated there in BINFO.  If this function returns a
+   non-NULL value it is the result of the lookup.  Called from
+   lookup_field via breadth_first_search.  */
+
+static tree
+lookup_field_r (binfo, data)
+     tree binfo;
+     void *data;
+{
+  struct lookup_field_info *lfi = (struct lookup_field_info *) data;
+  tree type = BINFO_TYPE (binfo);
+  tree nval;
+  int idx;
+
+  /* See if the field is present in TYPE.  */
+  nval = lookup_field_1 (type, lfi->name);
+  if (!nval)
+    idx = lookup_fnfields_here (type, lfi->name);
+
+  /* If the data member wasn't present, then there's nothing further
+     to do for this type.  */
+  if (!nval && idx < 0)
+    return NULL_TREE;
+
+  /* If the lookup already found a match, and the new value doesn't
+     hide the old one, we might have an ambiguity.  */
+  if (lfi->rval_binfo && !hides (binfo, lfi->rval_binfo))
+    {
+      if (nval && nval == lfi->rval && SHARED_MEMBER_P (nval))
+       /* The two things are really the same.  */
+       ;
+      else if (hides (lfi->rval_binfo, binfo))
+       /* The previous value hides the new one.  */
+       ;
+      else
+       {
+         /* We have a real ambiguity.  We keep a chain of all the
+            candidates.  */
+         if (!lfi->ambiguous && lfi->rval)
+           /* This is the first time we noticed an ambiguity.  Add
+              what we previously thought was a reasonable candidate
+              to the list.  */
+           lfi->ambiguous = scratch_tree_cons (NULL_TREE, lfi->rval,
+                                               NULL_TREE);
+         /* If NVAL is NULL here, that means that we found a
+            function, not a data member.  Pick a representative
+            function, from the overload set, for use in error
+            messages. */
+         if (!nval)
+           nval = OVL_CURRENT (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC
+                                             (type), idx));
+             
+         /* Add the new value.  */
+         lfi->ambiguous = scratch_tree_cons (NULL_TREE, nval, 
+                                             lfi->ambiguous);
+         lfi->errstr = "request for member `%D' is ambiguous";
+       }
+    }
+  else
+    {
+      /* The new lookup is the best we've got so far.  Verify that
+        it's the kind of thing we're looking for.  */
+      if (nval)
+       {
+         if (lfi->want_type && TREE_CODE (nval) != TYPE_DECL)
+           {
+             nval = purpose_member (lfi->name, CLASSTYPE_TAGS (type));
+             if (nval)
+               nval = TYPE_MAIN_DECL (TREE_VALUE (nval));
+           }
+         else if (!lfi->want_type && TREE_CODE (nval) == TYPE_DECL
+                  && lookup_fnfields_here (type, lfi->name) >= 0)
+           /* The type declaration is actually hidden by the
+              function declaration.  */
+           nval = NULL_TREE;
+       }
+
+      if (nval)
+       {
+         /* The lookup found a data member.  */
+         lfi->rval = nval;
+         if (lfi->protect)
+           lfi->access = compute_access (binfo, nval);
+         /* If the thing we're looking for is a virtual base class,
+            then we know we've got what we want at this point;
+            there's no way to get an ambiguity.  */
+         if (VBASE_NAME_P (lfi->name))
+           return nval;
+       }
+      else
+       /* The lookup found a function member.  This lookup hides
+          whatever was there before, so even though we're not
+          interested in this value we keep track of the way in
+          which we found the function.  Subsequent lookups
+          shouldn't find a data member if it is hidden by this
+          function member.  */
+       lfi->rval = NULL_TREE;
+
+      lfi->rval_binfo = binfo;
+    }
+
+  return 0;
+}
+
+/* Check to see if the result of the field lookup (as indicated by
+   DATA, which is really a struct field_info) has any access other
+   than that we previously computed.  SEARCH_HEAD and SEARCH_TAIL
+   bound the path taken to find the result.  Called from lookup_field
+   via breadth_first_search.  */
+
+static void
+lookup_field_post (search_head, search_tail, data)
+     tree *search_head;
+     tree *search_tail;
+     void *data;
+{
+  struct lookup_field_info *lfi = (struct lookup_field_info *) data;
+  tree rval = lfi->rval;
+  tree own_access = access_default_node;
+  tree *tp;
+
+  /* If we didn't find anything, or we found ambiguous function
+     declarations, but no data members, just return.  */
+  if (!rval)
+    {
+      lfi->errstr = 0;
+      return;
+    }
+
+  /* If we've already hit a snag, we're done.  */
+  if (lfi->errstr)
+    return;
+
+  /* Check accessibility.  */
+  if (lfi->protect)
+    {
+      /* If is possible for one of the derived types on the path to
+        have defined special access for this field.  Look for such
+        declarations and report an error if a conflict is found.  */
+      if (DECL_LANG_SPECIFIC (rval) && DECL_ACCESS (rval))
+       for (tp = search_head; tp < search_tail; ++tp)
+         {
+           tree new_v = NULL_TREE;
+       
+           if (lfi->access != access_default_node)
+             new_v = compute_access (*tp, lfi->rval);
+           if (lfi->access != access_default_node && new_v != lfi->access)
+             {
+               lfi->errstr = "conflicting access to member `%D'";
+               lfi->access = access_default_node;
+               return; 
+             }
+           own_access = new_v;
+           tp++;
+         }
+  
+      /* Check to see that access to the member is allowed.  */
+      if (own_access == access_private_node)
+       lfi->errstr = "member `%D' declared private";
+      else if (own_access == access_protected_node)
+       lfi->errstr = "member `%D' declared protected";
+      else if (lfi->access == access_private_node)
+       lfi->errstr = TREE_PRIVATE (lfi->rval)
+         ? "member `%D' is private"
+         : "member `%D' is from private base class";
+      else if (lfi->access== access_protected_node)
+       lfi->errstr = TREE_PROTECTED (rval)
+         ? "member `%D' is protected"
+         : "member `%D' is from protected base class";
+    }
+
+  /* The implicit typename extension allows us to find type
+     declarations in dependent base clases.  It also handles
+     out-of-class definitions where the enclosing class is a
+     template.  For example:
+
+       template <class T> struct S { struct I { void f(); }; };
+       template <class T> void S<T>::I::f() {}
+
+     will come through here to handle `S<T>::I'.  The bottom line is
+     that while searching for the field, we will have happily
+     descended into dependent base classes, and we must now figure out
+     what to do about it.  */
+
+  /* If we're not in a template, or the search terminated in the
+     current class, then there's no problem.  */
+  if (!processing_template_decl 
+      || currently_open_class (BINFO_TYPE (lfi->rval_binfo)))
+    return;
+  
+  /* We need to return a member template class so we can define partial
+     specializations.  Is there a better way?  */
+  if (DECL_CLASS_TEMPLATE_P (rval))
+    return;
+
+  /* Walk the path to the base in which the search finally suceeded,
+     checking for dependent bases along the way.  */
+  for (tp = (currently_open_class (BINFO_TYPE (*search_head)))
+        ? search_head + 1 : search_head; 
+       tp < search_tail; 
+       ++tp)
+    {
+      if (!uses_template_parms (BINFO_TYPE (*tp)))
+       continue;
+
+      if (TREE_CODE (rval) != TYPE_DECL)
+       {
+         /* The thing we're looking for isn't a type, so the implicit
+            typename extension doesn't apply, so we just pretend we
+            didn't find anything.  */
+         lfi->rval = NULL_TREE;
+         return;
+       }
+
+      /* We've passed a dependent base on our way to finding the
+        type.  So, create an implicit typename type.  The appropriate
+         context for the typename is *TP.  But, there's a small catch;
+         the base classes for a partial instantiation are not correct,
+        because we don't tsubst into them when we do the partial
+        instantiation.  So, we just use the context of the current
+        class type.  */
+      lfi->rval = TYPE_STUB_DECL (build_typename_type 
+                                 (BINFO_TYPE (*search_head), 
+                                  lfi->name, lfi->name, 
+                                  TREE_TYPE (rval)));
+      return;
+    }
+}
+
 /* Look for a field named NAME in an inheritance lattice dominated by
    XBASETYPE.  PROTECT is zero if we can avoid computing access
    information, otherwise it is 1.  WANT_TYPE is 1 when we should only
@@ -863,14 +1132,9 @@ lookup_field (xbasetype, name, protect, want_type)
      register tree xbasetype, name;
      int protect, want_type;
 {
-  int head = 0, tail = 0;
-  tree rval, rval_binfo = NULL_TREE, rval_binfo_h = NULL_TREE;
-  tree type = NULL_TREE, basetype_chain, basetype_path = NULL_TREE;
-  tree this_v = access_default_node;
-  tree entry, binfo, binfo_h;
-  tree own_access = access_default_node;
-  int vbase_name_p = VBASE_NAME_P (name);
-  tree ambiguous = NULL_TREE;
+  tree rval, rval_binfo = NULL_TREE;
+  tree type = NULL_TREE, basetype_path = NULL_TREE;
+  struct lookup_field_info lfi;
 
   /* rval_binfo is the binfo associated with the found member, note,
      this can be set with useful information, even when rval is not
@@ -888,6 +1152,8 @@ lookup_field (xbasetype, name, protect, want_type)
 
   char *errstr = 0;
 
+  bzero (&lfi, sizeof (lfi));
+
 #if 0
   /* We cannot search for constructor/destructor names like this.  */
   /* This can't go here, but where should it go?  */
@@ -927,306 +1193,31 @@ lookup_field (xbasetype, name, protect, want_type)
   n_calls_lookup_field++;
 #endif /* GATHER_STATISTICS */
 
-  rval = lookup_field_1 (type, name);
-
-  if (rval || lookup_fnfields_here (type, name) >= 0)
-    {
-      if (rval)
-       {
-         if (want_type)
-           {
-             if (TREE_CODE (rval) != TYPE_DECL)
-               {
-                 rval = purpose_member (name, CLASSTYPE_TAGS (type));
-                 if (rval)
-                   rval = TYPE_MAIN_DECL (TREE_VALUE (rval));
-               }
-           }
-         else
-           {
-             if (TREE_CODE (rval) == TYPE_DECL
-                 && lookup_fnfields_here (type, name) >= 0)
-               rval = NULL_TREE;
-           }
-       }
-
-      if (protect && rval)
-       {
-         if (TREE_PRIVATE (rval) | TREE_PROTECTED (rval))
-           this_v = compute_access (basetype_path, rval);
-         if (TREE_CODE (rval) == CONST_DECL)
-           {
-             if (this_v == access_private_node)
-               errstr = "enum `%D' is a private value of class `%T'";
-             else if (this_v == access_protected_node)
-               errstr = "enum `%D' is a protected value of class `%T'";
-           }
-         else
-           {
-             if (this_v == access_private_node)
-               errstr = "member `%D' is a private member of class `%T'";
-             else if (this_v == access_protected_node)
-               errstr = "member `%D' is a protected member of class `%T'";
-           }
-       }
-
-      rval_binfo = basetype_path;
-      goto out;
-    }
-
-  basetype_chain = build_expr_list (NULL_TREE, basetype_path);
-
-  /* The ambiguity check relies upon breadth first searching.  */
-
-  search_stack = push_search_level (search_stack, &search_obstack);
-  binfo = basetype_path;
-  binfo_h = binfo;
-
-  while (1)
-    {
-      tree binfos = BINFO_BASETYPES (binfo);
-      int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-      tree nval;
-      int idx = -1;
-
-      /* Process and/or queue base types.  */
-      for (i = 0; i < n_baselinks; i++)
-       {
-         tree base_binfo = TREE_VEC_ELT (binfos, i);
-         if (BINFO_FIELDS_MARKED (base_binfo) == 0)
-           {
-             tree btypes;
-
-             SET_BINFO_FIELDS_MARKED (base_binfo);
-             btypes = scratch_tree_cons (NULL_TREE, base_binfo, basetype_chain);
-             if (TREE_VIA_VIRTUAL (base_binfo))
-               btypes = scratch_tree_cons (NULL_TREE,
-                                   TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))),
-                                   btypes);
-             else
-               btypes = scratch_tree_cons (NULL_TREE,
-                                   TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
-                                   btypes);
-             obstack_ptr_grow (&search_obstack, btypes);
-             tail += 1;
-             if (tail >= search_stack->limit)
-               my_friendly_abort (98);
-           }
-       }
-
-      /* Process head of queue, if one exists.  */
-      if (head >= tail)
-       break;
-
-      basetype_chain = search_stack->first[head++];
-      binfo_h = TREE_VALUE (basetype_chain);
-      basetype_chain = TREE_CHAIN (basetype_chain);
-      basetype_path = TREE_VALUE (basetype_chain);
-      if (TREE_CHAIN (basetype_chain))
-       my_friendly_assert
-         ((BINFO_INHERITANCE_CHAIN (basetype_path)
-           == TREE_VALUE (TREE_CHAIN (basetype_chain)))
-          /* We only approximate base info for partial instantiations.  */ 
-          || current_template_parms,
-          980827);
-      else
-       my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path)
-                           == NULL_TREE, 980827);
-
-      binfo = basetype_path;
-      type = BINFO_TYPE (binfo);
-
-      /* See if we can find NAME in TYPE.  If RVAL is nonzero,
-        and we do find NAME in TYPE, verify that such a second
-        sighting is in fact valid.  */
-
-      nval = lookup_field_1 (type, name);
-
-      if (nval || (idx = lookup_fnfields_here (type, name)) >= 0)
-       {
-         if (nval && nval == rval && SHARED_MEMBER_P (nval))
-           {
-             /* This is ok, the member found is the same [class.ambig] */
-           }
-         else if (rval_binfo && hides (rval_binfo_h, binfo_h))
-           {
-             /* This is ok, the member found is in rval_binfo, not
-                here (binfo).  */
-           }
-         else if (rval_binfo==NULL_TREE || hides (binfo_h, rval_binfo_h))
-           {
-             /* This is ok, the member found is here (binfo), not in
-                rval_binfo.  */
-             if (nval)
-               {
-                 rval = nval;
-                 if (protect)
-                   this_v = compute_access (basetype_path, rval);
-                 /* These may look ambiguous, but they really are not.  */
-                 if (vbase_name_p)
-                   break;
-               }
-             else
-               {
-                 /* Undo finding it before, as something else hides it.  */
-                 rval = NULL_TREE;
-               }
-             rval_binfo = binfo;
-             rval_binfo_h = binfo_h;
-           }
-         else
-           {
-             /* This is ambiguous. Remember it. */
-             if (! ambiguous)
-               {
-                 errstr = "request for member `%D' is ambiguous";
-                 protect += 2;
-                 if (rval)
-                   ambiguous = scratch_tree_cons (NULL_TREE, rval, ambiguous);
-               }
-             if (! nval)
-               {
-                 nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
-                 nval = OVL_CURRENT (nval);
-               }
-              ambiguous = scratch_tree_cons (NULL_TREE, nval, ambiguous);
-           }
-       }
-    }
-  {
-    tree *tp = search_stack->first;
-    tree *search_tail = tp + tail;
-
-    if (rval_binfo)
-      {
-       type = BINFO_TYPE (rval_binfo);
-
-       if (rval)
-         {
-           if (want_type)
-             {
-               if (TREE_CODE (rval) != TYPE_DECL)
-                 {
-                   rval = purpose_member (name, CLASSTYPE_TAGS (type));
-                   if (rval)
-                     rval = TYPE_MAIN_DECL (TREE_VALUE (rval));
-                 }
-             }
-           else
-             {
-               if (TREE_CODE (rval) == TYPE_DECL
-                   && lookup_fnfields_here (type, name) >= 0)
-                 rval = NULL_TREE;
-             }
-         }
-      }
-
-    if (rval == NULL_TREE)
-      errstr = 0;
-
-    /* If this FIELD_DECL defines its own access level, deal with that.  */
-    if (rval && errstr == 0
-       && (protect & 1)
-       && DECL_LANG_SPECIFIC (rval)
-       && DECL_ACCESS (rval))
-      {
-       while (tp < search_tail)
-         {
-           /* If is possible for one of the derived types on the path to
-              have defined special access for this field.  Look for such
-              declarations and report an error if a conflict is found.  */
-           tree new_v = NULL_TREE;
-
-           if (this_v != access_default_node)
-             new_v = compute_access (TREE_VALUE (TREE_CHAIN (*tp)), rval);
-           if (this_v != access_default_node && new_v != this_v)
-             {
-               errstr = "conflicting access to member `%D'";
-               this_v = access_default_node;
-             }
-           own_access = new_v;
-           CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
-           tp += 1;
-         }
-      }
-    else
-      {
-       while (tp < search_tail)
-         {
-           CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
-           tp += 1;
-         }
-      }
-  }
-  search_stack = pop_search_level (search_stack);
-
-  if (errstr == 0)
-    {
-      if (own_access == access_private_node)
-       errstr = "member `%D' declared private";
-      else if (own_access == access_protected_node)
-       errstr = "member `%D' declared protected";
-      else if (this_v == access_private_node)
-       errstr = TREE_PRIVATE (rval)
-         ? "member `%D' is private"
-           : "member `%D' is from private base class";
-      else if (this_v == access_protected_node)
-       errstr = TREE_PROTECTED (rval)
-         ? "member `%D' is protected"
-           : "member `%D' is from protected base class";
-    }
-
- out:
-  if (protect == 2)
-    {
-      /* If we are not interested in ambiguities, don't report them,
-        just return NULL_TREE.  */
-      rval = NULL_TREE;
-      protect = 0;
-    }
+  lfi.name = name;
+  lfi.protect = protect;
+  lfi.want_type = want_type;
+  lfi.access = access_default_node;
+  breadth_first_search (basetype_path, &lookup_field_r, 
+                       &lookup_field_queue_p, &lookup_field_post, &lfi);
+  rval = lfi.rval;
+  rval_binfo = lfi.rval_binfo;
+  if (rval_binfo)
+    type = BINFO_TYPE (rval_binfo);
+  errstr = lfi.errstr;
+
+  /* If we are not interested in ambiguities, don't report them;
+     just return NULL_TREE.  */
+  if (!protect && lfi.ambiguous)
+    return NULL_TREE;
 
   if (errstr && protect)
     {
       cp_error (errstr, name, type);
-      if (ambiguous)
-        print_candidates (ambiguous);
+      if (lfi.ambiguous)
+        print_candidates (lfi.ambiguous);
       rval = error_mark_node;
     }
 
-  /* Do implicit typename stuff.  This code also handles out-of-class
-     definitions of nested classes whose enclosing class is a
-     template.  For example:
-    
-       template <class T> struct S { struct I { void f(); }; };
-       template <class T> void S<T>::I::f() {}
-
-     will come through here to handle `S<T>::I'.  */
-  if (rval && processing_template_decl
-      && ! currently_open_class (BINFO_TYPE (rval_binfo))
-      && uses_template_parms (type))
-    {
-      /* We need to return a member template class so we can define partial
-        specializations.  Is there a better way?  */
-      if (DECL_CLASS_TEMPLATE_P (rval))
-       return rval;
-
-      /* Don't return a non-type.  Actually, we ought to return something
-        so lookup_name_real can give a warning.  */
-      if (TREE_CODE (rval) != TYPE_DECL)
-       return NULL_TREE;
-
-      binfo = rval_binfo;
-      for (; ; binfo = BINFO_INHERITANCE_CHAIN (binfo))
-       if (BINFO_INHERITANCE_CHAIN (binfo) == NULL_TREE
-           || (BINFO_TYPE (BINFO_INHERITANCE_CHAIN (binfo))
-               == current_class_type))
-         break;
-
-      entry = build_typename_type (BINFO_TYPE (binfo), name,  name, 
-                                  TREE_TYPE (rval));
-      return TYPE_STUB_DECL (entry);
-    }
-
   return rval;
 }
 
@@ -1625,19 +1616,29 @@ lookup_member (xbasetype, name, protect, want_type)
 /* Search a multiple inheritance hierarchy by breadth-first search.
 
    BINFO is an aggregate type, possibly in a multiple-inheritance hierarchy.
-   TESTFN is a function, which, if true, means that our condition has been met,
-   and its return value should be returned.
+   TESTFN is a function, which, if true, means that our condition has
+   been met, and its return value should be returned.
    QFN, if non-NULL, is a predicate dictating whether the type should
-   even be queued.  */
+   even be queued.  
+   POSTFN, if non-NULL, is a function to call before returning.  It is
+   passed an array whose first element is the most derived type in the
+   chain, and whose last element is the least derived type. 
+   
+   All of the functions are also passed the DATA, which they may use
+   as they see fit.  */
 
 static tree
-breadth_first_search (binfo, testfn, qfn)
+breadth_first_search (binfo, testfn, qfn, postfn, data)
      tree binfo;
-     tree (*testfn) PROTO((tree));
-     int (*qfn) PROTO((tree));
+     tree (*testfn) PROTO((tree, void *));
+     int (*qfn) PROTO((tree, void *));
+     void (*postfn) PROTO((tree *, tree *, void *));
+     void *data;
 {
   int head = 0, tail = 0;
   tree rval = NULL_TREE;
+  tree *tp;
+  tree *search_tail;
 
   search_stack = push_search_level (search_stack, &search_obstack);
 
@@ -1645,19 +1646,32 @@ breadth_first_search (binfo, testfn, qfn)
   obstack_ptr_grow (&search_obstack, binfo);
   ++tail;
 
-  while (1)
+  while (head < tail)
     {
-      tree binfos = BINFO_BASETYPES (binfo);
-      int n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+      tree binfos;
+      int n_baselinks;
       int i;
 
-      /* Process and/or queue base types.  */
+      /* Pull the next type out of the queue.  */
+      binfo = search_stack->first[head++];
+
+      /* If this is the one we're looking for, we're done.  */
+      rval = (*testfn) (binfo, data);
+      if (rval)
+       break;
+
+      /* Queue up the base types.  */
+      binfos = BINFO_BASETYPES (binfo);
+      n_baselinks = binfos ? TREE_VEC_LENGTH (binfos): 0;
       for (i = 0; i < n_baselinks; i++)
        {
          tree base_binfo = TREE_VEC_ELT (binfos, i);
 
+         if (TREE_VIA_VIRTUAL (base_binfo))
+           base_binfo = TYPE_BINFO (BINFO_TYPE (base_binfo));
+
          if (BINFO_MARKED (base_binfo) == 0
-             && (qfn == 0 || (*qfn) (base_binfo)))
+             && (qfn == 0 || (*qfn) (base_binfo, data)))
            {
              SET_BINFO_MARKED (base_binfo);
              obstack_ptr_grow (&search_obstack, base_binfo);
@@ -1666,26 +1680,19 @@ breadth_first_search (binfo, testfn, qfn)
                my_friendly_abort (100);
            }
        }
-      /* Process head of queue, if one exists.  */
-      if (head >= tail)
-       {
-         rval = 0;
-         break;
-       }
+    }
 
-      binfo = search_stack->first[head++];
-      if ((rval = (*testfn) (binfo)))
-       break;
+  tp = search_stack->first;
+  search_tail = tp + tail;
+  
+  if (postfn)
+    (*postfn) (tp, search_tail, data);
+  
+  while (tp < search_tail)
+    {
+      tree binfo = *tp++;
+      CLEAR_BINFO_MARKED (binfo);
     }
-  {
-    tree *tp = search_stack->first;
-    tree *search_tail = tp + tail;
-    while (tp < search_tail)
-      {
-       tree binfo = *tp++;
-       CLEAR_BINFO_MARKED (binfo);
-      }
-  }
 
   search_stack = pop_search_level (search_stack);
   return rval;
@@ -1723,8 +1730,9 @@ get_virtuals_named_this (binfo)
 }
 
 static tree
-get_virtual_destructor (binfo)
+get_virtual_destructor (binfo, data)
      tree binfo;
+     void *data;
 {
   tree type = BINFO_TYPE (binfo);
   if (TYPE_HAS_DESTRUCTOR (type)
@@ -1734,8 +1742,9 @@ get_virtual_destructor (binfo)
 }
 
 static int
-tree_has_any_destructor_p (binfo)
+tree_has_any_destructor_p (binfo, data)
      tree binfo;
+     void *data;
 {
   tree type = BINFO_TYPE (binfo);
   return TYPE_NEEDS_DESTRUCTOR (type);
@@ -1824,7 +1833,7 @@ get_matching_virtual (binfo, fndecl, dtorp)
     {
       return breadth_first_search (binfo,
                                   get_virtual_destructor,
-                                  tree_has_any_destructor_p);
+                                  tree_has_any_destructor_p, 0, 0);
     }
   else
     {
@@ -3310,13 +3319,14 @@ reinit_search_statistics ()
 
 #define scratch_tree_cons expr_tree_cons
 
-static tree conversions;
 static tree
-add_conversions (binfo)
+add_conversions (binfo, data)
      tree binfo;
+     void *data;
 {
   int i;
   tree method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
+  tree *conversions = (tree *) data;
 
   for (i = 2; i < TREE_VEC_LENGTH (method_vec); ++i)
     {
@@ -3331,7 +3341,7 @@ add_conversions (binfo)
       /* Make sure we don't already have this conversion.  */
       if (! IDENTIFIER_MARKED (name))
        {
-         conversions = scratch_tree_cons (binfo, tmp, conversions);
+         *conversions = scratch_tree_cons (binfo, tmp, *conversions);
          IDENTIFIER_MARKED (name) = 1;
        }
     }
@@ -3343,11 +3353,11 @@ lookup_conversions (type)
      tree type;
 {
   tree t;
-
-  conversions = NULL_TREE;
+  tree conversions = NULL_TREE;
 
   if (TYPE_SIZE (type))
-    breadth_first_search (TYPE_BINFO (type), add_conversions, 0);
+    breadth_first_search (TYPE_BINFO (type), add_conversions,
+                         0, 0, &conversions);
 
   for (t = conversions; t; t = TREE_CHAIN (t))
     IDENTIFIER_MARKED (DECL_NAME (OVL_CURRENT (TREE_VALUE (t)))) = 0;
diff --git a/gcc/testsuite/g++.old-deja/g++.other/crash7.C b/gcc/testsuite/g++.old-deja/g++.other/crash7.C
new file mode 100644 (file)
index 0000000..c924adf
--- /dev/null
@@ -0,0 +1,11 @@
+// Build don't link:
+
+void f() 
+{
+  union {
+  private:
+    int i;
+  } u;
+
+  u.i = 3; // ERROR - private
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/typename15.C b/gcc/testsuite/g++.old-deja/g++.pt/typename15.C
new file mode 100644 (file)
index 0000000..8e26057
--- /dev/null
@@ -0,0 +1,18 @@
+// Build don't link:
+// Special g++ Options:
+
+template <class T, bool B> 
+struct R {
+  struct X {};
+};
+
+template <class T, bool B = false>
+struct S : public R <T, B> {
+};
+
+template <class T> void f() 
+{
+  S<T>::X();
+}
+
+template void f<int>();
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/typename16.C b/gcc/testsuite/g++.old-deja/g++.pt/typename16.C
new file mode 100644 (file)
index 0000000..51a8765
--- /dev/null
@@ -0,0 +1,31 @@
+// Build don't run:
+// Special g++ Options:
+
+struct B {
+  typedef int I;
+};
+
+template <class T>
+struct D1 : public B {
+};
+
+template <class T>
+struct D2 : public D1<T> {
+  I i;
+};
+
+template <>
+struct D1<int> {
+  typedef double I;
+};
+
+template <class T>
+void f(T);
+template <>
+void f(double) {}
+
+int main()
+{
+  D2<int> d2i;
+  f(d2i.i);
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/typename17.C b/gcc/testsuite/g++.old-deja/g++.pt/typename17.C
new file mode 100644 (file)
index 0000000..87b0ab3
--- /dev/null
@@ -0,0 +1,20 @@
+// Build don't link:
+
+template <class T>
+struct A
+{
+  typedef T A_Type;
+};
+
+
+template <class U>
+struct B : public A<U>
+{
+  typename B<U>::A_Type Func();
+};
+
+
+template <class U>
+typename B<U>::A_Type B<U>::Func()
+{
+}
index 0b19d54723ea6e23fae2ccac4ce039182960b02e..55d6430f2efd325a2258deff81183bea4a6e0b8c 100644 (file)
@@ -16,6 +16,6 @@ struct B : public A<U>
 
 
 template <class U>
-A<U>::A_Type B<U>::Func()
+B<U>::A_Type B<U>::Func()
 {
 }