re PR c++/775 (2.97 error declaring nested class a friend)

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
This commit is contained in:
Nathan Sidwell 2002-01-02 11:37:00 +00:00 committed by Nathan Sidwell
parent 4542128ef1
commit d46a33b322
7 changed files with 242 additions and 193 deletions

View 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

View 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));

View 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))
{
/* 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 <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);
*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;
}

View 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;
}
;
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
{ $<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);
}
| 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; }
;

View 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.

View File

@ -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
{
};

View 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>