re PR c++/775 (2.97 error declaring nested class a friend)
authorNathan Sidwell <nathan@codesourcery.com>
Wed, 2 Jan 2002 11:37:00 +0000 (11:37 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Wed, 2 Jan 2002 11:37:00 +0000 (11:37 +0000)
cp:
PR c++/775
* cp-tree.h (handle_class_head): Adjust prototype.
* decl2.c (handle_class_head): Add DEFN_P and NEW_TYPE_P
parameters. Use for all class heads.
* parse.y (named_class_head_sans_basetype, named_class_head,
named_complex_class_head_sans_basetype,
named_class_head_sans_basetype_defn,
unnamed_class_head): Remove.
(class_head, class_head_apparent_template): Recognize class heads
(class_head_decl, class_head_defn): New reductions. Process class
heads.
(structsp): Adjust class definition and class declaration
reductions.
(maybe_base_class_list): Give diagnostic on empty list.
testsuite:
* g++.dg/template/friend2.C: New test.
* g++.old-deja/g++/brendan/crash8.C: Adjust location of error.

From-SVN: r48466

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl2.c
gcc/cp/parse.y
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/friend3.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.brendan/crash8.C

index 14194c7eb55e9bbd078bbfb5e2dda26e53bceda9..3f05cb74a4255c0cc0ff9b04386890ee15af9546 100644 (file)
@@ -1,3 +1,20 @@
+2002-01-02  Nathan Sidwell  <nathan@codesourcery.com>
+
+       PR c++/775
+       * cp-tree.h (handle_class_head): Adjust prototype.
+       * decl2.c (handle_class_head): Add DEFN_P and NEW_TYPE_P
+       parameters. Use for all class heads.
+       * parse.y (named_class_head_sans_basetype, named_class_head,
+       named_complex_class_head_sans_basetype,
+       named_class_head_sans_basetype_defn,
+       unnamed_class_head): Remove.
+       (class_head, class_head_apparent_template): Recognize class heads
+       (class_head_decl, class_head_defn): New reductions. Process class
+       heads.
+       (structsp): Adjust class definition and class declaration
+       reductions.
+       (maybe_base_class_list): Give diagnostic on empty list.
+
 2002-01-02  Nathan Sidwell  <nathan@codesourcery.com>
 
        PR c++/4379
index 5069648752f7b7d106cead6d4442b9dce8cb3521..45b8fbfed40819f781e6649cb370c1d762fcc27e 100644 (file)
@@ -1,6 +1,6 @@
 /* Definitions for C++ parsing and type checking.
    Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001 Free Software Foundation, Inc.
+   2000, 2001, 2002 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -3769,7 +3769,7 @@ extern tree do_class_using_decl                   PARAMS ((tree));
 extern void do_using_directive                 PARAMS ((tree));
 extern void check_default_args                 PARAMS ((tree));
 extern void mark_used                          PARAMS ((tree));
-extern tree handle_class_head                  PARAMS ((tree, tree, tree));
+extern tree handle_class_head                  PARAMS ((tree, tree, tree, int, int *));
 extern tree lookup_arg_dependent                PARAMS ((tree, tree, tree));
 extern void finish_static_data_member_decl      PARAMS ((tree, tree, tree, int));
 extern tree build_artificial_parm               PARAMS ((tree, tree));
index 401ccbf20f3529226c35ba2d3a0262d63a097631..3ff1ccc622856156e53a1417b395eb5a5993e1ae 100644 (file)
@@ -5162,70 +5162,90 @@ mark_used (decl)
     instantiate_decl (decl, /*defer_ok=*/1);
 }
 
-/* Helper function for named_class_head_sans_basetype nonterminal.  We
-   have just seen something of the form `AGGR SCOPE::ID'.  Return a
-   TYPE_DECL for the type declared by ID in SCOPE.  */
+/* Helper function for class_head_decl and class_head_defn
+   nonterminals. AGGR is the class, union or struct tag. SCOPE is the
+   explicit scope used (NULL for no scope resolution). ID is the
+   name. DEFN_P is true, if this is a definition of the class and
+   NEW_TYPE_P is set to non-zero, if we push into the scope containing
+   the to be defined aggregate.
+   
+   Return a TYPE_DECL for the type declared by ID in SCOPE.  */
 
 tree
-handle_class_head (aggr, scope, id)
+handle_class_head (aggr, scope, id, defn_p, new_type_p)
      tree aggr, scope, id;
+     int defn_p;
+     int *new_type_p;
 {
   tree decl = NULL_TREE;
-
-  if (TREE_CODE (id) == TYPE_DECL)
-    /* We must bash typedefs back to the main decl of the type. Otherwise
-       we become confused about scopes.  */
-    decl = TYPE_MAIN_DECL (TREE_TYPE (id));
-  else if (DECL_CLASS_TEMPLATE_P (id))
-    decl = DECL_TEMPLATE_RESULT (id);
-  else 
-    {
-      tree current = current_scope ();
+  tree current = current_scope ();
+  bool xrefd_p = false;
   
-      if (current == NULL_TREE)
-        current = current_namespace;
-      if (scope == NULL_TREE)
-        scope = global_namespace;
+  if (current == NULL_TREE)
+    current = current_namespace;
 
-      if (TYPE_P (scope))
+  *new_type_p = 0;
+  
+  if (scope)
+    {
+      if (TREE_CODE (id) == TYPE_DECL)
+       /* We must bash typedefs back to the main decl of the
+                  type. Otherwise we become confused about scopes.  */
+       decl = TYPE_MAIN_DECL (TREE_TYPE (id));
+      else if (DECL_CLASS_TEMPLATE_P (id))
+       decl = DECL_TEMPLATE_RESULT (id);
+      else
        {
-         /* According to the suggested resolution of core issue 180,
-            'typename' is assumed after a class-key.  */
-         decl = make_typename_type (scope, id, 1);
-         if (decl != error_mark_node)
-           decl = TYPE_MAIN_DECL (decl);
+         if (TYPE_P (scope))
+           {
+             /* According to the suggested resolution of core issue
+                180, 'typename' is assumed after a class-key.  */
+             decl = make_typename_type (scope, id, 1);
+             if (decl != error_mark_node)
+               decl = TYPE_MAIN_DECL (decl);
+             else
+               decl = NULL_TREE;
+           }
+         else if (scope == current)
+           {
+             /* We've been given AGGR SCOPE::ID, when we're already
+                inside SCOPE.  Be nice about it.  */
+             if (pedantic)
+               pedwarn ("extra qualification `%T::' on member `%D' ignored",
+                        scope, id);
+           }
          else
-           decl = NULL_TREE;
+           error ("`%T' does not have a class or union named `%D'",
+                  scope, id);
        }
-      else if (scope == current)
-        {
-          /* We've been given AGGR SCOPE::ID, when we're already inside SCOPE.
-             Be nice about it.  */
-          if (pedantic)
-            pedwarn ("extra qualification `%T::' on member `%D' ignored",
-                        FROB_CONTEXT (scope), id);
-        }
-      else if (scope != global_namespace)
-       error ("`%T' does not have a nested type named `%D'", scope, id);
-      else
-       error ("no file-scope type named `%D'", id);
-      
-      /* Inject it at the current scope.  */
-      if (! decl)
-       decl = TYPE_MAIN_DECL (xref_tag (aggr, id, 1));
     }
-  /* Enter the SCOPE.  If this turns out not to be a definition, the
-     parser must leave the scope.  */
-  push_scope (CP_DECL_CONTEXT (decl));
-
-  /* If we see something like:
+  
+  if (!decl)
+    {
+      decl = TYPE_MAIN_DECL (xref_tag (aggr, id, !defn_p));
+      xrefd_p = true;
+    }
 
-       template <typename T> struct S::I ....
-       
-     we must create a TEMPLATE_DECL for the nested type.  */
-  if (PROCESSING_REAL_TEMPLATE_DECL_P ())
-    decl = push_template_decl (decl);
+  if (!TYPE_BINFO (TREE_TYPE (decl)))
+    {
+      error ("`%T' is not a class or union type", decl);
+      return error_mark_node;
+    }
+  
+  if (defn_p)
+    {
+      /* For a definition, we want to enter the containing scope
+        before looking up any base classes etc. Only do so, if this
+        is different to the current scope.  */
+      tree context = CP_DECL_CONTEXT (decl);
+
+      *new_type_p = current != context;
+      if (*new_type_p)
+       push_scope (context);
+  
+      if (!xrefd_p && PROCESSING_REAL_TEMPLATE_DECL_P ())
+       decl = push_template_decl (decl);
+    }
 
   return decl;
 }
index 7339fe364582c16fec98486c3b5d47cd4231b42b..64f3dc1a31e3d3f696b44848e1d5d9e671b3d78e 100644 (file)
@@ -1,6 +1,6 @@
 /* YACC parser for C++ syntax.
    Copyright (C) 1988, 1989, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -386,10 +386,8 @@ cp_parse_init ()
 %type <ttype> component_constructor_declarator
 %type <ttype> fn.def2 return_id constructor_declarator
 %type <ttype> .begin_function_body
-%type <ttype> named_class_head_sans_basetype
-%type <ftype> class_head named_class_head 
-%type <ftype> named_complex_class_head_sans_basetype 
-%type <ttype> unnamed_class_head
+%type <ttype> class_head class_head_apparent_template
+%type <ftype> class_head_decl class_head_defn
 %type <ttype> base_class_list
 %type <ttype> base_class_access_list
 %type <ttype> base_class maybe_base_class_list base_class.1
@@ -418,7 +416,6 @@ cp_parse_init ()
 %type <ttype> explicit_template_type
 /* in order to recognize aggr tags as defining and thus shadowing.  */
 %token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN
-%type <ttype> named_class_head_sans_basetype_defn
 %type <ttype> identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN
 %type <ttype> handler_args
 %type <ttype> self_template_type .finish_template_type
@@ -2277,8 +2274,21 @@ structsp:
                  if (!processing_template_decl)
                    pedwarn ("using `typename' outside of template"); }
        /* C++ extensions, merged with C to avoid shift/reduce conflicts */
-       | class_head '{'
-                { $1.t = begin_class_definition ($1.t); 
+       | class_head_defn maybe_base_class_list '{'
+               {
+                 if ($2 && $1.t != error_mark_node)
+                   {
+                     tree type = TREE_TYPE ($1.t);
+                 
+                     if (TREE_CODE (type) == TYPENAME_TYPE)
+                       /* In a definition of a member class template,
+                           we will get here with an implicit typename,
+                           a TYPENAME_TYPE with a type. */
+                       type = TREE_TYPE (type);
+                     maybe_process_partial_specialization (type);
+                     xref_basetypes (current_aggr, $1.t, type, $2);
+                   }
+                 $1.t = begin_class_definition (TREE_TYPE ($1.t)); 
                   current_aggr = NULL_TREE; }
           opt.component_decl_list '}' maybe_attribute
                { 
@@ -2289,8 +2299,7 @@ structsp:
                    yychar = YYLEX;
                  semi = yychar == ';';
 
-                 t = finish_class_definition ($1.t, $6, semi,
-                                              $1.new_type_flag); 
+                 t = finish_class_definition ($1.t, $7, semi, $1.new_type_flag);
                  $<ttype>$ = t;
 
                  /* restore current_aggr */
@@ -2307,32 +2316,13 @@ structsp:
          pending_inlines
                 {
                  finish_inline_definitions ();
-                 $$.t = $<ttype>7;
+                 $$.t = $<ttype>8;
                  $$.new_type_flag = 1; 
                }
-       | class_head  %prec EMPTY
+       | class_head_decl
                {
-                 if ($1.new_type_flag && $1.t != error_mark_node)
-                   pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL ($1.t)));
-                 $$.new_type_flag = 0;
-                 if ($1.t == error_mark_node)
-                   $$.t = $1.t;
-                 else if (TYPE_BINFO ($1.t) == NULL_TREE)
-                   {
-                     error ("%T is not a class type", $1.t);
-                     $$.t = error_mark_node;
-                   } 
-                 else
-                   {
-                     $$.t = $1.t;
-                     /* struct B: public A; is not accepted by the standard grammar.  */
-                     if (CLASS_TYPE_P ($$.t)
-                         && TYPE_BINFO_BASETYPES ($$.t) 
-                         && !COMPLETE_TYPE_P ($$.t)
-                         && ! TYPE_BEING_DEFINED ($$.t))
-                       error ("base clause without member specification for `%#T'",
-                                 $$.t);
-                   }
+                 $$.t = TREE_TYPE ($1.t);
+                 $$.new_type_flag = $1.new_type_flag;
                }
        ;
 
@@ -2362,140 +2352,126 @@ aggr:
                { $$ = build_tree_list ($2, $1); }
        ;
 
-named_class_head_sans_basetype:
+class_head:
          aggr identifier
-               { 
-                 current_aggr = $1; 
-                 $$ = $2; 
+               {
+                 current_aggr = $1;
+                 $$ = build_tree_list (NULL_TREE, $2);
                }
-       ;
-
-named_class_head_sans_basetype_defn:
-         aggr identifier_defn  %prec EMPTY
-               { current_aggr = $$; $$ = $2; }
-       | named_class_head_sans_basetype '{'
-               { yyungetc ('{', 1); }
-       | named_class_head_sans_basetype ':'
-               { yyungetc (':', 1); }
-       ;
-
-named_complex_class_head_sans_basetype:
-         aggr nested_name_specifier identifier
+       | aggr nested_name_specifier identifier
                {
                  current_aggr = $1;
-                 $$.t = handle_class_head ($1, $2, $3);
-                 $$.new_type_flag = 1;
+                 $$ = build_tree_list ($2, $3);
                }
        | aggr global_scope nested_name_specifier identifier
                {
                  current_aggr = $1;
-                 $$.t = handle_class_head ($1, $3, $4);
-                 $$.new_type_flag = 1;
+                 $$ = build_tree_list ($3, $4);
                }
        | aggr global_scope identifier
                {
                  current_aggr = $1;
-                 $$.t = handle_class_head ($1, NULL_TREE, $3);
-                 $$.new_type_flag = 1;
+                 $$ = build_tree_list (global_namespace, $3);
                }
-       | aggr apparent_template_type
+       ;
+
+class_head_apparent_template:
+         aggr apparent_template_type
                { 
                  current_aggr = $1; 
-                 $$.t = $2;
-                 $$.new_type_flag = 0;
+                 $$ = $2;
                }
        | aggr nested_name_specifier apparent_template_type
                { 
                  current_aggr = $1; 
-                 $$.t = $3;
-                 push_scope (CP_DECL_CONTEXT ($$.t));
-                 $$.new_type_flag = 1;
+                 $$ = $3;
                }
        | aggr global_scope nested_name_specifier apparent_template_type
                { 
                  current_aggr = $1; 
-                 $$.t = $4;
-                 push_scope (CP_DECL_CONTEXT ($$.t));
-                 $$.new_type_flag = 1;
+                 $$ = $4;
                }
        ;
 
-named_class_head:
-         named_class_head_sans_basetype  %prec EMPTY
-               { 
-                 $$.t = xref_tag (current_aggr, $1, 1); 
-                 $$.new_type_flag = 0;
+class_head_decl:
+         class_head %prec EMPTY
+               {
+                 $$.t = handle_class_head (current_aggr,
+                                           TREE_PURPOSE ($1), TREE_VALUE ($1),
+                                           0, &$$.new_type_flag);
                }
-       | named_class_head_sans_basetype_defn 
-                { $<ttype>$ = xref_tag (current_aggr, $1, 0); }
-          /* Class name is unqualified, so we look for base classes
-             in the current scope.  */
-          maybe_base_class_list  %prec EMPTY
-               { 
-                 $$.t = $<ttype>2;
-                 $$.new_type_flag = 0;
-                 if ($3)
-                    xref_basetypes (current_aggr, $1, $<ttype>2, $3); 
+       | aggr identifier_defn %prec EMPTY
+               {
+                 current_aggr = $1;
+                 $$.t = TYPE_MAIN_DECL (xref_tag (current_aggr, $2, 0));
+                 $$.new_type_flag = 1;
                }
-       | named_complex_class_head_sans_basetype 
-         maybe_base_class_list
-               { 
-                 if ($1.t != error_mark_node)
-                   {
-                     tree type = TREE_TYPE ($1.t);
-
-                     $$.t = type;
-                     $$.new_type_flag = $1.new_type_flag;
-                     if ((current_aggr == union_type_node)
-                         != (TREE_CODE (type) == UNION_TYPE))
-                       pedwarn (current_aggr == union_type_node
-                                   ? "`union' tag used in declaring `%#T'"
-                                   : "non-`union' tag used in declaring `%#T'", 
-                                   type);
-                     else if (TREE_CODE (type) == RECORD_TYPE)
-                       /* We might be specializing a template with a different
-                          class-key; deal.  */
-                       CLASSTYPE_DECLARED_CLASS (type) 
-                         = (current_aggr == class_type_node);
-                     if ($2)
-                       {
-                          if (TREE_CODE (type) == TYPENAME_TYPE)
-                            /* In a definition of a member class template, we
-                               will get here with an implicit typename, a
-                               TYPENAME_TYPE with a type. */
-                            type = TREE_TYPE (type);
-                         maybe_process_partial_specialization (type);
-                         xref_basetypes (current_aggr, $1.t, type, $2); 
-                       }
-                   }
+       | class_head_apparent_template %prec EMPTY
+               {
+                 $$.t = $1;
+                 $$.new_type_flag = 0;
                }
        ;
 
-unnamed_class_head:
-         aggr '{'
-               { $$ = xref_tag ($$, make_anon_name (), 0);
-                 yyungetc ('{', 1); }
-       ;
-
-/* The tree output of this nonterminal a declarationf or the type
-   named.  If NEW_TYPE_FLAG is set, then the name used in this
-   class-head was explicitly qualified, e.g.:  `struct X::Y'.  We have
-   already called push_scope for X.  */
-class_head:
-         unnamed_class_head
-                {
+class_head_defn:
+         class_head '{'
+               {
+                 yyungetc ('{', 1);
+                 $$.t = handle_class_head (current_aggr,
+                                           TREE_PURPOSE ($1), TREE_VALUE ($1),
+                                           1, &$$.new_type_flag);
+               }
+       | class_head ':'
+               {
+                 yyungetc (':', 1);
+                 $$.t = handle_class_head (current_aggr,
+                                           TREE_PURPOSE ($1), TREE_VALUE ($1),
+                                           1, &$$.new_type_flag);
+               }
+       | class_head_apparent_template '{'
+               {
+                 yyungetc ('{', 1);
+                 $$.t = $1;
+                 $$.new_type_flag = 0;
+               }
+       | class_head_apparent_template ':'
+               {
+                 yyungetc (':', 1);
                  $$.t = $1;
                  $$.new_type_flag = 0;
                }
-       | named_class_head
+       | aggr identifier_defn '{'
+               {
+                 yyungetc ('{', 1);
+                 current_aggr = $1;
+                 $$.t = handle_class_head (current_aggr,
+                                           NULL_TREE, $2,
+                                           1, &$$.new_type_flag);
+               }
+       | aggr identifier_defn ':'
+               {
+                 yyungetc (':', 1);
+                 current_aggr = $1;
+                 $$.t = handle_class_head (current_aggr,
+                                           NULL_TREE, $2,
+                                           1, &$$.new_type_flag);
+               }
+        | aggr '{'
+               {
+                 current_aggr = $1;
+                 $$.t = TYPE_MAIN_DECL (xref_tag ($1, make_anon_name (), 0));
+                 $$.new_type_flag = 0;
+                 yyungetc ('{', 1);
+               }
        ;
 
 maybe_base_class_list:
-         /* empty */  %prec EMPTY
+         /* empty */
                { $$ = NULL_TREE; }
-       | ':' see_typename  %prec EMPTY
-               { yyungetc(':', 1); $$ = NULL_TREE; }
-       | ':' see_typename base_class_list  %prec EMPTY
+       | ':' see_typename
+               { error ("no bases given following `:'");
+                 $$ = NULL_TREE; }
+       | ':' see_typename base_class_list
                { $$ = $3; }
        ;
 
index e75984c11eaf93f7c358547a00e6a32cbbb2f5e1..96c503d1fad7635066e61725fbd94fc79582b6d8 100644 (file)
@@ -1,3 +1,8 @@
+2002-01-02  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * g++.dg/template/friend2.C: New test.
+       * g++.old-deja/g++/brendan/crash8.C: Adjust location of error.
+
 2002-01-02  Nathan Sidwell  <nathan@codesourcery.com>
 
        * g++.dg/other/ptrmem1.C: New test.
diff --git a/gcc/testsuite/g++.dg/template/friend3.C b/gcc/testsuite/g++.dg/template/friend3.C
new file mode 100644 (file)
index 0000000..7400534
--- /dev/null
@@ -0,0 +1,31 @@
+// { dg-do compile }
+
+// Copyright (C) 2001 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 28 Dec 2001 <nathan@codesourcery.com>
+
+// PR 775 friend classes with qualified names inside template classes.
+
+struct A
+{
+  struct B {
+    B () { }
+  };
+};
+
+template <class T>
+struct C: A {
+  friend A::B::B (); // 2.95.2 ICE
+  friend struct A;
+  friend struct A::B; // 2.97 error
+};
+
+template class C<char>;
+
+template <typename T> class TPL
+{
+  class nested;
+};
+
+template <typename T> class TPL<T>::nested 
+{
+};
index 4de66c6d168cdc185075731ea9e4b3369bc09f3d..46cc16fa18c0ac5495bb6a55a3ea7cfbe3dc78b4 100644 (file)
@@ -1,8 +1,8 @@
 // Build don't link: 
 // GROUPS passed old-abort
 template<int a, int b>
-class Elvis // ERROR - in template.*
-{
+class Elvis
+{ // ERROR - in template.*
 } ;
 
 template<int a>