decl.c (struct binding_level): New field using_directives.

* decl.c (struct binding_level): New field using_directives.
	(push_using_decl): Not sorry anymore.
	(push_using_directive): New function.
	(lookup_tag): Use CP_DECL_CONTEXT to iterate.
	(unqualified_namespace_lookup): New function, code from ...
	(lookup_name_real): ... here.
	* decl2.c (lookup_using_namespace): Pass using list instead of
	initial scope.
	(validate_nonmember_using_decl): New function.
	(do_nonmember_using_decl): New function.
	(do_toplevel_using_decl): Use them.
	(do_local_using_decl): New function.
	(do_using_directive): Support block-level directives.
	* parse.y (simple_stmt): Support using declarations and
	directives.
	(namespace_qualifier, namespace_using_decl): New non-terminals.

From-SVN: r21089
This commit is contained in:
Martin v. Löwis 1998-07-12 11:41:22 -04:00 committed by Jason Merrill
parent 11b5139c46
commit ea9635c739
5 changed files with 237 additions and 95 deletions

View File

@ -1,5 +1,22 @@
1998-07-12 Martin von Löwis <loewis@informatik.hu-berlin.de>
* decl.c (struct binding_level): New field using_directives.
(push_using_decl): Not sorry anymore.
(push_using_directive): New function.
(lookup_tag): Use CP_DECL_CONTEXT to iterate.
(unqualified_namespace_lookup): New function, code from ...
(lookup_name_real): ... here.
* decl2.c (lookup_using_namespace): Pass using list instead of
initial scope.
(validate_nonmember_using_decl): New function.
(do_nonmember_using_decl): New function.
(do_toplevel_using_decl): Use them.
(do_local_using_decl): New function.
(do_using_directive): Support block-level directives.
* parse.y (simple_stmt): Support using declarations and
directives.
(namespace_qualifier, namespace_using_decl): New non-terminals.
* xref.c (classname): New function.
(GNU_xref_hier): Change class and base parameters to tree.
* decl.c (xref_baseypes): Change caller.

View File

@ -2359,7 +2359,9 @@ extern void pushdecl_nonclass_level PROTO((tree));
#endif
extern tree pushdecl_namespace_level PROTO((tree));
extern tree push_using_decl PROTO((tree, tree));
extern tree push_using_directive PROTO((tree, tree));
extern void push_class_level_binding PROTO((tree, tree));
extern tree push_using_decl PROTO((tree, tree));
extern tree implicitly_declare PROTO((tree));
extern tree lookup_label PROTO((tree));
extern tree shadow_label PROTO((tree));
@ -2489,6 +2491,7 @@ extern void push_decl_namespace PROTO((tree));
extern void pop_decl_namespace PROTO((void));
extern void do_namespace_alias PROTO((tree, tree));
extern void do_toplevel_using_decl PROTO((tree));
extern void do_local_using_decl PROTO((tree));
extern tree do_class_using_decl PROTO((tree));
extern void do_using_directive PROTO((tree));
extern void check_default_args PROTO((tree));

View File

@ -613,6 +613,10 @@ struct binding_level
/* A list of USING_DECL nodes. */
tree usings;
/* A list of used namespaces. PURPOSE is the namespace,
VALUE the common ancestor with this binding_level's namespace. */
tree using_directives;
/* For each level, a list of shadowed outer-level local definitions
to be restored when this level is popped.
Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and
@ -3822,12 +3826,6 @@ push_using_decl (scope, name)
{
tree decl;
if (!toplevel_bindings_p ())
{
sorry ("using declaration inside function");
return NULL_TREE;
}
my_friendly_assert (TREE_CODE (scope) == NAMESPACE_DECL, 383);
my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 384);
for (decl = current_binding_level->usings; decl; decl = TREE_CHAIN (decl))
@ -3842,6 +3840,26 @@ push_using_decl (scope, name)
return decl;
}
/* Add namespace to using_directives. Return NULL_TREE if nothing was
changed (i.e. there was already a directive), or the fresh
TREE_LIST otherwise. */
tree
push_using_directive (used, ancestor)
tree used;
tree ancestor;
{
tree ud = current_binding_level->using_directives;
/* Check if we already have this. */
if (purpose_member (used, ud) != NULL_TREE)
return NULL_TREE;
ud = perm_tree_cons (used, ancestor, ud);
current_binding_level->using_directives = ud;
return ud;
}
/* DECL is a FUNCTION_DECL which may have other definitions already in
place. We get around this by making the value of the identifier point
to a list of all the things that want to be referenced by that name. It
@ -4732,6 +4750,62 @@ select_decl (binding, prefer_type, namespaces_only)
return val;
}
/* Unscoped lookup of a global, iterate over namespaces, considering
using namespace statements. */
static tree
unqualified_namespace_lookup (name, prefer_type, namespaces_only)
tree name;
int prefer_type;
int namespaces_only;
{
struct tree_binding _binding;
tree b = binding_init (&_binding);
tree initial = current_decl_namespace();
tree scope = initial;
tree siter;
struct binding_level *level;
tree val = NULL_TREE;
while (!val)
{
val = binding_for_name (name, scope);
/* Initialize binding for this context. */
BINDING_VALUE (b) = BINDING_VALUE (val);
BINDING_TYPE (b) = BINDING_TYPE (val);
/* Add all _DECLs seen through local using-directives. */
for (level = current_binding_level;
!level->namespace_p;
level = level->level_chain)
if (!lookup_using_namespace (name, b, level->using_directives, scope))
/* Give up because of error. */
return NULL_TREE;
/* Add all _DECLs seen through global using-directives. */
/* XXX local and global using lists should work equally. */
siter = initial;
while (1)
{
if (!lookup_using_namespace (name, b, DECL_NAMESPACE_USING (siter),
scope))
/* Give up because of error. */
return NULL_TREE;
if (siter == scope) break;
siter = CP_DECL_CONTEXT (siter);
}
val = select_decl (b, prefer_type, namespaces_only);
if (scope == global_namespace)
break;
scope = DECL_CONTEXT (scope);
if (scope == NULL_TREE)
scope = global_namespace;
}
return val;
}
/* Look up NAME in the current binding level and its superiors in the
namespace of variables, functions and typedefs. Return a ..._DECL
node of some kind representing its definition if there is only one
@ -4903,35 +4977,7 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
else if (classval)
val = classval;
else
{
/* Unscoped lookup of a global, iterate over namespaces,
considering using namespace statements. */
struct tree_binding _binding;
tree b = binding_init (&_binding);
tree initial = current_decl_namespace();
tree scope = initial;
val = NULL_TREE;
while (!val)
{
val = binding_for_name (name, scope);
/* Initialize binding for this context. */
BINDING_VALUE (b) = BINDING_VALUE (val);
BINDING_TYPE (b) = BINDING_TYPE (val);
/* Add all _DECLs seen through using-directives. */
if (!lookup_using_namespace (name, b, initial, scope))
{
/* Give up because of error. */
val = NULL_TREE;
break;
}
val = select_decl (b, prefer_type, namespaces_only);
if (scope == global_namespace)
break;
scope = DECL_CONTEXT (scope);
if (scope == NULL_TREE)
scope = global_namespace;
}
}
val = unqualified_namespace_lookup (name, prefer_type, namespaces_only);
done:
if (val)

View File

@ -3940,32 +3940,24 @@ ambiguous_decl (name, old, new)
}
/* Add the bindings of name in used namespaces to val.
The using list is defined by current, and the lookup goes to scope.
The using list is defined by usings, and the lookup goes to scope.
Returns zero on errors. */
int
lookup_using_namespace (name, val, current, scope)
tree name, val, current, scope;
lookup_using_namespace (name, val, usings, scope)
tree name, val, usings, scope;
{
tree iter;
tree val1;
/* Iterate over all namespaces from current to scope. */
while (val != error_mark_node)
{
/* Iterate over all used namespaces in current, searching for
using directives of scope. */
for (iter = DECL_NAMESPACE_USING (current);
iter; iter = TREE_CHAIN (iter))
if (TREE_VALUE (iter) == scope)
{
val1 = binding_for_name (name, TREE_PURPOSE (iter));
/* Resolve ambiguities. */
val = ambiguous_decl (name, val, val1);
}
if (current == scope)
break;
current = CP_DECL_CONTEXT (current);
}
/* Iterate over all used namespaces in current, searching for using
directives of scope. */
for (iter = usings; iter; iter = TREE_CHAIN (iter))
if (TREE_VALUE (iter) == scope)
{
val1 = binding_for_name (name, TREE_PURPOSE (iter));
/* Resolve ambiguities. */
val = ambiguous_decl (name, val, val1);
}
return val != error_mark_node;
}
@ -4405,39 +4397,49 @@ do_namespace_alias (alias, namespace)
}
}
/* Process a using-declaration not appearing in class or local scope. */
/* Check a non-member using-declaration. Return the name and scope
being used, and the USING_DECL, or NULL_TREE on failure. */
void
do_toplevel_using_decl (decl)
static tree
validate_nonmember_using_decl (decl, scope, name)
tree decl;
tree *scope;
tree *name;
{
tree scope, name, binding, decls, newval, newtype;
struct tree_binding _decls;
if (TREE_CODE (decl) == SCOPE_REF
&& TREE_OPERAND (decl, 0) == std_node)
return;
return NULL_TREE;
if (TREE_CODE (decl) == SCOPE_REF)
{
scope = TREE_OPERAND (decl, 0);
name = TREE_OPERAND (decl, 1);
*scope = TREE_OPERAND (decl, 0);
*name = TREE_OPERAND (decl, 1);
}
else if (TREE_CODE (decl) == IDENTIFIER_NODE
|| TREE_CODE (decl) == TYPE_DECL)
{
scope = global_namespace;
name = decl;
*scope = global_namespace;
*name = decl;
}
else
my_friendly_abort (382);
if (TREE_CODE_CLASS (TREE_CODE (name)) == 'd')
name = DECL_NAME (name);
if (TREE_CODE_CLASS (TREE_CODE (*name)) == 'd')
*name = DECL_NAME (*name);
/* Make a USING_DECL. */
decl = push_using_decl (scope, name);
if (!decl)
return;
binding = binding_for_name (name, current_namespace);
return push_using_decl (*scope, *name);
}
/* Process local and global using-declarations. */
static void
do_nonmember_using_decl (scope, name, oldval, oldtype, newval, newtype)
tree scope, name;
tree oldval, oldtype;
tree *newval, *newtype;
{
tree decls;
struct tree_binding _decls;
*newval = *newtype = NULL_TREE;
decls = binding_init (&_decls);
if (!qualified_lookup_using_namespace (name, scope, decls))
/* Lookup error */
@ -4448,14 +4450,12 @@ do_toplevel_using_decl (decl)
cp_error ("`%D' not declared", name);
return;
}
newval = newtype = NULL_TREE;
/* Check for using functions. */
if (BINDING_VALUE (decls) && is_overloaded_fn (BINDING_VALUE (decls)))
{
tree oldval = BINDING_VALUE (binding);
tree tmp, tmp1;
newval = oldval;
*newval = oldval;
for (tmp = BINDING_VALUE (decls); tmp; tmp = OVL_NEXT (tmp))
{
@ -4473,27 +4473,48 @@ do_toplevel_using_decl (decl)
if (tmp1)
continue;
newval = build_overload (OVL_CURRENT (tmp), newval);
if (TREE_CODE (newval) != OVERLOAD)
newval = ovl_cons (newval, NULL_TREE);
OVL_USED (newval) = 1;
*newval = build_overload (OVL_CURRENT (tmp), *newval);
if (TREE_CODE (*newval) != OVERLOAD)
*newval = ovl_cons (*newval, NULL_TREE);
OVL_USED (*newval) = 1;
}
}
else
{
tree oldval = BINDING_VALUE (binding);
newval = BINDING_VALUE (decls);
if (oldval && oldval != newval && !duplicate_decls (newval, oldval))
newval = oldval;
*newval = BINDING_VALUE (decls);
if (oldval && oldval != *newval && !duplicate_decls (*newval, oldval))
*newval = oldval;
}
newtype = BINDING_TYPE (decls);
if (BINDING_TYPE (binding) && newtype && BINDING_TYPE (binding) != newtype)
*newtype = BINDING_TYPE (decls);
if (oldtype && *newtype && oldtype != *newtype)
{
cp_error ("using directive `%D' introduced ambiguous type `%T'",
name, BINDING_TYPE (decls));
name, oldtype);
return;
}
}
/* Process a using-declaration not appearing in class or local scope. */
void
do_toplevel_using_decl (decl)
tree decl;
{
tree scope, name, binding;
tree oldval, oldtype, newval, newtype;
decl = validate_nonmember_using_decl (decl, &scope, &name);
if (decl == NULL_TREE)
return;
binding = binding_for_name (name, current_namespace);
oldval = BINDING_VALUE (binding);
oldtype = BINDING_TYPE (binding);
do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype);
/* Copy declarations found. */
if (newval)
BINDING_VALUE (binding) = newval;
@ -4502,6 +4523,29 @@ do_toplevel_using_decl (decl)
return;
}
void
do_local_using_decl (decl)
tree decl;
{
tree scope, name;
tree oldval, oldtype, newval, newtype;
decl = validate_nonmember_using_decl (decl, &scope, &name);
if (decl == NULL_TREE)
return;
/* XXX nested values */
oldval = IDENTIFIER_LOCAL_VALUE (name);
/* XXX get local type */
oldtype = NULL_TREE;
do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype);
if (newval)
/* XXX update bindings */
IDENTIFIER_LOCAL_VALUE (name) = newval;
/* XXX type */
}
tree
do_class_using_decl (decl)
tree decl;
@ -4534,11 +4578,6 @@ do_using_directive (namespace)
{
if (namespace == std_node)
return;
if (!toplevel_bindings_p ())
{
sorry ("using directives inside functions");
return;
}
/* using namespace A::B::C; */
if (TREE_CODE (namespace) == SCOPE_REF)
namespace = TREE_OPERAND (namespace, 1);
@ -4554,8 +4593,13 @@ do_using_directive (namespace)
return;
}
namespace = ORIGINAL_NAMESPACE (namespace);
/* direct usage */
add_using_namespace (current_namespace, namespace, 0);
if (!toplevel_bindings_p ())
push_using_directive
(namespace, namespace_ancestor (current_decl_namespace(),
current_namespace));
else
/* direct usage */
add_using_namespace (current_namespace, namespace, 0);
}
void

View File

@ -222,7 +222,8 @@ empty_parms ()
%type <ttype> template_id do_id object_template_id notype_template_declarator
%type <ttype> overqualified_id notype_qualified_id any_id
%type <ttype> complex_direct_notype_declarator functional_cast
%type <ttype> complex_parmlist parms_comma
%type <ttype> complex_parmlist parms_comma
%type <ttype> namespace_qualifier namespace_using_decl
%type <ftype> type_id new_type_id typed_typespecs typespec typed_declspecs
%type <ftype> typed_declspecs1 type_specifier_seq nonempty_cv_qualifiers
@ -438,6 +439,29 @@ using_decl:
{ $$ = $3; }
;
namespace_using_decl:
USING namespace_qualifier identifier
{ $$ = build_parse_node (SCOPE_REF, $2, $3); }
| USING global_scope identifier
{ $$ = build_parse_node (SCOPE_REF, global_namespace, $3); }
| USING global_scope namespace_qualifier identifier
{ $$ = build_parse_node (SCOPE_REF, $3, $4); }
;
namespace_qualifier:
NSNAME SCOPE
{
if (TREE_CODE ($$) == IDENTIFIER_NODE)
$$ = lastiddecl;
got_scope = $$;
}
| namespace_qualifier NSNAME SCOPE
{
if (TREE_CODE ($$) == IDENTIFIER_NODE)
$$ = lastiddecl;
got_scope = $$;
}
any_id:
unqualified_id
| qualified_id
@ -3244,6 +3268,14 @@ simple_stmt:
| ';'
{ finish_stmt (); }
| try_block
| USING NAMESPACE any_id ';'
{
if (TREE_CODE ($3) == IDENTIFIER_NODE && lastiddecl)
$3 = lastiddecl;
do_using_directive ($3);
}
| namespace_using_decl
{ do_local_using_decl ($1); }
;
function_try_block: