C++ PATCHes for using decls/arrays

Mark Mitchell mark@markmitchell.com
Thu Jan 21 21:16:00 GMT 1999


Brendan turned up a couple more regressions:

We issued a bogus error on:

  template <int x> int foo(char[4][x]) { return x; }
  int (*bar)(char[4][3]) = &foo;

And failed to issue an error on:

  namespace foo
  {
    void x (bool);
    void x (char);
    void x (int);
    void x (double);
  }

  namespace baz { void x (int); }

  void fn (int i)
  {
    using foo::x;
    using baz::x;
    x(i); 	
  }

Some of the handling of using declarations was a little suspect in
that it was relying on what was essentially a bug in dupliate_decls.
I've cleaned it up.

-- 
Mark Mitchell 			mark@markmitchell.com
Mark Mitchell Consulting	http://www.markmitchell.com

1999-01-21  Mark Mitchell  <mark@markmitchell.com>

	* cp-tree.h (PUSH_GLOBAL): New macro.
	(PUSH_LOCAL): Likewise.
	(PUSH_USING): Likewise.
	(namespace_bindings_p): Declare.
	(push_overloaded_decl): Likewise.
	* decl.c (push_overloaded_decl): Don't make it static.  Check for
	illegal declarations after using declarations here.
	(namespace_bindings_p): Likewise.
	(duplicate_decls): Don't consider declarations from different
	namespaces to be the same.
	(pushdecl): Use symbolic PUSH_ constants in calls to
	push_overloaded_decl.
	(push_overloaded_decl_1): Likewise.
	* decl2.c (validate_nonmember_using_decl): Tweak `std' handling. 
	(do_nonmember_using_decl): Check for illegal using declarations
	after ordinary declarations here.
	(do_local_using_decl): Call pushdecl to insert declarations.

	* tree.c (build_cplus_array_type_1): Don't call build_array_type
	for types involving template parameters.

Index: testsuite/g++.old-deja/g++.ns/using12.C
===================================================================
RCS file: using12.C
diff -N using12.C
*** /dev/null	Sat Dec  5 20:30:03 1998
--- using12.C	Thu Jan 21 21:02:03 1999
***************
*** 0 ****
--- 1,19 ----
+ // Build don't link:
+ // Origin: Brendan Kehoe <brendan@cygnus.com>
+ 
+ namespace foo
+ {
+   void x (bool);     // ERROR - candidates
+   void x (char);     // ERROR - candidates
+   void x (int);      // ERROR - candidates
+   void x (double);   // ERROR - candidates
+ }
+ 
+ namespace baz { void x (int); }  // ERROR - candidates
+ 
+ void fn (int i)
+ {
+   using foo::x;
+   using baz::x;
+   x(i); 	 // ERROR - ambiguous
+ }
Index: testsuite/g++.old-deja/g++.pt/array3.C
===================================================================
RCS file: array3.C
diff -N array3.C
*** /dev/null	Sat Dec  5 20:30:03 1998
--- array3.C	Thu Jan 21 21:02:04 1999
***************
*** 0 ****
--- 1,5 ----
+ // Build don't link:
+ // Origin: Brendan Kehoe <brendan@cygnus.com>
+ 
+  template <int x> int foo(char[4][x]) { return x; }
+  int (*bar)(char[4][3]) = &foo;
Index: testsuite/g++.old-deja/g++.ns/overload4.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.ns/overload4.C,v
retrieving revision 1.2
diff -c -p -r1.2 overload4.C
*** overload4.C	1998/12/16 21:51:00	1.2
--- overload4.C	1999/01/22 05:02:48
***************
*** 1,6 ****
  // Build don't link:
  namespace A{
!   void f();   // ERROR - .*
  }
  
  using A::f;
--- 1,6 ----
  // Build don't link:
  namespace A{
!   void f();  
  }
  
  using A::f;
Index: testsuite/g++.old-deja/g++.ns/overload5.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.ns/overload5.C,v
retrieving revision 1.2
diff -c -p -r1.2 overload5.C
*** overload5.C	1998/12/16 21:51:01	1.2
--- overload5.C	1999/01/22 05:02:48
***************
*** 1,6 ****
  // Build don't link:
  namespace A{
!   void f(){}         // ERROR - previous declaration
  }
  
  using A::f;
--- 1,6 ----
  // Build don't link:
  namespace A{
!   void f(){}        
  }
  
  using A::f;
Index: cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.189
diff -c -p -r1.189 cp-tree.h
*** cp-tree.h	1999/01/21 14:29:23	1.189
--- cp-tree.h	1999/01/22 04:53:16
*************** extern tree current_class_name;	/* IDENT
*** 2582,2587 ****
--- 2582,2595 ----
  				   another declaration of an existing
  				   entity is seen.  */
  
+ /* Used with push_overloaded_decl.  */
+ #define PUSH_GLOBAL          0  /* Push the DECL into namespace scope,
+ 				   regardless of the current scope.  */
+ #define PUSH_LOCAL           1  /* Push the DECL into the current
+ 				   scope.  */
+ #define PUSH_USING           2  /* We are pushing this DECL as the
+ 				   result of a using declaration.  */
+ 
  /* Returns nonzero iff TYPE1 and TYPE2 are the same type, in the usual
     sense of `same'.  */
  #define same_type_p(type1, type2) \
*************** extern tree perform_qualification_conver
*** 2692,2697 ****
--- 2700,2706 ----
  extern void set_identifier_local_value		PROTO((tree, tree));
  extern int global_bindings_p			PROTO((void));
  extern int toplevel_bindings_p			PROTO((void));
+ extern int namespace_bindings_p			PROTO((void));
  extern void keep_next_level			PROTO((void));
  extern int kept_level_p				PROTO((void));
  extern void declare_parm_level			PROTO((void));
*************** extern int check_static_variable_definit
*** 2816,2821 ****
--- 2825,2831 ----
  extern void push_local_binding                  PROTO((tree, tree));
  extern void push_class_binding                  PROTO((tree, tree));
  extern tree check_default_argument              PROTO((tree, tree));
+ extern tree push_overloaded_decl		PROTO((tree, int));
  
  /* in decl2.c */
  extern int check_java_method			PROTO((tree));
Index: decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.297
diff -c -p -r1.297 decl.c
*** decl.c	1999/01/21 14:29:26	1.297
--- decl.c	1999/01/22 04:53:25
*************** static struct stack_level *decl_stack;
*** 135,141 ****
  static tree grokparms				PROTO((tree, int));
  static tree lookup_nested_type			PROTO((tree, tree));
  static char *redeclaration_error_message	PROTO((tree, tree));
- static tree push_overloaded_decl		PROTO((tree, int));
  
  static struct stack_level *push_decl_level PROTO((struct stack_level *,
  						  struct obstack *));
--- 135,140 ----
*************** static void pop_binding_level PROTO((voi
*** 145,151 ****
  static void suspend_binding_level PROTO((void));
  static void resume_binding_level PROTO((struct binding_level *));
  static struct binding_level *make_binding_level PROTO((void));
- static int namespace_bindings_p PROTO((void));
  static void declare_namespace_level PROTO((void));
  static void signal_catch PROTO((int)) ATTRIBUTE_NORETURN;
  static void storedecls PROTO((tree));
--- 144,149 ----
*************** toplevel_bindings_p ()
*** 922,928 ****
  
  /* Nonzero if this is a namespace scope.  */
  
! static int
  namespace_bindings_p ()
  {
    return current_binding_level->namespace_p;
--- 920,926 ----
  
  /* Nonzero if this is a namespace scope.  */
  
! int
  namespace_bindings_p ()
  {
    return current_binding_level->namespace_p;
*************** duplicate_decls (newdecl, olddecl)
*** 2942,2947 ****
--- 2940,2950 ----
      }
    else if (!types_match)
      {
+       if (DECL_REAL_CONTEXT (newdecl) != DECL_REAL_CONTEXT (olddecl))
+ 	/* These are certainly not duplicate declarations; they're
+ 	   from different scopes.  */
+ 	return 0;
+ 
        if (TREE_CODE (newdecl) == TEMPLATE_DECL)
  	{
  	  /* The name of a class template may not be declared to refer to
*************** pushdecl (x)
*** 3655,3661 ****
  
        if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_FUNCTION_MEMBER_P (x))
  	{
! 	  t = push_overloaded_decl (x, 1);
  	  if (t != x || DECL_LANGUAGE (x) == lang_c)
  	    return t;
  	  if (!namespace_bindings_p ())
--- 3658,3664 ----
  
        if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_FUNCTION_MEMBER_P (x))
  	{
! 	  t = push_overloaded_decl (x, PUSH_LOCAL);
  	  if (t != x || DECL_LANGUAGE (x) == lang_c)
  	    return t;
  	  if (!namespace_bindings_p ())
*************** pushdecl (x)
*** 3665,3671 ****
  	    need_new_binding = 0;
  	}
        else if (DECL_FUNCTION_TEMPLATE_P (x) && DECL_NAMESPACE_SCOPE_P (x))
! 	return push_overloaded_decl (x, 0);
  
        /* If declaring a type as a typedef, copy the type (unless we're
  	 at line 0), and install this TYPE_DECL as the new type's typedef
--- 3668,3674 ----
  	    need_new_binding = 0;
  	}
        else if (DECL_FUNCTION_TEMPLATE_P (x) && DECL_NAMESPACE_SCOPE_P (x))
! 	return push_overloaded_decl (x, PUSH_GLOBAL);
  
        /* If declaring a type as a typedef, copy the type (unless we're
  	 at line 0), and install this TYPE_DECL as the new type's typedef
*************** push_using_directive (used)
*** 4157,4175 ****
     DECL may also be a TEMPLATE_DECL, with a FUNCTION_DECL in its DECL_RESULT
     slot.  It is dealt with the same way.
  
     The value returned may be a previous declaration if we guessed wrong
     about what language DECL should belong to (C or C++).  Otherwise,
     it's always DECL (and never something that's not a _DECL).  */
  
! static tree
! push_overloaded_decl (decl, forgettable)
       tree decl;
!      int forgettable;
  {
    tree name = DECL_NAME (decl);
    tree old;
    tree new_binding;
!   int doing_global = (namespace_bindings_p () || ! forgettable);
  
    if (doing_global)
      {
--- 4160,4184 ----
     DECL may also be a TEMPLATE_DECL, with a FUNCTION_DECL in its DECL_RESULT
     slot.  It is dealt with the same way.
  
+    FLAGS is a bitwise-or of the following values:
+      PUSH_LOCAL: Bind DECL in the current scope, rather than at
+                  namespace scope.
+      PUSH_USING: DECL is being pushed as the result of a using
+                  declaration. 
+ 
     The value returned may be a previous declaration if we guessed wrong
     about what language DECL should belong to (C or C++).  Otherwise,
     it's always DECL (and never something that's not a _DECL).  */
  
! tree
! push_overloaded_decl (decl, flags)
       tree decl;
!      int flags;
  {
    tree name = DECL_NAME (decl);
    tree old;
    tree new_binding;
!   int doing_global = (namespace_bindings_p () || !(flags & PUSH_LOCAL));
  
    if (doing_global)
      {
*************** push_overloaded_decl (decl, forgettable)
*** 4202,4210 ****
            tree tmp;
  	  
  	  for (tmp = old; tmp; tmp = OVL_NEXT (tmp))
! 	    if (decl == OVL_CURRENT (tmp) 
! 		|| duplicate_decls (decl, OVL_CURRENT (tmp)))
! 	      return OVL_CURRENT (tmp);
  	}
        else
  	{
--- 4211,4229 ----
            tree tmp;
  	  
  	  for (tmp = old; tmp; tmp = OVL_NEXT (tmp))
! 	    {
! 	      tree fn = OVL_CURRENT (tmp);
! 
! 	      if (TREE_CODE (tmp) == OVERLOAD && OVL_USED (tmp)
! 		  && !(flags & PUSH_USING)
! 		  && compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)),
! 				TYPE_ARG_TYPES (TREE_TYPE (decl))))
! 		cp_error ("`%#D' conflicts with previous using declaration `%#D'",
! 			  decl, fn);
! 	      
! 	      if (duplicate_decls (decl, fn))
! 		return fn;
! 	    }
  	}
        else
  	{
*************** static void
*** 5776,5782 ****
  push_overloaded_decl_1 (x)
       tree x;
  {
!   push_overloaded_decl (x, 0);
  }
  
  #ifdef __GNUC__
--- 5795,5801 ----
  push_overloaded_decl_1 (x)
       tree x;
  {
!   push_overloaded_decl (x, PUSH_GLOBAL);
  }
  
  #ifdef __GNUC__
Index: decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.172
diff -c -p -r1.172 decl2.c
*** decl2.c	1999/01/18 12:49:19	1.172
--- decl2.c	1999/01/22 04:53:28
*************** validate_nonmember_using_decl (decl, sco
*** 4703,4708 ****
--- 4703,4718 ----
    if (TREE_CODE (decl) == SCOPE_REF
        && TREE_OPERAND (decl, 0) == std_node)
      {
+       if (namespace_bindings_p ()
+ 	  && current_namespace == global_namespace)
+ 	/* There's no need for a using declaration at all, here,
+ 	   since `std' is the same as `::'.  We can't just pass this
+ 	   on because we'll complain later about declaring something
+ 	   in the same scope as a using declaration with the same
+ 	   name.  We return NULL_TREE which indicates to the caller
+ 	   that there's no need to do any further processing.  */
+ 	return NULL_TREE;
+ 
        *scope = global_namespace;
        *name = TREE_OPERAND (decl, 1);
      }
*************** do_nonmember_using_decl (scope, name, ol
*** 4773,4789 ****
        *newval = oldval;
        for (tmp = BINDING_VALUE (decls); tmp; tmp = OVL_NEXT (tmp))
  	{
! 	  /* Compare each new function with each old one.
! 	     If the old function was also used, there is no conflict. */
  	  for (tmp1 = oldval; tmp1; tmp1 = OVL_NEXT (tmp1))
! 	    if (OVL_CURRENT (tmp) == OVL_CURRENT (tmp1))
! 	      break;
! 	    else if (OVL_USED (tmp1))
! 	      continue;
! 	    else if (duplicate_decls (OVL_CURRENT (tmp), OVL_CURRENT (tmp1)))
! 	      return;
  
! 	  /* Duplicate use, ignore */
  	  if (tmp1)
  	    continue;
  	    
--- 4783,4819 ----
        *newval = oldval;
        for (tmp = BINDING_VALUE (decls); tmp; tmp = OVL_NEXT (tmp))
  	{
! 	  tree new_fn = OVL_CURRENT (tmp);
! 
! 	  /* [namespace.udecl]
! 
! 	     If a function declaration in namespace scope or block
! 	     scope has the same name and the same parameter types as a
! 	     function introduced by a using declaration the program is
! 	     ill-formed.  */
  	  for (tmp1 = oldval; tmp1; tmp1 = OVL_NEXT (tmp1))
! 	    {
! 	      tree old_fn = OVL_CURRENT (tmp1);
  
! 	      if (!OVL_USED (tmp1)
! 		  && compparms (TYPE_ARG_TYPES (TREE_TYPE (new_fn)),
! 				TYPE_ARG_TYPES (TREE_TYPE (old_fn))))
! 		{
! 		  /* There was already a non-using declaration in
! 		     this scope with the same parameter types.  */
! 		  cp_error ("`%D' is already declared in this scope",
! 			    name);
! 		  break;
! 		}
! 	      else if (duplicate_decls (new_fn, old_fn))
! 		/* We're re-using something we already used 
! 		   before.  We don't need to add it again.  */ 
! 		break;
! 	    }
! 
! 	  /* If we broke out of the loop, there's no reason to add
! 	     this function to the using declarations for this
! 	     scope.  */
  	  if (tmp1)
  	    continue;
  	    
*************** do_local_using_decl (decl)
*** 4856,4862 ****
    do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype);
  
    if (newval)
!     push_local_binding (name, newval);
    if (newtype)
      set_identifier_type_value (name, newtype);
  }
--- 4886,4905 ----
    do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype);
  
    if (newval)
!     {
!       if (is_overloaded_fn (newval))
! 	{
! 	  tree fn;
! 
! 	  /* We only need to push declarations for those functions
! 	     that were not already bound in the current level.  */
! 	  for (fn = newval; fn != oldval; fn = OVL_NEXT (fn))
! 	    push_overloaded_decl (OVL_CURRENT (fn), 
! 				  PUSH_LOCAL | PUSH_USING);
! 	}
!       else
! 	push_local_binding (name, newval);
!     }
    if (newtype)
      set_identifier_type_value (name, newtype);
  }
Index: tree.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/tree.c,v
retrieving revision 1.91
diff -c -p -r1.91 tree.c
*** tree.c	1999/01/21 14:29:32	1.91
--- tree.c	1999/01/22 04:53:37
*************** build_cplus_array_type_1 (elt_type, inde
*** 416,422 ****
        saveable_obstack = &permanent_obstack;
      }
  
!   if (processing_template_decl)
      {
        t = make_node (ARRAY_TYPE);
        TREE_TYPE (t) = elt_type;
--- 416,424 ----
        saveable_obstack = &permanent_obstack;
      }
  
!   if (processing_template_decl 
!       || uses_template_parms (elt_type) 
!       || uses_template_parms (index_type))
      {
        t = make_node (ARRAY_TYPE);
        TREE_TYPE (t) = elt_type;



More information about the Gcc-patches mailing list