decl.c (struct binding_level): New field using_directives.
authorMartin v. Löwis <loewis@informatik.hu-berlin.de>
Sun, 12 Jul 1998 15:41:22 +0000 (11:41 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sun, 12 Jul 1998 15:41:22 +0000 (11:41 -0400)
* 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
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/parse.y

index 8abfcb5..44343f7 100644 (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.
index 6d66077..e4da3a7 100644 (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));
index a65cdf6..90f174e 100644 (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)
index ccf00f5..5bf9687 100644 (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
index 99a7b7a..0e0d5fd 100644 (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: