This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
local using directives
- To: egcs-patches at cygnus dot com
- Subject: local using directives
- From: Martin von Loewis <martin at mira dot isdn dot cs dot tu-berlin dot de>
- Date: Mon, 29 Jun 1998 23:22:48 +0200
This patch adds using declarations and directives as block-level
statements. Now argument-dependent lookup is the only feature that is
still missing in the namespace implementation.
Regards,
Martin
1998-06-29 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.
Index: cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.91
diff -c -p -r1.91 cp-tree.h
*** cp-tree.h 1998/06/25 15:21:36 1.91
--- cp-tree.h 1998/06/29 20:31:15
*************** extern void pushdecl_nonclass_level PRO
*** 2348,2354 ****
--- 2348,2356 ----
#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));
*************** extern void push_decl_namespace
*** 2478,2483 ****
--- 2480,2486 ----
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));
Index: decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.145
diff -c -p -r1.145 decl.c
*** decl.c 1998/06/25 17:24:49 1.145
--- decl.c 1998/06/29 20:31:44
*************** struct binding_level
*** 613,618 ****
--- 613,622 ----
/* 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
*************** push_using_decl (scope, name)
*** 3821,3832 ****
{
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))
--- 3830,3835 ----
*************** push_using_decl (scope, name)
*** 3841,3846 ****
--- 3844,3869 ----
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
*************** lookup_tag (form, name, binding_level, t
*** 4414,4420 ****
else if (level->namespace_p)
/* Do namespace lookup. */
/* XXX: is this a real lookup, considering using-directives etc. ??? */
! for (tail = current_namespace; 1; tail = DECL_CONTEXT (tail))
{
tree old = BINDING_TYPE (binding_for_name (name, tail));
/* If it has an original type, it is a typedef, and we
--- 4437,4443 ----
else if (level->namespace_p)
/* Do namespace lookup. */
/* XXX: is this a real lookup, considering using-directives etc. ??? */
! for (tail = current_namespace; 1; tail = CP_DECL_CONTEXT (tail))
{
tree old = BINDING_TYPE (binding_for_name (name, tail));
/* If it has an original type, it is a typedef, and we
*************** select_decl (binding, prefer_type, names
*** 4731,4736 ****
--- 4763,4824 ----
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
*************** lookup_name_real (name, prefer_type, non
*** 4901,4935 ****
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;
! }
! }
done:
if (val)
--- 4989,4995 ----
else if (classval)
val = classval;
else
! val = unqualified_namespace_lookup (name, prefer_type, namespaces_only);
done:
if (val)
Index: decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.90
diff -c -p -r1.90 decl2.c
*** decl2.c 1998/06/25 14:11:54 1.90
--- decl2.c 1998/06/29 20:31:49
*************** ambiguous_decl (name, old, new)
*** 3928,3959 ****
}
/* Add the bindings of name in used namespaces to val.
! The using list is defined by current, and the lookup goes to scope.
Returns zero on errors. */
int
! lookup_using_namespace (name, val, current, scope)
! tree name, val, current, 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);
! }
return val != error_mark_node;
}
--- 3928,3951 ----
}
/* Add the bindings of name in used namespaces to val.
! The using list is defined by usings, and the lookup goes to scope.
Returns zero on errors. */
int
! lookup_using_namespace (name, val, usings, scope)
! tree name, val, usings, scope;
{
tree iter;
tree val1;
! /* 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;
}
*************** do_namespace_alias (alias, namespace)
*** 4393,4431 ****
}
}
! /* Process a using-declaration not appearing in class or local scope. */
! void
! do_toplevel_using_decl (decl)
tree decl;
{
- tree scope, name, binding, decls, newval, newtype;
- struct tree_binding _decls;
-
if (TREE_CODE (decl) == SCOPE_REF
&& TREE_OPERAND (decl, 0) == std_node)
! return;
if (TREE_CODE (decl) == SCOPE_REF)
{
! 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;
}
else
my_friendly_abort (382);
! 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);
decls = binding_init (&_decls);
if (!qualified_lookup_using_namespace (name, scope, decls))
/* Lookup error */
--- 4385,4433 ----
}
}
! /* Check a non-member using-declaration. Return the name and scope
! being used, and the USING_DECL, or NULL_TREE on failure. */
! static tree
! validate_nonmember_using_decl (decl, scope, name)
tree decl;
+ tree *scope;
+ tree *name;
{
if (TREE_CODE (decl) == SCOPE_REF
&& TREE_OPERAND (decl, 0) == std_node)
! return NULL_TREE;
if (TREE_CODE (decl) == SCOPE_REF)
{
! *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;
}
else
my_friendly_abort (382);
! if (TREE_CODE_CLASS (TREE_CODE (*name)) == 'd')
! *name = DECL_NAME (*name);
/* Make a USING_DECL. */
! 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 */
*************** do_toplevel_using_decl (decl)
*** 4436,4449 ****
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;
for (tmp = BINDING_VALUE (decls); tmp; tmp = OVL_NEXT (tmp))
{
--- 4438,4449 ----
cp_error ("`%D' not declared", name);
return;
}
/* Check for using functions. */
if (BINDING_VALUE (decls) && is_overloaded_fn (BINDING_VALUE (decls)))
{
tree tmp, tmp1;
! *newval = oldval;
for (tmp = BINDING_VALUE (decls); tmp; tmp = OVL_NEXT (tmp))
{
*************** do_toplevel_using_decl (decl)
*** 4461,4487 ****
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;
}
}
else
{
! tree oldval = BINDING_VALUE (binding);
! 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)
{
cp_error ("using directive `%D' introduced ambiguous type `%T'",
! name, BINDING_TYPE (decls));
return;
}
/* Copy declarations found. */
if (newval)
BINDING_VALUE (binding) = newval;
--- 4461,4508 ----
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;
}
}
else
{
! *newval = BINDING_VALUE (decls);
! if (oldval && oldval != *newval && !duplicate_decls (*newval, oldval))
! *newval = oldval;
}
! *newtype = BINDING_TYPE (decls);
! if (oldtype && *newtype && oldtype != *newtype)
{
cp_error ("using directive `%D' introduced ambiguous type `%T'",
! 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;
*************** do_toplevel_using_decl (decl)
*** 4490,4495 ****
--- 4511,4539 ----
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;
*************** do_using_directive (namespace)
*** 4522,4532 ****
{
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);
--- 4566,4571 ----
*************** do_using_directive (namespace)
*** 4542,4549 ****
return;
}
namespace = ORIGINAL_NAMESPACE (namespace);
! /* direct usage */
! add_using_namespace (current_namespace, namespace, 0);
}
void
--- 4581,4593 ----
return;
}
namespace = ORIGINAL_NAMESPACE (namespace);
! 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
Index: parse.y
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/parse.y,v
retrieving revision 1.65
diff -c -p -r1.65 parse.y
*** parse.y 1998/06/25 03:28:32 1.65
--- parse.y 1998/06/29 20:53:26
*************** empty_parms ()
*** 222,228 ****
%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 <ftype> type_id new_type_id typed_typespecs typespec typed_declspecs
%type <ftype> typed_declspecs1 type_specifier_seq nonempty_cv_qualifiers
--- 222,229 ----
%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> 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
*************** using_decl:
*** 438,443 ****
--- 439,467 ----
{ $$ = $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
*************** simple_stmt:
*** 3242,3247 ****
--- 3271,3284 ----
| ';'
{ 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: