diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 14194c7eb55..3f05cb74a42 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,20 @@ +2002-01-02 Nathan Sidwell + + 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 PR c++/4379 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 5069648752f..45b8fbfed40 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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)); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 401ccbf20f3..3ff1ccc6228 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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)) - { - /* 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", - FROB_CONTEXT (scope), id); - } - else if (scope != global_namespace) - error ("`%T' does not have a nested type named `%D'", scope, id); + *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 - 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)); + { + 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 + error ("`%T' does not have a class or union named `%D'", + scope, id); + } + } + + if (!decl) + { + decl = TYPE_MAIN_DECL (xref_tag (aggr, id, !defn_p)); + xrefd_p = true; } - - /* 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 (!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); - template struct S::I .... - - we must create a TEMPLATE_DECL for the nested type. */ - if (PROCESSING_REAL_TEMPLATE_DECL_P ()) - decl = push_template_decl (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; } diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y index 7339fe36458..64f3dc1a31e 100644 --- a/gcc/cp/parse.y +++ b/gcc/cp/parse.y @@ -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 component_constructor_declarator %type fn.def2 return_id constructor_declarator %type .begin_function_body -%type named_class_head_sans_basetype -%type class_head named_class_head -%type named_complex_class_head_sans_basetype -%type unnamed_class_head +%type class_head class_head_apparent_template +%type class_head_decl class_head_defn %type base_class_list %type base_class_access_list %type base_class maybe_base_class_list base_class.1 @@ -418,7 +416,6 @@ cp_parse_init () %type explicit_template_type /* in order to recognize aggr tags as defining and thus shadowing. */ %token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN -%type named_class_head_sans_basetype_defn %type identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN %type handler_args %type 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); $$ = t; /* restore current_aggr */ @@ -2307,32 +2316,13 @@ structsp: pending_inlines { finish_inline_definitions (); - $$.t = $7; + $$.t = $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; - } - ; - -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 { current_aggr = $1; - $$.t = handle_class_head ($1, $2, $3); - $$.new_type_flag = 1; + $$ = build_tree_list (NULL_TREE, $2); + } + | aggr nested_name_specifier identifier + { + current_aggr = $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)); + $$ = $4; + } + ; + +class_head_decl: + class_head %prec EMPTY + { + $$.t = handle_class_head (current_aggr, + TREE_PURPOSE ($1), TREE_VALUE ($1), + 0, &$$.new_type_flag); + } + | aggr identifier_defn %prec EMPTY + { + current_aggr = $1; + $$.t = TYPE_MAIN_DECL (xref_tag (current_aggr, $2, 0)); $$.new_type_flag = 1; } - ; - -named_class_head: - named_class_head_sans_basetype %prec EMPTY - { - $$.t = xref_tag (current_aggr, $1, 1); - $$.new_type_flag = 0; - } - | named_class_head_sans_basetype_defn - { $$ = 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 = $2; - $$.new_type_flag = 0; - if ($3) - xref_basetypes (current_aggr, $1, $2, $3); - } - | 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); - } - } - } - ; - -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_apparent_template %prec EMPTY + { $$.t = $1; $$.new_type_flag = 0; } - | named_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; + } + | 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; } ; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e75984c11ea..96c503d1fad 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2002-01-02 Nathan Sidwell + + * g++.dg/template/friend2.C: New test. + * g++.old-deja/g++/brendan/crash8.C: Adjust location of error. + 2002-01-02 Nathan Sidwell * 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 index 00000000000..7400534acac --- /dev/null +++ b/gcc/testsuite/g++.dg/template/friend3.C @@ -0,0 +1,31 @@ +// { dg-do compile } + +// Copyright (C) 2001 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 28 Dec 2001 + +// PR 775 friend classes with qualified names inside template classes. + +struct A +{ + struct B { + B () { } + }; +}; + +template +struct C: A { + friend A::B::B (); // 2.95.2 ICE + friend struct A; + friend struct A::B; // 2.97 error +}; + +template class C; + +template class TPL +{ + class nested; +}; + +template class TPL::nested +{ +}; diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash8.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash8.C index 4de66c6d168..46cc16fa18c 100644 --- a/gcc/testsuite/g++.old-deja/g++.brendan/crash8.C +++ b/gcc/testsuite/g++.old-deja/g++.brendan/crash8.C @@ -1,8 +1,8 @@ // Build don't link: // GROUPS passed old-abort template -class Elvis // ERROR - in template.* -{ +class Elvis +{ // ERROR - in template.* } ; template