From ea9635c73973763d0bf639967d5ca512a7e1b121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20v=2E=20L=C3=B6wis?= Date: Sun, 12 Jul 1998 11:41:22 -0400 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 17 +++++ gcc/cp/cp-tree.h | 3 + gcc/cp/decl.c | 116 +++++++++++++++++++++++---------- gcc/cp/decl2.c | 162 ++++++++++++++++++++++++++++++----------------- gcc/cp/parse.y | 34 +++++++++- 5 files changed, 237 insertions(+), 95 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8abfcb557fb..44343f72f3d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,22 @@ 1998-07-12 Martin von Löwis + * 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. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6d660770d1e..e4da3a7a0c4 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index a65cdf6505b..90f174e7dbf 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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) diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index ccf00f58485..5bf96876259 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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 diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y index 99a7b7a408f..0e0d5fdcfa8 100644 --- a/gcc/cp/parse.y +++ b/gcc/cp/parse.y @@ -222,7 +222,8 @@ empty_parms () %type template_id do_id object_template_id notype_template_declarator %type overqualified_id notype_qualified_id any_id %type complex_direct_notype_declarator functional_cast -%type complex_parmlist parms_comma +%type complex_parmlist parms_comma +%type namespace_qualifier namespace_using_decl %type type_id new_type_id typed_typespecs typespec typed_declspecs %type 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: