Namespace aliases

Martin v. Loewis loewis@informatik.hu-berlin.de
Tue Jun 2 12:37:00 GMT 1998


The patch below fixes a few problems with namespace aliases. In
particular, this does:
- implement namespace aliases as a first class concept: DECL_NAMESPACE
  nodes whos abstract_origin points to the original-namespace
- check whether namespace re-opening uses only
  original-namespace-names.
- fix namespace-alias redeclarations.
- fix aliasing to qualified namespaces.

Please report any problems you find.

Martin

1998-06-02  Martin v. Löwis  <loewis@informatik.hu-berlin.de>

	* cp-tree.h (DECL_NAMESPACE_ALIAS): Declare.

	* decl.c (lookup_name_real): Add namespaces_only parameter.
	If set, return only NAMESPACE_DECLs.
	(select_decl): Likewise.
	(identifier_type_value): Give additional parameter.
	(lookup_name_nonclass): Likewise.
	(lookup_name): Likewise.
	(find_binding): Skip namespace aliases.
	(binding_for_name): Likewise.
	(push_namespace): Check for namespace aliases.
	(lookup_name_namespace_only): New function.
	(begin_only_namespace_names, end_only_namespace_names): New functions.

	* decl2.c (set_decl_namespace): Skip namespace aliases.
	(do_using_directive): Likewise.
	(do_namespace_alias): Produce namespace aliases, fix alias redeclaration.

	* error.c (dump_decl): Support SCOPE_REF.

	* parse.y (extdef): Wrap lookup with namespace_only for namespace
	aliases and using declarations.

Index: cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.78
diff -c -p -r1.78 cp-tree.h
*** cp-tree.h	1998/06/01 18:25:26	1.78
--- cp-tree.h	1998/06/02 19:16:49
*************** struct lang_decl
*** 1205,1210 ****
--- 1205,1214 ----
     of a namespace, to record the transitive closure of using namespace. */
  #define DECL_NAMESPACE_USERS(NODE) DECL_INITIAL (NODE)
  
+ /* In a NAMESPACE_DECL, points to the original namespace if this is
+    a namespace alias.  */
+ #define DECL_NAMESPACE_ALIAS(NODE) DECL_ABSTRACT_ORIGIN (NODE)
+ 
  /* In a TREE_LIST concatenating using directives, indicate indirekt
     directives  */
  #define TREE_INDIRECT_USING(NODE) ((NODE)->common.lang_flag_0)
*************** extern tree lookup_name_nonclass		PROTO(
*** 2354,2359 ****
--- 2358,2366 ----
  extern tree lookup_function_nonclass            PROTO((tree, tree));
  extern tree lookup_name				PROTO((tree, int));
  extern tree lookup_name_current_level		PROTO((tree));
+ extern tree lookup_name_namespace_only          PROTO((tree));
+ extern void begin_only_namespace_names          PROTO((void));
+ extern void end_only_namespace_names            PROTO((void));
  extern int  lookup_using_namespace              PROTO((tree,tree,tree,tree));
  extern int  qualified_lookup_using_namespace    PROTO((tree,tree,tree));
  extern tree auto_function			PROTO((tree, tree, enum built_in_function));
Index: decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.130
diff -c -p -r1.130 decl.c
*** decl.c	1998/06/01 18:25:28	1.130
--- decl.c	1998/06/02 19:16:53
*************** static tree store_bindings PROTO((tree, 
*** 157,163 ****
  static tree lookup_tag_reverse PROTO((tree, tree));
  static tree obscure_complex_init PROTO((tree, tree));
  static tree maybe_build_cleanup_1 PROTO((tree, tree));
! static tree lookup_name_real PROTO((tree, int, int));
  static void warn_extern_redeclared_static PROTO((tree, tree));
  static void grok_reference_init PROTO((tree, tree, tree));
  static tree grokfndecl PROTO((tree, tree, tree, tree, int,
--- 157,163 ----
  static tree lookup_tag_reverse PROTO((tree, tree));
  static tree obscure_complex_init PROTO((tree, tree));
  static tree maybe_build_cleanup_1 PROTO((tree, tree));
! static tree lookup_name_real PROTO((tree, int, int, int));
  static void warn_extern_redeclared_static PROTO((tree, tree));
  static void grok_reference_init PROTO((tree, tree, tree));
  static tree grokfndecl PROTO((tree, tree, tree, tree, int,
*************** tree vtbl_type_node;
*** 331,336 ****
--- 331,339 ----
  tree std_node;
  int in_std = 0;
  
+ /* Expect only namespace names now. */
+ static int only_namespace_names;
+ 
  /* In a destructor, the point at which all derived class destroying
     has been done, just before any base class destroying will be done.  */
  
*************** find_binding (name, scope)
*** 1646,1651 ****
--- 1649,1657 ----
       tree scope;
  {
    tree iter, prev = NULL_TREE;
+   if (DECL_NAMESPACE_ALIAS (scope))
+     scope = DECL_NAMESPACE_ALIAS (scope);
+   
    for (iter = IDENTIFIER_NAMESPACE_BINDINGS (name); iter;
         iter = TREE_CHAIN (iter))
      {
*************** binding_for_name (name, scope)
*** 1678,1683 ****
--- 1684,1693 ----
  {
    tree b = IDENTIFIER_NAMESPACE_BINDINGS (name);
    tree result;
+ 
+   if (DECL_NAMESPACE_ALIAS (scope))
+     scope = DECL_NAMESPACE_ALIAS (scope);
+   
    if (b && TREE_CODE (b) != CPLUS_BINDING)
      {
        /* Get rid of optimization for global scope. */
*************** push_namespace (name)
*** 1783,1789 ****
        /* Check whether this is an extended namespace definition. */
        d = IDENTIFIER_NAMESPACE_VALUE (name);
        if (d != NULL_TREE && TREE_CODE (d) == NAMESPACE_DECL)
! 	need_new = 0;
      }
    
    if (need_new)
--- 1793,1807 ----
        /* Check whether this is an extended namespace definition. */
        d = IDENTIFIER_NAMESPACE_VALUE (name);
        if (d != NULL_TREE && TREE_CODE (d) == NAMESPACE_DECL)
!         {
!           need_new = 0;
!           if (DECL_NAMESPACE_ALIAS (d))
!             {
!               cp_error ("namespace alias `%D' not allowed here, assuming `%D'",
!                         d, DECL_NAMESPACE_ALIAS (d));
!               d = DECL_NAMESPACE_ALIAS (d);
!             }
!         }
      }
    
    if (need_new)
*************** identifier_type_value (id)
*** 2145,2151 ****
      return REAL_IDENTIFIER_TYPE_VALUE (id);
    /* Have to search for it. It must be on the global level, now.
       Ask lookup_name not to return non-types. */
!   id = lookup_name_real (id, 2, 1);
    if (id)
      return TREE_TYPE (id);
    return NULL_TREE;
--- 2163,2169 ----
      return REAL_IDENTIFIER_TYPE_VALUE (id);
    /* Have to search for it. It must be on the global level, now.
       Ask lookup_name not to return non-types. */
!   id = lookup_name_real (id, 2, 1, 0);
    if (id)
      return TREE_TYPE (id);
    return NULL_TREE;
*************** make_typename_type (context, name)
*** 4680,4691 ****
  /* Select the right _DECL from multiple choices. */
  
  static tree
! select_decl (binding, prefer_type)
       tree binding;
       int prefer_type;
  {
    tree val;
    val = BINDING_VALUE (binding);
    /* If we could have a type and
       we have nothing or we need a type and have none.  */
    if (BINDING_TYPE (binding)
--- 4698,4717 ----
  /* Select the right _DECL from multiple choices. */
  
  static tree
! select_decl (binding, prefer_type, namespaces_only)
       tree binding;
       int prefer_type;
  {
    tree val;
    val = BINDING_VALUE (binding);
+   if (namespaces_only)
+     {
+       /* We are not interested in types. */
+       if (val && TREE_CODE (val) == NAMESPACE_DECL)
+         return val;
+       return NULL_TREE;
+     }
+   
    /* If we could have a type and
       we have nothing or we need a type and have none.  */
    if (BINDING_TYPE (binding)
*************** select_decl (binding, prefer_type)
*** 4713,4727 ****
     using IDENTIFIER_CLASS_VALUE.  */
  
  static tree
! lookup_name_real (name, prefer_type, nonclass)
       tree name;
!      int prefer_type, nonclass;
  {
    register tree val;
    int yylex = 0;
    tree from_obj = NULL_TREE;
    tree locval, classval;
  
    if (prefer_type == -2)
      {
        extern int looking_for_typename;
--- 4739,4757 ----
     using IDENTIFIER_CLASS_VALUE.  */
  
  static tree
! lookup_name_real (name, prefer_type, nonclass, namespaces_only)
       tree name;
!      int prefer_type, nonclass, namespaces_only;
  {
    register tree val;
    int yylex = 0;
    tree from_obj = NULL_TREE;
    tree locval, classval;
  
+   /* Hack: copy flag set by parser, if set. */
+   if (only_namespace_names)
+     namespaces_only = 1;
+   
    if (prefer_type == -2)
      {
        extern int looking_for_typename;
*************** lookup_name_real (name, prefer_type, non
*** 4756,4762 ****
  	      val = binding_init (&b);
  	      if (!qualified_lookup_using_namespace (name, type, val))
  		return NULL_TREE;
! 	      val = select_decl (val, prefer_type);
  	    }
  	  else if (! IS_AGGR_TYPE (type)
  		   || TREE_CODE (type) == TEMPLATE_TYPE_PARM
--- 4786,4792 ----
  	      val = binding_init (&b);
  	      if (!qualified_lookup_using_namespace (name, type, val))
  		return NULL_TREE;
! 	      val = select_decl (val, prefer_type, namespaces_only);
  	    }
  	  else if (! IS_AGGR_TYPE (type)
  		   || TREE_CODE (type) == TEMPLATE_TYPE_PARM
*************** lookup_name_real (name, prefer_type, non
*** 4800,4806 ****
  
    locval = classval = NULL_TREE;
  
!   if (!current_binding_level->namespace_p
        && IDENTIFIER_LOCAL_VALUE (name)
        /* Kludge to avoid infinite recursion with identifier_type_value.  */
        && (prefer_type <= 0
--- 4830,4836 ----
  
    locval = classval = NULL_TREE;
  
!   if (!namespaces_only && !current_binding_level->namespace_p
        && IDENTIFIER_LOCAL_VALUE (name)
        /* Kludge to avoid infinite recursion with identifier_type_value.  */
        && (prefer_type <= 0
*************** lookup_name_real (name, prefer_type, non
*** 4885,4891 ****
  	      val = NULL_TREE;
  	      break;
  	    }
! 	  val = select_decl (b, prefer_type);
  	  if (scope == global_namespace)
  	    break;
  	  scope = DECL_CONTEXT (scope);
--- 4915,4921 ----
  	      val = NULL_TREE;
  	      break;
  	    }
! 	  val = select_decl (b, prefer_type, namespaces_only);
  	  if (scope == global_namespace)
  	    break;
  	  scope = DECL_CONTEXT (scope);
*************** tree
*** 4932,4938 ****
  lookup_name_nonclass (name)
       tree name;
  {
!   return lookup_name_real (name, 0, 1);
  }
  
  tree
--- 4962,4968 ----
  lookup_name_nonclass (name)
       tree name;
  {
!   return lookup_name_real (name, 0, 1, 0);
  }
  
  tree
*************** lookup_function_nonclass (name, args)
*** 4944,4954 ****
  }
  
  tree
  lookup_name (name, prefer_type)
       tree name;
       int prefer_type;
  {
!   return lookup_name_real (name, prefer_type, 0);
  }
  
  /* Similar to `lookup_name' but look only at current binding level.  */
--- 4974,4992 ----
  }
  
  tree
+ lookup_name_namespace_only (name)
+      tree name;
+ {
+   /* type-or-namespace, nonclass, namespace_only */
+   return lookup_name_real (name, 1, 1, 1);
+ }
+ 
+ tree
  lookup_name (name, prefer_type)
       tree name;
       int prefer_type;
  {
!   return lookup_name_real (name, prefer_type, 0, 0);
  }
  
  /* Similar to `lookup_name' but look only at current binding level.  */
*************** lookup_name_current_level (name)
*** 4985,4990 ****
--- 5023,5040 ----
      }
  
    return t;
+ }
+ 
+ void
+ begin_only_namespace_names ()
+ {
+   only_namespace_names = 1;
+ }
+ 
+ void
+ end_only_namespace_names ()
+ {
+   only_namespace_names = 0;
  }
  
  /* Arrange for the user to get a source line number, even when the
Index: decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.80
diff -c -p -r1.80 decl2.c
*** decl2.c	1998/06/01 18:25:32	1.80
--- decl2.c	1998/06/02 19:16:53
*************** set_decl_namespace (decl, scope)
*** 4003,4008 ****
--- 4003,4012 ----
    tree old;
    if (scope == std_node)
      scope = global_namespace;
+   /* Get rid of namespace aliases. */
+   if (DECL_NAMESPACE_ALIAS (scope))
+     scope = DECL_NAMESPACE_ALIAS (scope);
+   
    if (!is_namespace_ancestor (current_namespace, scope))
      cp_error ("declaration of `%D' not in a namespace surrounding `%D'",
  	      decl, scope);
*************** do_namespace_alias (alias, namespace)
*** 4345,4371 ****
       tree alias, namespace;
  {
    tree binding;
!   tree ns;
!   if (TREE_CODE (namespace) == IDENTIFIER_NODE)
!     ns = lookup_name (namespace, 1);
!   else
!     ns = namespace;
!   if (TREE_CODE (ns) != NAMESPACE_DECL)
      {
!       cp_error ("`%D' is not a namespace", namespace);
        return;
      }
    binding = binding_for_name (alias, current_namespace);
!   if (BINDING_VALUE (binding) && BINDING_VALUE (binding) != namespace)
      {
        cp_error ("invalid namespace alias `%D'", alias);
!       cp_error_at ("`%D' previously declared here", alias);
      }
    else
      {
!       /* XXX the alias is not exactly identical to the name space,
! 	 it must not be used in a using directive or namespace alias */
!       BINDING_VALUE (binding) = ns;
      }
  }
  
--- 4349,4384 ----
       tree alias, namespace;
  {
    tree binding;
!   tree old;
! 
!   if (TREE_CODE (namespace) != NAMESPACE_DECL)
      {
!       /* The parser did not find it, so it's not there. */
!       cp_error ("unknown namespace `%D'", namespace);
        return;
      }
+ 
+   if (DECL_NAMESPACE_ALIAS (namespace))
+     namespace = DECL_NAMESPACE_ALIAS (namespace);
+ 
    binding = binding_for_name (alias, current_namespace);
!   old = BINDING_VALUE (binding);
!   if (old)
      {
+       if (TREE_CODE (old) == NAMESPACE_DECL
+           && DECL_NAMESPACE_ALIAS (old) == namespace)
+         /* Ok: redeclaration. */
+         return;
        cp_error ("invalid namespace alias `%D'", alias);
!       cp_error_at ("`%D' previously declared here", old);
      }
    else
      {
!       /* Build the alias. */
!       alias = build_lang_decl (NAMESPACE_DECL, alias, void_type_node);     
!       DECL_NAMESPACE_ALIAS (alias) = namespace;
!       DECL_CONTEXT (alias) = DECL_CONTEXT (namespace);
!       BINDING_VALUE (binding) = alias;
      }
  }
  
*************** do_using_directive (namespace)
*** 4502,4508 ****
        sorry ("using directives inside functions");
        return;
      }
!   /* using A::B::C; */
    if (TREE_CODE (namespace) == SCOPE_REF)
        namespace = TREE_OPERAND (namespace, 1);
    if (TREE_CODE (namespace) == IDENTIFIER_NODE)
--- 4515,4521 ----
        sorry ("using directives inside functions");
        return;
      }
!   /* using namespace A::B::C; */
    if (TREE_CODE (namespace) == SCOPE_REF)
        namespace = TREE_OPERAND (namespace, 1);
    if (TREE_CODE (namespace) == IDENTIFIER_NODE)
*************** do_using_directive (namespace)
*** 4516,4521 ****
--- 4529,4536 ----
        cp_error ("`%T' is not a namespace", namespace);
        return;
      }
+   if (DECL_NAMESPACE_ALIAS (namespace))
+     namespace = DECL_NAMESPACE_ALIAS (namespace);
    /* direct usage */
    add_using_namespace (current_namespace, namespace, 0);
  }
Index: error.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/error.c,v
retrieving revision 1.44
diff -c -p -r1.44 error.c
*** error.c	1998/05/26 12:55:05	1.44
--- error.c	1998/06/02 19:16:55
*************** dump_decl (t, v)
*** 726,731 ****
--- 726,737 ----
        OB_PUTID (DECL_NAME (t));
        break;
  
+     case SCOPE_REF:
+       dump_decl (TREE_OPERAND (t, 0), 0);
+       OB_PUTS ("::");
+       dump_decl (TREE_OPERAND (t, 1), 0);
+       break;      
+ 
      case ARRAY_REF:
        dump_decl (TREE_OPERAND (t, 0), v);
        OB_PUTC ('[');
Index: parse.y
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/parse.y,v
retrieving revision 1.60
diff -c -p -r1.60 parse.y
*** parse.y	1998/05/27 01:25:47	1.60
--- parse.y	1998/06/02 19:16:57
*************** extdef:
*** 401,418 ****
  		{ push_namespace (NULL_TREE); }
  	  extdefs_opt '}'
  		{ pop_namespace (); }
! 	| NAMESPACE identifier '=' any_id ';'
! 		{ do_namespace_alias ($2, $4); }
  	| using_decl ';'
  		{ do_toplevel_using_decl ($1); }
! 	| USING NAMESPACE any_id ';'
  		{
  		  /* If no declaration was found, the using-directive is
  		     invalid. Since that was not reported, we need the
  		     identifier for the error message. */
! 		  if (TREE_CODE ($3) == IDENTIFIER_NODE && lastiddecl)
! 		    $3 = lastiddecl;
! 		  do_using_directive ($3);
  		}
  	| extension extdef
  		{ pedantic = $<itype>1; }
--- 401,428 ----
  		{ push_namespace (NULL_TREE); }
  	  extdefs_opt '}'
  		{ pop_namespace (); }
! 	| NAMESPACE identifier '=' 
!                 { begin_only_namespace_names (); }
!                 any_id ';'
! 		{
! 		  end_only_namespace_names ();
! 		  if (lastiddecl)
! 		    $5 = lastiddecl;
! 		  do_namespace_alias ($2, $5);
! 		}
  	| using_decl ';'
  		{ do_toplevel_using_decl ($1); }
! 	| USING NAMESPACE
! 		{ begin_only_namespace_names (); }
! 		any_id ';'
  		{
+ 		  end_only_namespace_names ();
  		  /* If no declaration was found, the using-directive is
  		     invalid. Since that was not reported, we need the
  		     identifier for the error message. */
! 		  if (TREE_CODE ($4) == IDENTIFIER_NODE && lastiddecl)
! 		    $4 = lastiddecl;
! 		  do_using_directive ($4);
  		}
  	| extension extdef
  		{ pedantic = $<itype>1; }
Index: typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.75
diff -c -p -r1.75 typeck.c
*** typeck.c	1998/06/01 18:25:35	1.75
--- typeck.c	1998/06/02 19:17:00
*************** convert_arguments (return_loc, typelist,
*** 2957,2962 ****
--- 2957,2965 ----
  	  /* Strip the `&' from an overloaded FUNCTION_DECL.  */
  	  if (TREE_CODE (val) == ADDR_EXPR)
  	    val = TREE_OPERAND (val, 0);
+ 	  /* Strip all list nodes to get down to OVERLOAD node if present. */
+ 	  while (val && TREE_CODE (val) == TREE_LIST)
+ 	    val = TREE_VALUE (val);
  	  if (really_overloaded_fn (val))
  	    cp_error ("insufficient type information to resolve address of overloaded function `%D'",
  		      DECL_NAME (get_first_fn (val)));
--- /dev/null	Tue Jun  2 20:54:31 1998
+++ g++.ns/alias3.C	Tue Jun  2 19:24:34 1998
@@ -0,0 +1,30 @@
+namespace A{
+  struct X{};
+  void f(X&);
+  extern int i;
+  namespace a_very_long_namespace_name{
+    int k;
+  }
+}
+
+namespace B = A;
+namespace B = A;
+namespace B = B;
+
+namespace avl = A::a_very_long_namespace_name;
+
+void B::f(A::X& x)
+{
+  B::f(x);
+  f(x);
+  avl::k = 1;
+}
+
+int B::i = 0;
+
+int main()
+{
+  B::X x;
+  if (B::i)
+    A::f(x);
+}
--- /dev/null	Tue Jun  2 20:54:31 1998
+++ g++.ns/alias4.C	Tue Jun  2 19:40:36 1998
@@ -0,0 +1,13 @@
+namespace A = B;  // ERROR - unknown namespace
+
+namespace C{}
+namespace D = C;  
+namespace D {     // ERROR - reopening namespace with alias
+  void f();
+}
+
+void C::f(){}     // ERROR - previous definition
+
+void D::f(){}     // ERROR - redefinition
+
+namespace E = C::F; // ERROR - unknown namespace



More information about the Gcc-patches mailing list