This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

local using directives


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:



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]