OSDN Git Service

Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
[pf3gnuchains/gcc-fork.git] / gcc / cp / search.c
index be6cffc..8b15764 100644 (file)
@@ -1,6 +1,6 @@
 /* Breadth-first and depth-first routines for
    searching multiple-inheritance lattice for GNU C++.
-   Copyright (C) 1987, 89, 92-96, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1987, 89, 92-97, 1998 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -116,17 +116,17 @@ 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 void add_conversions PROTO((tree));
+static tree add_conversions PROTO((tree));
 static tree get_virtuals_named_this PROTO((tree));
-static tree get_virtual_destructor PROTO((tree, int));
-static int tree_has_any_destructor_p PROTO((tree, int));
+static tree get_virtual_destructor PROTO((tree));
+static int tree_has_any_destructor_p PROTO((tree));
 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 HOST_WIDE_INT breadth_first_search
-       PROTO((tree, int (*) (tree, int), int (*) (tree, int)));
+static tree breadth_first_search
+       PROTO((tree, tree (*) (tree), int (*) (tree)));
 
 static tree vbase_types;
 static tree vbase_decl_ptr_intermediate, vbase_decl_ptr;
@@ -523,7 +523,14 @@ lookup_field_1 (type, name)
          if (temp)
            return temp;
        }
-      if (DECL_NAME (field) == name)
+      if (TREE_CODE (field) == USING_DECL)
+       /* For now, we're just treating member using declarations as
+          old ARM-style access declarations.  Thus, there's no reason
+          to return a USING_DECL, and the rest of the compiler can't
+          handle it.  Once the class is defined, these are purged
+          from TYPE_FIELDS anyhow; see handle_using_decl.  */
+       ;
+      else if (DECL_NAME (field) == name)
        {
          if ((TREE_CODE(field) == VAR_DECL || TREE_CODE(field) == CONST_DECL)
              && DECL_ASSEMBLER_NAME (field) != NULL)
@@ -1178,12 +1185,28 @@ lookup_field (xbasetype, name, protect, want_type)
       rval = error_mark_node;
     }
 
-  /* Do implicit typename stuff.  */
-  if (rval && TREE_CODE (rval) == TYPE_DECL
-      && processing_template_decl
+  /* 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
@@ -1191,9 +1214,9 @@ lookup_field (xbasetype, name, protect, want_type)
                == current_class_type))
          break;
 
-      entry = make_typename_type (BINFO_TYPE (binfo), name);
-      TREE_TYPE (entry) = TREE_TYPE (rval);
-      rval = TYPE_MAIN_DECL (entry);
+      entry = build_typename_type (BINFO_TYPE (binfo), name,  name, 
+                                  TREE_TYPE (rval));
+      return TYPE_STUB_DECL (entry);
     }
 
   return rval;
@@ -1270,7 +1293,8 @@ static int
 lookup_fnfields_1 (type, name)
      tree type, name;
 {
-  register tree method_vec = CLASSTYPE_METHOD_VEC (type);
+  register tree method_vec 
+    = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
 
   if (method_vec != 0)
     {
@@ -1598,17 +1622,21 @@ lookup_member (xbasetype, name, protect, want_type)
    QFN, if non-NULL, is a predicate dictating whether the type should
    even be queued.  */
 
-static HOST_WIDE_INT
+static tree
 breadth_first_search (binfo, testfn, qfn)
      tree binfo;
-     int (*testfn) PROTO((tree, int));
-     int (*qfn) PROTO((tree, int));
+     tree (*testfn) PROTO((tree));
+     int (*qfn) PROTO((tree));
 {
   int head = 0, tail = 0;
-  int rval = 0;
+  tree rval = NULL_TREE;
 
   search_stack = push_search_level (search_stack, &search_obstack);
 
+  SET_BINFO_MARKED (binfo);
+  obstack_ptr_grow (&search_obstack, binfo);
+  ++tail;
+
   while (1)
     {
       tree binfos = BINFO_BASETYPES (binfo);
@@ -1621,12 +1649,11 @@ breadth_first_search (binfo, testfn, qfn)
          tree base_binfo = TREE_VEC_ELT (binfos, i);
 
          if (BINFO_MARKED (base_binfo) == 0
-             && (qfn == 0 || (*qfn) (binfo, i)))
+             && (qfn == 0 || (*qfn) (base_binfo)))
            {
              SET_BINFO_MARKED (base_binfo);
-             obstack_ptr_grow (&search_obstack, binfo);
-             obstack_ptr_grow (&search_obstack, (HOST_WIDE_INT) i);
-             tail += 2;
+             obstack_ptr_grow (&search_obstack, base_binfo);
+             ++tail;
              if (tail >= search_stack->limit)
                my_friendly_abort (100);
            }
@@ -1639,10 +1666,8 @@ breadth_first_search (binfo, testfn, qfn)
        }
 
       binfo = search_stack->first[head++];
-      i = (HOST_WIDE_INT) search_stack->first[head++];
-      if ((rval = (*testfn) (binfo, i)))
+      if ((rval = (*testfn) (binfo)))
        break;
-      binfo = BINFO_BASETYPE (binfo, i);
     }
   {
     tree *tp = search_stack->first;
@@ -1650,8 +1675,7 @@ breadth_first_search (binfo, testfn, qfn)
     while (tp < search_tail)
       {
        tree binfo = *tp++;
-       int i = (HOST_WIDE_INT)(*tp++);
-       CLEAR_BINFO_MARKED (BINFO_BASETYPE (binfo, i));
+       CLEAR_BINFO_MARKED (binfo);
       }
   }
 
@@ -1660,7 +1684,7 @@ breadth_first_search (binfo, testfn, qfn)
 }
 
 /* Functions to use in breadth first searches.  */
-typedef int (*pfi) PROTO((tree, int));
+typedef tree (*pfi) PROTO((tree));
 
 static tree declarator;
 
@@ -1691,13 +1715,10 @@ get_virtuals_named_this (binfo)
 }
 
 static tree
-get_virtual_destructor (binfo, i)
+get_virtual_destructor (binfo)
      tree binfo;
-     int i;
 {
   tree type = BINFO_TYPE (binfo);
-  if (i >= 0)
-    type = BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo), i));
   if (TYPE_HAS_DESTRUCTOR (type)
       && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1)))
     return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1);
@@ -1705,13 +1726,10 @@ get_virtual_destructor (binfo, i)
 }
 
 static int
-tree_has_any_destructor_p (binfo, i)
+tree_has_any_destructor_p (binfo)
      tree binfo;
-     int i;
 {
   tree type = BINFO_TYPE (binfo);
-  if (i >= 0)
-    type = BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo), i));
   return TYPE_NEEDS_DESTRUCTOR (type);
 }
 
@@ -1739,14 +1757,13 @@ covariant_return_p (brettype, drettype)
       drettype = TREE_TYPE (drettype);
     }
 
-  if (comptypes (brettype, drettype, 1))
+  if (same_type_p (brettype, drettype))
     return 0;
 
   if (! (TREE_CODE (brettype) == TREE_CODE (drettype)
         && (TREE_CODE (brettype) == POINTER_TYPE
             || TREE_CODE (brettype) == REFERENCE_TYPE)
-        && TYPE_READONLY (brettype) == TYPE_READONLY (drettype)
-        && TYPE_VOLATILE (brettype) == TYPE_VOLATILE (drettype)))
+        && TYPE_QUALS (brettype) == TYPE_QUALS (drettype)))
     return 0;
 
   if (! can_convert (brettype, drettype))
@@ -1797,16 +1814,9 @@ get_matching_virtual (binfo, fndecl, dtorp)
      of TYPE, so we must perform first ply of search here.  */
   if (dtorp)
     {
-      if (tree_has_any_destructor_p (binfo, -1))
-       tmp = get_virtual_destructor (binfo, -1);
-
-      if (tmp)
-       return tmp;
-
-      tmp = (tree) breadth_first_search (binfo,
-                                        (pfi) get_virtual_destructor,
-                                        tree_has_any_destructor_p);
-      return tmp;
+      return breadth_first_search (binfo,
+                                  get_virtual_destructor,
+                                  tree_has_any_destructor_p);
     }
   else
     {
@@ -1842,18 +1852,22 @@ get_matching_virtual (binfo, fndecl, dtorp)
              btypes = TYPE_ARG_TYPES (TREE_TYPE (tmp));
              if (instptr_type == NULL_TREE)
                {
-                 if (compparms (TREE_CHAIN (btypes), dtypes, 3))
+                 if (compparms (TREE_CHAIN (btypes), dtypes))
                    /* Caller knows to give error in this case.  */
                    return tmp;
                  return NULL_TREE;
                }
 
-             if ((TYPE_READONLY (TREE_TYPE (TREE_VALUE (btypes)))
-                  == TYPE_READONLY (instptr_type))
-                 && compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes), 3))
+             if (/* The first parameter is the `this' parameter,
+                    which has POINTER_TYPE, and we can therefore
+                    safely use TYPE_QUALS, rather than
+                    CP_TYPE_QUALS.  */
+                 (TYPE_QUALS (TREE_TYPE (TREE_VALUE (btypes)))
+                  == TYPE_QUALS (instptr_type))
+                 && compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes)))
                {
                  tree brettype = TREE_TYPE (TREE_TYPE (tmp));
-                 if (comptypes (brettype, drettype, 1))
+                 if (same_type_p (brettype, drettype))
                    /* OK */;
                  else if ((i = covariant_return_p (brettype, drettype)))
                    {
@@ -1867,7 +1881,7 @@ get_matching_virtual (binfo, fndecl, dtorp)
                        }
                    }
                  else if (IS_AGGR_TYPE_2 (brettype, drettype)
-                          && comptypes (brettype, drettype, 0))
+                          && same_or_base_type_p (brettype, drettype))
                    {
                      error ("invalid covariant return type (must use pointer or reference)");
                      cp_error_at ("  overriding `%#D'", tmp);
@@ -1945,7 +1959,7 @@ get_abstract_virtuals (type)
      tree type;
 {
   tree vbases;
-  tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (type);
+  tree abstract_virtuals = NULL;
 
   /* First get all from non-virtual bases.  */
   abstract_virtuals
@@ -1961,7 +1975,9 @@ get_abstract_virtuals (type)
        {
          tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals));
          tree base_fndecl = TREE_OPERAND (base_pfn, 0);
-         if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl))
+         if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
+           cp_error ("`%#D' needs a final overrider", base_fndecl);
+         else if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl))
            abstract_virtuals = tree_cons (NULL_TREE, base_fndecl, abstract_virtuals);
          virtuals = TREE_CHAIN (virtuals);
        }
@@ -2532,7 +2548,7 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
              /* Dup it if it isn't in local scope yet.  */
              nvtbl = build_decl
                (VAR_DECL, DECL_NAME (vtbl),
-                TYPE_MAIN_VARIANT (TREE_TYPE (BINFO_VTABLE (binfo))));
+                TYPE_MAIN_VARIANT (TREE_TYPE (vtbl)));
              DECL_ALIGN (nvtbl) = MAX (TYPE_ALIGN (double_type_node),
                                        DECL_ALIGN (nvtbl));
              TREE_READONLY (nvtbl) = 0;
@@ -2596,8 +2612,9 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
 
          TREE_READONLY (new_delta) = 0;
          TREE_TYPE (new_delta) = 
-           cp_build_type_variant (TREE_TYPE (new_delta), /*constp=*/0,
-                                  TYPE_VOLATILE (TREE_TYPE (new_delta)));
+           cp_build_qualified_type (TREE_TYPE (new_delta),
+                                    CP_TYPE_QUALS (TREE_TYPE (new_delta))
+                                    & ~TYPE_QUAL_CONST);
          expand_expr_stmt (build_modify_expr (new_delta, NOP_EXPR,
                                               old_delta));
        }
@@ -3004,6 +3021,7 @@ dfs_pushdecls (binfo)
 
          /* If the class value is not an envelope of the kind described in
             the comment above, we create a new envelope.  */
+         maybe_push_cache_obstack ();
          if (class_value == NULL_TREE || TREE_CODE (class_value) != TREE_LIST
              || TREE_PURPOSE (class_value) == NULL_TREE
              || TREE_CODE (TREE_PURPOSE (class_value)) == IDENTIFIER_NODE)
@@ -3016,10 +3034,11 @@ dfs_pushdecls (binfo)
            }
 
          envelope_add_decl (type, fields, &TREE_PURPOSE (class_value));
+         pop_obstacks ();
        }
     }
 
-  method_vec = CLASSTYPE_METHOD_VEC (type);
+  method_vec = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
   if (method_vec && ! dummy)
     {
       tree *methods;
@@ -3041,6 +3060,8 @@ dfs_pushdecls (binfo)
          name = DECL_NAME (OVL_CURRENT (*methods));
          class_value = IDENTIFIER_CLASS_VALUE (name);
 
+         maybe_push_cache_obstack ();
+
          /* If the class value is not an envelope of the kind described in
             the comment above, we create a new envelope.  */
          if (class_value == NULL_TREE || TREE_CODE (class_value) != TREE_LIST
@@ -3057,7 +3078,6 @@ dfs_pushdecls (binfo)
          /* Here we try to rule out possible ambiguities.
             If we can't do that, keep a TREE_LIST with possibly ambiguous
             decls in there.  */
-         maybe_push_cache_obstack ();
          /* Arbitrarily choose the first function in the list.  This is OK
             because this is only used for initial lookup; anything that
             actually uses the function will look it up again.  */
@@ -3079,7 +3099,8 @@ dfs_compress_decls (binfo)
      tree binfo;
 {
   tree type = BINFO_TYPE (binfo);
-  tree method_vec = CLASSTYPE_METHOD_VEC (type);
+  tree method_vec 
+    = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
 
   if (processing_template_decl && type != current_class_type
       && dependent_base_p (binfo))
@@ -3129,6 +3150,11 @@ push_class_decls (type)
   struct obstack *ambient_obstack = current_obstack;
   search_stack = push_search_level (search_stack, &search_obstack);
 
+  /* Build up all the relevant bindings and such on the cache
+     obstack.  That way no memory is wasted when we throw away the
+     cache later.  */
+  maybe_push_cache_obstack ();
+
   /* Push class fields into CLASS_VALUE scope, and mark.  */
   dfs_walk (TYPE_BINFO (type), dfs_pushdecls, unmarked_pushdecls_p);
 
@@ -3196,6 +3222,10 @@ push_class_decls (type)
        pushdecl_class_level (new);
       closed_envelopes = TREE_CHAIN (closed_envelopes);
     }
+  
+  /* Undo the call to maybe_push_cache_obstack above.  */
+  pop_obstacks ();
+
   current_obstack = ambient_obstack;
 }
 
@@ -3273,7 +3303,7 @@ reinit_search_statistics ()
 #define scratch_tree_cons expr_tree_cons
 
 static tree conversions;
-static void
+static tree
 add_conversions (binfo)
      tree binfo;
 {
@@ -3283,25 +3313,37 @@ add_conversions (binfo)
   for (i = 2; i < TREE_VEC_LENGTH (method_vec); ++i)
     {
       tree tmp = TREE_VEC_ELT (method_vec, i);
+      tree name;
 
-      if (!tmp
-         || !IDENTIFIER_TYPENAME_P (DECL_NAME (OVL_CURRENT (tmp))))
+      if (!tmp || ! DECL_CONV_FN_P (OVL_CURRENT (tmp)))
        break;
-      conversions = scratch_tree_cons (binfo, tmp, conversions);
+
+      name = DECL_NAME (OVL_CURRENT (tmp));
+
+      /* Make sure we don't already have this conversion.  */
+      if (! IDENTIFIER_MARKED (name))
+       {
+         conversions = scratch_tree_cons (binfo, tmp, conversions);
+         IDENTIFIER_MARKED (name) = 1;
+       }
     }
-  SET_BINFO_MARKED (binfo);
+  return NULL_TREE;
 }
 
 tree
 lookup_conversions (type)
      tree type;
 {
+  tree t;
+
   conversions = NULL_TREE;
+
   if (TYPE_SIZE (type))
-    {
-      dfs_walk (TYPE_BINFO (type), add_conversions, unmarkedp);
-      dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp);
-    }
+    breadth_first_search (TYPE_BINFO (type), add_conversions, 0);
+
+  for (t = conversions; t; t = TREE_CHAIN (t))
+    IDENTIFIER_MARKED (DECL_NAME (OVL_CURRENT (TREE_VALUE (t)))) = 0;
+
   return conversions;
 }