Friend class name lookup 2/n, PR c++/14513, c++/15410
authorKriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
Thu, 25 Nov 2004 16:55:34 +0000 (16:55 +0000)
committerKriang Lerdsuwanakij <lerdsuwa@gcc.gnu.org>
Thu, 25 Nov 2004 16:55:34 +0000 (16:55 +0000)
Friend class name lookup 2/n, PR c++/14513, c++/15410
* name-lookup.c (lookup_name_real): Simplify.
(lookup_type_scope): Add SCOPE parameter.  Handle friend class
lookup.
* name-lookup.h (tag_scope): New enum type.
(lookup_type_scope): Adjust declaration.
* decl.c (lookup_and_check_tag, xref_tag, xref_tag_from_type):
Change bool parameter GLOBALIZED to TAG_SCOPE parameter SCOPE.
(start_enum): Likewise.  Add assertion test that NAME is
IDENTIFIER_NODE.  Use anonymous name for dummy ENUMERAL_TYPE in
case of error.
* cp-tree.h (xref_tag, xref_tag_from_type): Adjust declarations.
* parser.c (cp_parser_elaborated_type_specifier,
cp_parser_class_head): Adjust call to xref_tag.
* pt.c (lookup_template_class, instantiate_class_template):
Likewise.
* rtti.c (init_rtti_processing, build_dynamic_cast_1,
tinfo_base_init, emit_support_tinfos): Likewise.

* g++.dg/lookup/friend2.C: New test.
* g++.dg/template/friend31.C: Likewise.

From-SVN: r91299

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/rtti.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/lookup/friend2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/friend31.C [new file with mode: 0644]

index 1b89a1d3ba4e2087c170d292648815f4f332c2b6..8acfe55b86ba5499ab7b7aa7d08a41f682491a21 100644 (file)
@@ -1,3 +1,24 @@
+2004-11-25  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>
+
+       Friend class name lookup 2/n, PR c++/14513, c++/15410
+       * name-lookup.c (lookup_name_real): Simplify.
+       (lookup_type_scope): Add SCOPE parameter.  Handle friend class
+       lookup.
+       * name-lookup.h (tag_scope): New enum type.
+       (lookup_type_scope): Adjust declaration.
+       * decl.c (lookup_and_check_tag, xref_tag, xref_tag_from_type):
+       Change bool parameter GLOBALIZED to TAG_SCOPE parameter SCOPE.
+       (start_enum): Likewise.  Add assertion test that NAME is 
+       IDENTIFIER_NODE.  Use anonymous name for dummy ENUMERAL_TYPE in
+       case of error.
+       * cp-tree.h (xref_tag, xref_tag_from_type): Adjust declarations.
+       * parser.c (cp_parser_elaborated_type_specifier,
+       cp_parser_class_head): Adjust call to xref_tag.
+       * pt.c (lookup_template_class, instantiate_class_template):
+       Likewise.
+       * rtti.c (init_rtti_processing, build_dynamic_cast_1,
+       tinfo_base_init, emit_support_tinfos): Likewise.
+
 2004-11-25  Joseph S. Myers  <joseph@codesourcery.com>
 
        * g++spec.c, lex.c: Avoid ` as left quote in diagnostics.
index 64f5ab9b8ada59cb8cffd31db900ed9566a1f974..0f0bfb290679c55a80eb47421629c3202a91123f 100644 (file)
@@ -3745,8 +3745,8 @@ extern tree get_scope_of_declarator             (const cp_declarator *);
 extern void grok_special_member_properties     (tree);
 extern int grok_ctor_properties                        (tree, tree);
 extern bool grok_op_properties                 (tree, int, bool);
-extern tree xref_tag                           (enum tag_types, tree, bool, bool);
-extern tree xref_tag_from_type                 (tree, tree, int);
+extern tree xref_tag                           (enum tag_types, tree, tag_scope, bool);
+extern tree xref_tag_from_type                 (tree, tree, tag_scope);
 extern void xref_basetypes                     (tree, tree);
 extern tree start_enum                         (tree);
 extern void finish_enum                                (tree);
index c47c342bc6f8612cc39ae7b958da50dbd45e5dc9..98ca4f944ad870d56e0268ccbcd3a90adb066a7e 100644 (file)
@@ -82,7 +82,7 @@ static int typename_compare (const void *, const void *);
 static tree local_variable_p_walkfn (tree *, int *, void *);
 static tree record_builtin_java_type (const char *, int);
 static const char *tag_name (enum tag_types);
-static tree lookup_and_check_tag (enum tag_types, tree, bool globalize, bool);
+static tree lookup_and_check_tag (enum tag_types, tree, tag_scope, bool);
 static int walk_namespaces_r (tree, walk_namespaces_fn, void *);
 static int walk_globals_r (tree, void*);
 static int walk_vtables_r (tree, void*);
@@ -9122,20 +9122,20 @@ check_elaborated_type_specifier (enum tag_types tag_code,
 }
 
 /* Lookup NAME in elaborate type specifier in scope according to
-   GLOBALIZE and issue diagnostics if necessary.
+   SCOPE and issue diagnostics if necessary.
    Return *_TYPE node upon success, NULL_TREE when the NAME is not
    found, and ERROR_MARK_NODE for type error.  */
 
 static tree
 lookup_and_check_tag (enum tag_types tag_code, tree name,
-                     bool globalize, bool template_header_p)
+                     tag_scope scope, bool template_header_p)
 {
   tree t;
   tree decl;
-  if (globalize)
+  if (scope == ts_global)
     decl = lookup_name (name, 2);
   else
-    decl = lookup_type_scope (name);
+    decl = lookup_type_scope (name, scope);
 
   if (decl && DECL_CLASS_TEMPLATE_P (decl))
     decl = DECL_TEMPLATE_RESULT (decl);
@@ -9174,16 +9174,18 @@ lookup_and_check_tag (enum tag_types tag_code, tree name,
    If a declaration is given, process it here, and report an error if
    multiple declarations are not identical.
 
-   GLOBALIZE is false when this is also a definition.  Only look in
+   SCOPE is TS_CURRENT when this is also a definition.  Only look in
    the current frame for the name (since C++ allows new names in any
-   scope.)
+   scope.)  It is TS_WITHIN_ENCLOSING_NON_CLASS if this is a friend
+   declaration.  Only look beginning from the current scope outward up
+   till the nearest non-class scope.  Otherwise it is TS_GLOBAL.
 
    TEMPLATE_HEADER_P is true when this declaration is preceded by
    a set of template parameters.  */
 
 tree
 xref_tag (enum tag_types tag_code, tree name,
-         bool globalize, bool template_header_p)
+         tag_scope scope, bool template_header_p)
 {
   enum tree_code code;
   tree t;
@@ -9215,16 +9217,16 @@ xref_tag (enum tag_types tag_code, tree name,
     t = NULL_TREE;
   else
     t = lookup_and_check_tag  (tag_code, name,
-                              globalize, template_header_p);
+                              scope, template_header_p);
 
   if (t == error_mark_node)
     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
 
-  if (globalize && t && current_class_type
+  if (scope != ts_current && t && current_class_type
       && template_class_depth (current_class_type)
       && template_header_p)
     {
-      /* Since GLOBALIZE is nonzero, we are not looking at a
+      /* Since SCOPE is not TS_CURRENT, we are not looking at a
         definition of this tag.  Since, in addition, we are currently
         processing a (member) template declaration of a template
         class, we must be very careful; consider:
@@ -9279,12 +9281,13 @@ xref_tag (enum tag_types tag_code, tree name,
        {
          t = make_aggr_type (code);
          TYPE_CONTEXT (t) = context;
-         pushtag (name, t, globalize);
+         /* pushtag only cares whether SCOPE is zero or not.  */
+         pushtag (name, t, scope != ts_current);
        }
     }
   else
     {
-      if (!globalize && processing_template_decl && IS_AGGR_TYPE (t))
+      if (template_header_p && IS_AGGR_TYPE (t))
        redeclare_class_template (t, current_template_parms);
       else if (!processing_template_decl
               && CLASS_TYPE_P (t)
@@ -9299,7 +9302,7 @@ xref_tag (enum tag_types tag_code, tree name,
 }
 
 tree
-xref_tag_from_type (tree old, tree id, int globalize)
+xref_tag_from_type (tree old, tree id, tag_scope scope)
 {
   enum tag_types tag_kind;
 
@@ -9311,7 +9314,7 @@ xref_tag_from_type (tree old, tree id, int globalize)
   if (id == NULL_TREE)
     id = TYPE_IDENTIFIER (old);
 
-  return xref_tag (tag_kind, id, globalize, false);
+  return xref_tag (tag_kind, id, scope, false);
 }
 
 /* Create the binfo hierarchy for REF with (possibly NULL) base list
@@ -9499,7 +9502,7 @@ xref_basetypes (tree ref, tree base_list)
 
 \f
 /* Begin compiling the definition of an enumeration type.
-   NAME is its name (or null if anonymous).
+   NAME is its name.
    Returns the type object, as yet incomplete.
    Also records info about it so that build_enumerator
    may be used to declare the individual values as they are read.  */
@@ -9507,14 +9510,17 @@ xref_basetypes (tree ref, tree base_list)
 tree
 start_enum (tree name)
 {
-  tree enumtype = NULL_TREE;
+  tree enumtype;
+
+  gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
 
   /* If this is the real definition for a previous forward reference,
      fill in the contents in the same object that used to be the
      forward reference.  */
 
-  if (name != NULL_TREE)
-    enumtype = lookup_and_check_tag (enum_type, name, 0, 0);
+  enumtype = lookup_and_check_tag (enum_type, name,
+                                  /*tag_scope=*/ts_current,
+                                  /*template_header_p=*/false);
 
   if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE)
     {
@@ -9525,6 +9531,11 @@ start_enum (tree name)
     }
   else
     {
+      /* In case of error, make a dummy enum to allow parsing to
+        continue.  */
+      if (enumtype == error_mark_node)
+       name = make_anon_name ();
+
       enumtype = make_node (ENUMERAL_TYPE);
       pushtag (name, enumtype, 0);
     }
index 29b93ffe921c2899ae3dd727ccc42ade54a6220e..a0188620759b21d6f32b929863aa98c95a43bd35 100644 (file)
@@ -4088,11 +4088,7 @@ lookup_name_real (tree name, int prefer_type, int nonclass, bool block_p,
 
   /* Now lookup in namespace scopes.  */
   if (!val)
-    {
-      tree t = unqualified_namespace_lookup (name, flags);
-      if (t)
-       val = t;
-    }
+    val = unqualified_namespace_lookup (name, flags);
 
   if (val)
     {
@@ -4128,15 +4124,18 @@ lookup_name (tree name, int prefer_type)
 }
 
 /* Look up NAME for type used in elaborated name specifier in
-   the current scope (possibly more if cleanup or template parameter
-   scope is encounter).  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.  */
+   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)
+lookup_type_scope (tree name, tag_scope scope)
 {
   cxx_binding *iter = NULL;
   tree val = NULL_TREE;
@@ -4149,19 +4148,22 @@ lookup_type_scope (tree name)
   for (; iter; iter = outer_binding (name, iter, /*class_p=*/ true))
     {
       /* Check if this is the kind of thing we're looking for.
-        Make sure it doesn't come from base class.  For ITER->VALUE,
-        we can simply use INHERITED_VALUE_BINDING_P.  For ITER->TYPE,
-        we have to use our own check.
+        If SCOPE is TS_CURRENT, also make sure it doesn't come from 
+        base class.  For ITER->VALUE, we can simply use
+        INHERITED_VALUE_BINDING_P.  For ITER->TYPE, we have to use 
+        our own check.
 
         We check ITER->TYPE before ITER->VALUE in order to handle
           typedef struct C {} C;
         correctly.  */
 
       if (qualify_lookup (iter->type, LOOKUP_PREFER_TYPES)
-         && (LOCAL_BINDING_P (iter)
+         && (scope != ts_current
+             || LOCAL_BINDING_P (iter)
              || DECL_CONTEXT (iter->type) == iter->scope->this_entity))
        val = iter->type;
-      else if (!INHERITED_VALUE_BINDING_P (iter)
+      else if ((scope != ts_current
+               || !INHERITED_VALUE_BINDING_P (iter))
               && qualify_lookup (iter->value, LOOKUP_PREFER_TYPES))
        val = iter->value;
 
@@ -4177,16 +4179,21 @@ lookup_type_scope (tree name)
 
       if (iter)
        {
-         /* If this is the kind of thing we're looking for, we're done.  */
-         if (qualify_lookup (iter->type, LOOKUP_PREFER_TYPES))
+         /* 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))
+         else if (qualify_lookup (iter->value, LOOKUP_PREFER_TYPES)
+                  && (CP_DECL_CONTEXT (iter->value)
+                      == iter->scope->this_entity))
            val = iter->value;
        }
        
     }
 
-  /* Type found, check if it is in the current scope, ignoring cleanup
+  /* Type found, check if it is in the allowed scopes, ignoring cleanup
      and template parameter scopes.  */
   if (val)
     {
@@ -4198,6 +4205,9 @@ lookup_type_scope (tree name)
 
          if (b->kind == sk_cleanup || b->kind == sk_template_parms)
            b = b->level_chain;
+         else if (b->kind == sk_class
+                  && scope == ts_within_enclosing_non_class)
+           b = b->level_chain;
          else
            break;
        }
index b43fa1e4f323de2c0c101a19ca42e0033efe8d32..08a9ba504b9e99307832a0841add3ba61934a971 100644 (file)
@@ -125,6 +125,22 @@ typedef enum scope_kind {
                        "template <>", this scope is always empty.  */
 } scope_kind;
 
+/* The scope where the class/struct/union/enum tag applies.  */
+typedef enum tag_scope {
+  ts_current = 0,      /* Current scope only.  This is for the
+                            class-key identifier;
+                          case mentioned in [basic.lookup.elab]/2,
+                          or the class/enum definition
+                            class-key identifier { ... };  */
+  ts_global = 1,       /* All scopes.  This is the 3.4.1
+                          [basic.lookup.unqual] lookup mentioned
+                          in [basic.lookup.elab]/2.  */
+  ts_within_enclosing_non_class = 2    /* Search within enclosing non-class
+                                          only, for friend class lookup
+                                          according to [namespace.memdef]/3
+                                          and [class.friend]/9.  */
+} tag_scope;
+
 typedef struct cp_class_binding GTY(())
 {
   cxx_binding base;
@@ -303,7 +319,7 @@ extern tree lookup_tag (enum tree_code, tree, cxx_scope *, int);
 extern tree lookup_tag_reverse (tree, tree);
 extern tree lookup_name        (tree, int);
 extern tree lookup_name_real (tree, int, int, bool, int, int);
-extern tree lookup_type_scope (tree);
+extern tree lookup_type_scope (tree, tag_scope);
 extern tree namespace_binding (tree, tree);
 extern void set_namespace_binding (tree, tree, tree);
 extern tree lookup_namespace_name (tree, tree);
index 1a9786845c49673757a741eb20f253088c608938..3548b45c117515e13b38f022c9aae6a9b77f874d 100644 (file)
@@ -9731,15 +9731,23 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
             definition of a new type; a new type can only be declared in a
             declaration context.  */
 
+         tag_scope ts;
+         if (is_friend)
+           /* Friends have special name lookup rules.  */
+           ts = ts_within_enclosing_non_class;
+         else if (is_declaration
+                  && cp_lexer_next_token_is (parser->lexer,
+                                             CPP_SEMICOLON))
+           /* This is a `class-key identifier ;' */
+           ts = ts_current;
+         else
+           ts = ts_global;
+
          /* Warn about attributes. They are ignored.  */
          if (attributes)
            warning ("type attributes are honored only at type definition");
 
-         type = xref_tag (tag_type, identifier,
-                          (is_friend
-                           || !is_declaration
-                           || cp_lexer_next_token_is_not (parser->lexer,
-                                                          CPP_SEMICOLON)),
+         type = xref_tag (tag_type, identifier, ts,
                           parser->num_template_parameter_lists);
        }
     }
@@ -12642,7 +12650,7 @@ cp_parser_class_head (cp_parser* parser,
       /* If the class was unnamed, create a dummy name.  */
       if (!id)
        id = make_anon_name ();
-      type = xref_tag (class_key, id, /*globalize=*/false,
+      type = xref_tag (class_key, id, /*tag_scope=*/ts_current,
                       parser->num_template_parameter_lists);
     }
   else
index c171f31b083835b1fa82382c445e156aada3d3df..b514cc1430137d0cf36a542a5a382d1f2bcde727 100644 (file)
@@ -4576,7 +4576,7 @@ lookup_template_class (tree d1,
        {
          found = xref_tag_from_type (TREE_TYPE (template),
                                      DECL_NAME (template),
-                                     /*globalize=*/1);
+                                     /*tag_scope=*/ts_global);
          POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, found);
        }
       
@@ -5788,7 +5788,8 @@ instantiate_class_template (tree type)
                     classes.  */
                  push_nested_namespace (ns);
                  friend_type = 
-                   xref_tag_from_type (friend_type, NULL_TREE, 1);
+                   xref_tag_from_type (friend_type, NULL_TREE, 
+                                       /*tag_scope=*/ts_global);
                  pop_nested_namespace (ns);
                }
 
index 9bb2c364bbff41accfd541d1aad6ab1f34adddc1..cf66904b9b6dfdf36ac31b2e75da4e6bbd564aa1 100644 (file)
@@ -113,7 +113,7 @@ init_rtti_processing (void)
   push_namespace (std_identifier);
   type_info_type_node 
     = xref_tag (class_type, get_identifier ("type_info"),
-               true, false);
+               /*tag_scope=*/ts_global, false);
   pop_namespace ();
   const_type_info_type = build_qualified_type (type_info_type_node, 
                                               TYPE_QUAL_CONST);
@@ -628,7 +628,7 @@ build_dynamic_cast_1 (tree type, tree expr)
              push_nested_namespace (ns);
              tinfo_ptr = xref_tag (class_type,
                                    get_identifier ("__class_type_info"),
-                                   true, false);
+                                   /*tag_scope=*/ts_global, false);
              
              tinfo_ptr = build_pointer_type
                (build_qualified_type
@@ -808,7 +808,7 @@ tinfo_base_init (tree desc, tree target)
   
       push_nested_namespace (abi_node);
       real_type = xref_tag (class_type, TINFO_REAL_NAME (desc),
-                           true, false);
+                           /*tag_scope=*/ts_global, false);
       pop_nested_namespace (abi_node);
   
       if (!COMPLETE_TYPE_P (real_type))
@@ -1340,7 +1340,7 @@ emit_support_tinfos (void)
   push_nested_namespace (abi_node);
   bltn_type = xref_tag (class_type,
                        get_identifier ("__fundamental_type_info"), 
-                       true, false);
+                       /*tag_scope=*/ts_global, false);
   pop_nested_namespace (abi_node);
   if (!COMPLETE_TYPE_P (bltn_type))
     return;
index f41d675b497743c066c35d3e200a877f301d39dd..e82c3fd17db67ab75710ca4811302ca9153536ae 100644 (file)
@@ -1,3 +1,9 @@
+2004-11-25  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>
+
+       Friend class name lookup 2/n, PR c++/14513, c++/15410
+       * g++.dg/lookup/friend2.C: New test.
+       * g++.dg/template/friend31.C: Likewise.
+
 2004-11-24  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
 
        * lib/target-libpath.exp (orig_ld_library_path_saved): Add missing set.
diff --git a/gcc/testsuite/g++.dg/lookup/friend2.C b/gcc/testsuite/g++.dg/lookup/friend2.C
new file mode 100644 (file)
index 0000000..765c69b
--- /dev/null
@@ -0,0 +1,21 @@
+// { dg-do compile }
+
+// Origin: Albert Chin <bugzilla-gcc@thewrittenword.com>
+//        Wolfgang Bangerth <bangerth@dealii.org>
+
+// PR c++/14513, unqualified lookup of friend class.
+
+struct S {
+    void test (void);
+};
+
+namespace NS {
+  class X {
+      friend class S;
+      static int *i;   // { dg-error "private" }
+  };
+}
+
+void S::test () {
+  NS::X::i;            // { dg-error "this context" }
+}
diff --git a/gcc/testsuite/g++.dg/template/friend31.C b/gcc/testsuite/g++.dg/template/friend31.C
new file mode 100644 (file)
index 0000000..2d62f87
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do compile }
+
+// Origin: Ivan Godard <igodard@pacbell.net>
+
+// PR c++/15410: Declaration of friend class template with wrong
+// template parameter.
+
+template <typename T, typename U> struct F; // { dg-error "previous declaration" }
+
+class W
+{
+  template<int i> friend class F;      // { dg-error "template parameter" }
+  int x;
+};
+
+template <typename T, typename U> struct F
+{
+  void Look(W& w) { w.x = 3; }
+};
+
+int main()
+{
+  W w;
+  F<char, bool> f;
+  f.Look(w);
+  return 0;
+}