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]
Other format: [Raw text]

Re: [C++ PATCH] Fix friend class name lookup part 3/n (PR3332)


The attached patch is the version I am checking in.  It has
the resume_scope changes suggested by Mark and the
push_inner_scope changes.  The push_inner_scope now obtains
current_scope () by itself and call push_inner_scope_r.  We
still need this two param (OUTER, INNER) version because of
recursion.

--Kriang


Nathan Sidwell wrote:


Nathan Sidwell wrote:


This looks ok. I presume that we could migtate push_scope & pop_scope to

use this new interface, and remove the OUTER param from push_inner_scope

(it's always current_scope (), right?).


I'd like to run this by Mark, just to make sure.



I've discussed this with Mark, and he noticed you've replaced a


push_decl_namespace call with push_namespace (DECL_NAME (...)), which

forces us to do name lookup. Mark suggests that what is wanted here is

not ...

+

+ push_namespace (DECL_NAME (inner));

+

+ /* Restore template parameter scopes. */

but

resume_scope (NAMESPACE_LEVEL (inner))

current_namespace = inner


which looks good to me. Could you verify that that works, and if so


check the patch in. Thanks.


nathan




diff -cprN gcc-main-save/gcc/cp/name-lookup.c gcc-main-new/gcc/cp/name-lookup.c
*** gcc-main-save/gcc/cp/name-lookup.c	Thu Nov 25 23:12:08 2004
--- gcc-main-new/gcc/cp/name-lookup.c	Wed Nov 24 23:32:20 2004
*************** is_ancestor (tree root, tree child)
*** 2537,2544 ****
      }
  }
  
! /* Enter the class or namespace scope indicated by T.  Returns TRUE iff
!    pop_scope should be called later to exit this scope.  */
  
  bool
  push_scope (tree t)
--- 2537,2546 ----
      }
  }
  
! /* Enter the class or namespace scope indicated by T suitable for
!    name lookup.  T can be arbitrary scope, not necessary nested inside
!    the current scope.  Returns TRUE iff pop_scope should be called
!    later to exit this scope.  */
  
  bool
  push_scope (tree t)
*************** pop_scope (tree t)
*** 2573,2578 ****
--- 2575,2684 ----
    else if CLASS_TYPE_P (t)
      pop_nested_class ();
  }
+ 
+ /* Subroutine of push_inner_scope.  */
+ 
+ static void
+ push_inner_scope_r (tree outer, tree inner)
+ {
+   tree prev;
+ 
+   if (outer == inner
+       || (TREE_CODE (inner) != NAMESPACE_DECL && !CLASS_TYPE_P (inner)))
+     return;
+ 
+   prev = CP_DECL_CONTEXT (TREE_CODE (inner) == NAMESPACE_DECL ? inner : TYPE_NAME (inner));
+   if (outer != prev)
+     push_inner_scope_r (outer, prev);
+   if (TREE_CODE (inner) == NAMESPACE_DECL)
+     {
+       struct cp_binding_level *save_template_parm = 0;
+       /* Temporary take out template parameter scopes.  They are saved
+ 	 in reversed order in save_template_parm.  */
+       while (current_binding_level->kind == sk_template_parms)
+ 	{
+ 	  struct cp_binding_level *b = current_binding_level;
+ 	  current_binding_level = b->level_chain;
+ 	  b->level_chain = save_template_parm;
+ 	  save_template_parm = b;
+ 	}
+ 
+       resume_scope (NAMESPACE_LEVEL (inner));
+       current_namespace = inner;
+ 
+       /* Restore template parameter scopes.  */
+       while (save_template_parm)
+ 	{
+ 	  struct cp_binding_level *b = save_template_parm;
+ 	  save_template_parm = b->level_chain;
+ 	  b->level_chain = current_binding_level;
+ 	  current_binding_level = b;
+ 	}
+     }
+   else
+     pushclass (inner);
+ }
+ 
+ /* Enter the scope INNER from current scope.  INNER must be a scope
+    nested inside current scope.  This works with both name lookup and
+    pushing name into scope.  In case a template parameter scope is present,
+    namespace is pushed under the template parameter scope according to
+    name lookup rule in 14.6.1/6.
+    
+    Return the former current scope suitable for pop_inner_scope.  */
+ 
+ tree
+ push_inner_scope (tree inner)
+ {
+   tree outer = current_scope ();
+   if (!outer)
+     outer = current_namespace;
+ 
+   push_inner_scope_r (outer, inner);
+   return outer;
+ }
+ 
+ /* Exit the current scope INNER back to scope OUTER.  */
+ 
+ void
+ pop_inner_scope (tree outer, tree inner)
+ {
+   if (outer == inner
+       || (TREE_CODE (inner) != NAMESPACE_DECL && !CLASS_TYPE_P (inner)))
+     return;
+ 
+   while (outer != inner)
+     {
+       if (TREE_CODE (inner) == NAMESPACE_DECL)
+ 	{
+ 	  struct cp_binding_level *save_template_parm = 0;
+ 	  /* Temporary take out template parameter scopes.  They are saved
+ 	     in reversed order in save_template_parm.  */
+ 	  while (current_binding_level->kind == sk_template_parms)
+ 	    {
+ 	      struct cp_binding_level *b = current_binding_level;
+ 	      current_binding_level = b->level_chain;
+ 	      b->level_chain = save_template_parm;
+ 	      save_template_parm = b;
+ 	    }
+ 
+ 	  pop_namespace ();
+ 
+ 	  /* Restore template parameter scopes.  */
+ 	  while (save_template_parm)
+ 	    {
+ 	      struct cp_binding_level *b = save_template_parm;
+ 	      save_template_parm = b->level_chain;
+ 	      b->level_chain = current_binding_level;
+ 	      current_binding_level = b;
+ 	    }
+ 	}
+       else
+ 	popclass ();
+ 
+       inner = CP_DECL_CONTEXT (TREE_CODE (inner) == NAMESPACE_DECL ? inner : TYPE_NAME (inner));
+     }
+ }
  
  /* Do a pushlevel for class declarations.  */
  
*************** lookup_name (tree name, int prefer_type)
*** 4120,4133 ****
  
  /* Look up NAME for type used in elaborated name specifier in
     the scopes given by SCOPE.  SCOPE can be either TS_CURRENT or
!    TS_WITHIN_ENCLOSING_NON_CLASS (possibly more scope is checked if 
!    cleanup or template parameter scope is encountered).
  
     Unlike lookup_name_real, we make sure that NAME is actually
!    declared in the desired scope, not from inheritance, using 
!    declaration, nor using directive.  A TYPE_DECL best matching
!    the NAME is returned.  Catching error and issuing diagnostics
!    are caller's responsibility.  */
  
  tree
  lookup_type_scope (tree name, tag_scope scope)
--- 4226,4242 ----
  
  /* Look up NAME for type used in elaborated name specifier in
     the scopes given by SCOPE.  SCOPE can be either TS_CURRENT or
!    TS_WITHIN_ENCLOSING_NON_CLASS.  Although not implied by the
!    name, more scopes are checked if cleanup or template parameter
!    scope is encountered.
  
     Unlike lookup_name_real, we make sure that NAME is actually
!    declared in the desired scope, not from inheritance, nor using
!    directive.  For using declaration, there is DR138 still waiting
!    to be resolved.
! 
!    A TYPE_DECL best matching the NAME is returned.  Catching error
!    and issuing diagnostics are caller's responsibility.  */
  
  tree
  lookup_type_scope (tree name, tag_scope scope)
*************** lookup_type_scope (tree name, tag_scope 
*** 4177,4188 ****
  	  /* If this is the kind of thing we're looking for, we're done.
  	     Ignore names found via using declaration.  See DR138 for
  	     current status.  */
! 	  if (qualify_lookup (iter->type, LOOKUP_PREFER_TYPES)
! 	      && (CP_DECL_CONTEXT (iter->type) == iter->scope->this_entity))
  	    val = iter->type;
! 	  else if (qualify_lookup (iter->value, LOOKUP_PREFER_TYPES)
! 		   && (CP_DECL_CONTEXT (iter->value)
! 		       == iter->scope->this_entity))
  	    val = iter->value;
  	}
  	
--- 4286,4294 ----
  	  /* If this is the kind of thing we're looking for, we're done.
  	     Ignore names found via using declaration.  See DR138 for
  	     current status.  */
! 	  if (qualify_lookup (iter->type, LOOKUP_PREFER_TYPES))
  	    val = iter->type;
! 	  else if (qualify_lookup (iter->value, LOOKUP_PREFER_TYPES))
  	    val = iter->value;
  	}
  	
diff -cprN gcc-main-save/gcc/cp/name-lookup.h gcc-main-new/gcc/cp/name-lookup.h
*** gcc-main-save/gcc/cp/name-lookup.h	Thu Nov 25 23:12:08 2004
--- gcc-main-new/gcc/cp/name-lookup.h	Wed Nov 24 23:23:48 2004
*************** extern void keep_next_level (bool);
*** 306,311 ****
--- 306,313 ----
  extern bool is_ancestor (tree, tree);
  extern bool push_scope (tree);
  extern void pop_scope (tree);
+ extern tree push_inner_scope (tree);
+ extern void pop_inner_scope (tree, tree);
  extern void push_binding_level (struct cp_binding_level *);
  
  extern void push_namespace (tree);
diff -cprN gcc-main-save/gcc/cp/parser.c gcc-main-new/gcc/cp/parser.c
*** gcc-main-save/gcc/cp/parser.c	Thu Nov 25 23:12:08 2004
--- gcc-main-new/gcc/cp/parser.c	Wed Nov 24 23:31:41 2004
*************** cp_parser_class_specifier (cp_parser* pa
*** 12237,12243 ****
    int has_trailing_semicolon;
    bool nested_name_specifier_p;
    unsigned saved_num_template_parameter_lists;
!   bool pop_p = false;
    tree scope = NULL_TREE;
  
    push_deferring_access_checks (dk_no_deferred);
--- 12237,12243 ----
    int has_trailing_semicolon;
    bool nested_name_specifier_p;
    unsigned saved_num_template_parameter_lists;
!   tree old_scope = NULL_TREE;
    tree scope = NULL_TREE;
  
    push_deferring_access_checks (dk_no_deferred);
*************** cp_parser_class_specifier (cp_parser* pa
*** 12276,12282 ****
    if (nested_name_specifier_p)
      {
        scope = CP_DECL_CONTEXT (TYPE_MAIN_DECL (type));
!       pop_p = push_scope (scope);
      }
    type = begin_class_definition (type);
  
--- 12276,12282 ----
    if (nested_name_specifier_p)
      {
        scope = CP_DECL_CONTEXT (TYPE_MAIN_DECL (type));
!       old_scope = push_inner_scope (scope);
      }
    type = begin_class_definition (type);
  
*************** cp_parser_class_specifier (cp_parser* pa
*** 12301,12308 ****
      }
    if (type != error_mark_node)
      type = finish_struct (type, attributes);
!   if (pop_p)
!     pop_scope (scope);
    /* If this class is not itself within the scope of another class,
       then we need to parse the bodies of all of the queued function
       definitions.  Note that the queued functions defined in a class
--- 12301,12308 ----
      }
    if (type != error_mark_node)
      type = finish_struct (type, attributes);
!   if (nested_name_specifier_p)
!     pop_inner_scope (old_scope, scope);
    /* If this class is not itself within the scope of another class,
       then we need to parse the bodies of all of the queued function
       definitions.  Note that the queued functions defined in a class
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/lookup/friend3.C gcc-main-new/gcc/testsuite/g++.dg/lookup/friend3.C
*** gcc-main-save/gcc/testsuite/g++.dg/lookup/friend3.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/lookup/friend3.C	Wed Nov 24 23:19:42 2004
***************
*** 0 ****
--- 1,19 ----
+ // Copyright (C) 2004 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+ // { dg-do compile }
+ 
+ // Friend name lookup in class defined outside its namespace
+ 
+ namespace A {
+   class B;
+   class C;
+ }
+ 
+ class A::B {
+   friend class C;
+   typedef int i;
+ };
+ 
+ class A::C {
+   A::B::i j;
+ };
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/lookup/friend4.C gcc-main-new/gcc/testsuite/g++.dg/lookup/friend4.C
*** gcc-main-save/gcc/testsuite/g++.dg/lookup/friend4.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/lookup/friend4.C	Wed Nov 24 23:19:42 2004
***************
*** 0 ****
--- 1,22 ----
+ // Copyright (C) 2004 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+ // { dg-do compile }
+ 
+ // Friend name lookup in class defined outside its namespace
+ // (Local class case)
+ 
+ void f() {
+   class A {
+     class B;
+     class C;
+   };
+ 
+   class A::B {
+     friend class C;
+     typedef int i;
+   };
+ 
+   class A::C {
+     A::B::i j;
+   };
+ }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/lookup/friend5.C gcc-main-new/gcc/testsuite/g++.dg/lookup/friend5.C
*** gcc-main-save/gcc/testsuite/g++.dg/lookup/friend5.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/lookup/friend5.C	Wed Nov 24 23:19:42 2004
***************
*** 0 ****
--- 1,34 ----
+ // { dg-do compile }
+ 
+ // Origin: aroach@stoic.electriceyeball.com
+ 
+ // PR c++/3332: Friend function lookup in class defined outside its
+ // namespace
+ 
+ namespace N
+ {
+   class A;
+ }
+ 
+ class N::A
+ {
+   void x();
+   friend void func(void);
+ };
+ 
+ namespace N
+ {
+   void func(void);
+ }
+ 
+ void N::func(void)
+ {
+   N::A a;
+   a.x();
+ }
+ 
+ int main()
+ {
+   return 0;
+ }
+ 

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