aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/search.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/search.c')
-rw-r--r--gcc/cp/search.c325
1 files changed, 230 insertions, 95 deletions
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index fefd11b8b16..7aa811299bd 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -1,7 +1,7 @@
/* Breadth-first and depth-first routines for
searching multiple-inheritance lattice for GNU C++.
Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2002 Free Software Foundation, Inc.
+ 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -80,7 +80,6 @@ struct vbase_info
tree inits;
};
-static tree lookup_field_1 PARAMS ((tree, tree));
static int is_subobject_of_p PARAMS ((tree, tree, tree));
static int is_subobject_of_p_1 PARAMS ((tree, tree, tree));
static tree dfs_check_overlap PARAMS ((tree, void *));
@@ -453,9 +452,8 @@ get_dynamic_cast_base_type (subtype, target)
figure out whether it can access this field. (Since it is only one
level, this is reasonable.) */
-static tree
-lookup_field_1 (type, name)
- tree type, name;
+tree
+lookup_field_1 (tree type, tree name, bool want_type)
{
register tree field;
@@ -492,14 +490,28 @@ lookup_field_1 (type, name)
lo = i + 1;
else
{
+ field = NULL_TREE;
+
/* We might have a nested class and a field with the
same name; we sorted them appropriately via
- field_decl_cmp, so just look for the last field with
- this name. */
- while (i + 1 < hi
- && DECL_NAME (fields[i+1]) == name)
- ++i;
- return fields[i];
+ field_decl_cmp, so just look for the first or last
+ field with this name. */
+ if (want_type)
+ {
+ do
+ field = fields[i--];
+ while (i >= lo && DECL_NAME (fields[i]) == name);
+ if (TREE_CODE (field) != TYPE_DECL
+ && !DECL_CLASS_TEMPLATE_P (field))
+ field = NULL_TREE;
+ }
+ else
+ {
+ do
+ field = fields[i++];
+ while (i < hi && DECL_NAME (fields[i]) == name);
+ }
+ return field;
}
}
return NULL_TREE;
@@ -510,7 +522,7 @@ lookup_field_1 (type, name)
#ifdef GATHER_STATISTICS
n_calls_lookup_field_1++;
#endif /* GATHER_STATISTICS */
- while (field)
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
#ifdef GATHER_STATISTICS
n_fields_searched++;
@@ -519,7 +531,7 @@ lookup_field_1 (type, name)
if (DECL_NAME (field) == NULL_TREE
&& ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
- tree temp = lookup_field_1 (TREE_TYPE (field), name);
+ tree temp = lookup_field_1 (TREE_TYPE (field), name, want_type);
if (temp)
return temp;
}
@@ -529,10 +541,13 @@ lookup_field_1 (type, name)
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)
+ continue;
+
+ if (DECL_NAME (field) == name
+ && (!want_type
+ || TREE_CODE (field) == TYPE_DECL
+ || DECL_CLASS_TEMPLATE_P (field)))
return field;
- field = TREE_CHAIN (field);
}
/* Not found. */
if (name == vptr_identifier)
@@ -1003,9 +1018,15 @@ void
type_access_control (type, val)
tree type, val;
{
+ /* The check processing_specialization is here because the parser in 3.3
+ does not set current_class_type while parsing class head of class
+ template specialization. Access checking, if performed, will be
+ evaluated in the wrong context so we disable it here. This doesn't
+ apply to the new parser in 3.4. */
if (val == NULL_TREE
|| (TREE_CODE (val) != TEMPLATE_DECL && TREE_CODE (val) != TYPE_DECL)
- || ! DECL_CLASS_SCOPE_P (val))
+ || ! DECL_CLASS_SCOPE_P (val)
+ || processing_specialization)
return;
if (type_lookups == error_mark_node)
@@ -1288,7 +1309,7 @@ lookup_field_r (binfo, data)
if (!nval)
/* Look for a data member or type. */
- nval = lookup_field_1 (type, lfi->name);
+ nval = lookup_field_1 (type, lfi->name, lfi->want_type);
/* If there is no declaration with the indicated name in this type,
then there's nothing to do. */
@@ -1313,11 +1334,12 @@ lookup_field_r (binfo, data)
}
else
nval = NULL_TREE;
- if (!nval)
+ if (!nval && CLASSTYPE_NESTED_UDTS (type) != NULL)
{
- nval = purpose_member (lfi->name, CLASSTYPE_TAGS (type));
- if (nval)
- nval = TYPE_MAIN_DECL (TREE_VALUE (nval));
+ binding_entry e = binding_table_find (CLASSTYPE_NESTED_UDTS (type),
+ lfi->name);
+ if (e != NULL)
+ nval = TYPE_MAIN_DECL (e->type);
else
return NULL_TREE;
}
@@ -1464,7 +1486,7 @@ lookup_member (xbasetype, name, protect, want_type)
&& IDENTIFIER_CLASS_VALUE (name))
{
tree field = IDENTIFIER_CLASS_VALUE (name);
- if (TREE_CODE (field) != FUNCTION_DECL
+ if (! is_overloaded_fn (field)
&& ! (want_type && TREE_CODE (field) != TYPE_DECL))
/* We're in the scope of this class, and the value has already
been looked up. Just return the cached value. */
@@ -1580,95 +1602,208 @@ lookup_fnfields (xbasetype, name, protect)
return rval;
}
+/* Try to find NAME inside a nested class. */
+
+tree
+lookup_nested_field (name, complain)
+ tree name;
+ int complain;
+{
+ register tree t;
+
+ tree id = NULL_TREE;
+ if (TYPE_MAIN_DECL (current_class_type))
+ {
+ /* Climb our way up the nested ladder, seeing if we're trying to
+ modify a field in an enclosing class. If so, we should only
+ be able to modify if it's static. */
+ for (t = TYPE_MAIN_DECL (current_class_type);
+ t && DECL_CONTEXT (t);
+ t = TYPE_MAIN_DECL (DECL_CONTEXT (t)))
+ {
+ if (TREE_CODE (DECL_CONTEXT (t)) != RECORD_TYPE)
+ break;
+
+ /* N.B.: lookup_field will do the access checking for us */
+ id = lookup_field (DECL_CONTEXT (t), name, complain, 0);
+ if (id == error_mark_node)
+ {
+ id = NULL_TREE;
+ continue;
+ }
+
+ if (id != NULL_TREE)
+ {
+ if (TREE_CODE (id) == FIELD_DECL
+ && ! TREE_STATIC (id)
+ && TREE_TYPE (id) != error_mark_node)
+ {
+ if (complain)
+ {
+ /* At parse time, we don't want to give this error, since
+ we won't have enough state to make this kind of
+ decision properly. But there are times (e.g., with
+ enums in nested classes) when we do need to call
+ this fn at parse time. So, in those cases, we pass
+ complain as a 0 and just return a NULL_TREE. */
+ error ("assignment to non-static member `%D' of enclosing class `%T'",
+ id, DECL_CONTEXT (t));
+ /* Mark this for do_identifier(). It would otherwise
+ claim that the variable was undeclared. */
+ TREE_TYPE (id) = error_mark_node;
+ }
+ else
+ {
+ id = NULL_TREE;
+ continue;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ return id;
+}
+
+/* Return the index in the CLASSTYPE_METHOD_VEC for CLASS_TYPE
+ corresponding to "operator TYPE ()", or -1 if there is no such
+ operator. Only CLASS_TYPE itself is searched; this routine does
+ not scan the base classes of CLASS_TYPE. */
+
+static int
+lookup_conversion_operator (tree class_type, tree type)
+{
+ int pass;
+ int i;
+
+ tree methods = CLASSTYPE_METHOD_VEC (class_type);
+
+ for (pass = 0; pass < 2; ++pass)
+ for (i = CLASSTYPE_FIRST_CONVERSION_SLOT;
+ i < TREE_VEC_LENGTH (methods);
+ ++i)
+ {
+ tree fn = TREE_VEC_ELT (methods, i);
+ /* The size of the vector may have some unused slots at the
+ end. */
+ if (!fn)
+ break;
+
+ /* All the conversion operators come near the beginning of the
+ class. Therefore, if FN is not a conversion operator, there
+ is no matching conversion operator in CLASS_TYPE. */
+ fn = OVL_CURRENT (fn);
+ if (!DECL_CONV_FN_P (fn))
+ break;
+
+ if (pass == 0)
+ {
+ /* On the first pass we only consider exact matches. If
+ the types match, this slot is the one where the right
+ conversion operators can be found. */
+ if (TREE_CODE (fn) != TEMPLATE_DECL
+ && same_type_p (DECL_CONV_FN_TYPE (fn), type))
+ return i;
+ }
+ else
+ {
+ /* On the second pass we look for template conversion
+ operators. It may be possible to instantiate the
+ template to get the type desired. All of the template
+ conversion operators share a slot. By looking for
+ templates second we ensure that specializations are
+ preferred over templates. */
+ if (TREE_CODE (fn) == TEMPLATE_DECL)
+ return i;
+ }
+ }
+
+ return -1;
+}
+
/* TYPE is a class type. Return the index of the fields within
the method vector with name NAME, or -1 is no such field exists. */
int
-lookup_fnfields_1 (type, name)
- tree type, name;
+lookup_fnfields_1 (tree type, tree name)
{
- tree method_vec = (CLASS_TYPE_P (type)
- ? CLASSTYPE_METHOD_VEC (type)
- : NULL_TREE);
+ tree method_vec;
+ tree *methods;
+ tree tmp;
+ int i;
+ int len;
- if (method_vec != 0)
- {
- register int i;
- register tree *methods = &TREE_VEC_ELT (method_vec, 0);
- int len = TREE_VEC_LENGTH (method_vec);
- tree tmp;
+ if (!CLASS_TYPE_P (type))
+ return -1;
+
+ method_vec = CLASSTYPE_METHOD_VEC (type);
+
+ if (!method_vec)
+ return -1;
+
+ methods = &TREE_VEC_ELT (method_vec, 0);
+ len = TREE_VEC_LENGTH (method_vec);
#ifdef GATHER_STATISTICS
- n_calls_lookup_fnfields_1++;
+ n_calls_lookup_fnfields_1++;
#endif /* GATHER_STATISTICS */
- /* Constructors are first... */
- if (name == ctor_identifier)
- return (methods[CLASSTYPE_CONSTRUCTOR_SLOT]
- ? CLASSTYPE_CONSTRUCTOR_SLOT : -1);
- /* and destructors are second. */
- if (name == dtor_identifier)
- return (methods[CLASSTYPE_DESTRUCTOR_SLOT]
- ? CLASSTYPE_DESTRUCTOR_SLOT : -1);
-
- for (i = CLASSTYPE_FIRST_CONVERSION_SLOT;
- i < len && methods[i];
- ++i)
+ /* Constructors are first... */
+ if (name == ctor_identifier)
+ return (methods[CLASSTYPE_CONSTRUCTOR_SLOT]
+ ? CLASSTYPE_CONSTRUCTOR_SLOT : -1);
+ /* and destructors are second. */
+ if (name == dtor_identifier)
+ return (methods[CLASSTYPE_DESTRUCTOR_SLOT]
+ ? CLASSTYPE_DESTRUCTOR_SLOT : -1);
+ if (IDENTIFIER_TYPENAME_P (name))
+ return lookup_conversion_operator (type, TREE_TYPE (name));
+
+ /* Skip the conversion operators. */
+ i = CLASSTYPE_FIRST_CONVERSION_SLOT;
+ while (i < len && methods[i] && DECL_CONV_FN_P (OVL_CURRENT (methods[i])))
+ i++;
+
+ /* If the type is complete, use binary search. */
+ if (COMPLETE_TYPE_P (type))
+ {
+ int lo = i;
+ int hi = len;
+
+ while (lo < hi)
{
+ i = (lo + hi) / 2;
+
#ifdef GATHER_STATISTICS
n_outer_fields_searched++;
#endif /* GATHER_STATISTICS */
- tmp = OVL_CURRENT (methods[i]);
- if (DECL_NAME (tmp) == name)
+ tmp = methods[i];
+ /* This slot may be empty; we allocate more slots than we
+ need. In that case, the entry we're looking for is
+ closer to the beginning of the list. */
+ if (tmp)
+ tmp = DECL_NAME (OVL_CURRENT (tmp));
+ if (!tmp || tmp > name)
+ hi = i;
+ else if (tmp < name)
+ lo = i + 1;
+ else
return i;
-
- /* If the type is complete and we're past the conversion ops,
- switch to binary search. */
- if (! DECL_CONV_FN_P (tmp)
- && COMPLETE_TYPE_P (type))
- {
- int lo = i + 1, hi = len;
-
- while (lo < hi)
- {
- i = (lo + hi) / 2;
-
+ }
+ }
+ else
+ for (; i < len && methods[i]; ++i)
+ {
#ifdef GATHER_STATISTICS
- n_outer_fields_searched++;
+ n_outer_fields_searched++;
#endif /* GATHER_STATISTICS */
- tmp = DECL_NAME (OVL_CURRENT (methods[i]));
-
- if (tmp > name)
- hi = i;
- else if (tmp < name)
- lo = i + 1;
- else
- return i;
- }
- break;
- }
- }
-
- /* If we didn't find it, it might have been a template
- conversion operator to a templated type. If there are any,
- such template conversion operators will all be overloaded on
- the first conversion slot. (Note that we don't look for this
- case above so that we will always find specializations
- first.) */
- if (IDENTIFIER_TYPENAME_P (name))
- {
- i = CLASSTYPE_FIRST_CONVERSION_SLOT;
- if (i < len && methods[i])
- {
- tmp = OVL_CURRENT (methods[i]);
- if (TREE_CODE (tmp) == TEMPLATE_DECL
- && DECL_TEMPLATE_CONV_FN_P (tmp))
- return i;
- }
- }
- }
+ tmp = OVL_CURRENT (methods[i]);
+ if (DECL_NAME (tmp) == name)
+ return i;
+ }
return -1;
}
@@ -2736,8 +2871,8 @@ lookup_conversions (type)
tree t;
tree conversions = NULL_TREE;
- if (COMPLETE_TYPE_P (type))
- bfs_walk (TYPE_BINFO (type), add_conversions, 0, &conversions);
+ complete_type (type);
+ bfs_walk (TYPE_BINFO (type), add_conversions, 0, &conversions);
for (t = conversions; t; t = TREE_CHAIN (t))
IDENTIFIER_MARKED (DECL_NAME (OVL_CURRENT (TREE_VALUE (t)))) = 0;