/* 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.
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;
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)
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
== 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;
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)
{
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);
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);
}
}
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;
while (tp < search_tail)
{
tree binfo = *tp++;
- int i = (HOST_WIDE_INT)(*tp++);
- CLEAR_BINFO_MARKED (BINFO_BASETYPE (binfo, i));
+ CLEAR_BINFO_MARKED (binfo);
}
}
}
/* Functions to use in breadth first searches. */
-typedef int (*pfi) PROTO((tree, int));
+typedef tree (*pfi) PROTO((tree));
static tree declarator;
}
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);
}
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);
}
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))
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
{
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)))
{
}
}
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);
tree type;
{
tree vbases;
- tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (type);
+ tree abstract_virtuals = NULL;
/* First get all from non-virtual bases. */
abstract_virtuals
{
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);
}
/* 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;
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));
}
/* 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)
}
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;
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
/* 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. */
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))
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);
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;
}
#define scratch_tree_cons expr_tree_cons
static tree conversions;
-static void
+static tree
add_conversions (binfo)
tree 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;
}