aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2002-01-02 11:37:00 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2002-01-02 11:37:00 +0000
commitd46a33b3223caf37f764ce4c26d9e293b9f26fff (patch)
treed70dbbf96d384cc554f4062e493f143a44a5e130
parent4542128ef1545dc28cf4e3a2e4232f6058267c1c (diff)
downloadgcc-d46a33b3223caf37f764ce4c26d9e293b9f26fff.zip
gcc-d46a33b3223caf37f764ce4c26d9e293b9f26fff.tar.gz
gcc-d46a33b3223caf37f764ce4c26d9e293b9f26fff.tar.bz2
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
-rw-r--r--gcc/cp/ChangeLog17
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/decl2.c124
-rw-r--r--gcc/cp/parse.y234
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/template/friend3.C31
-rw-r--r--gcc/testsuite/g++.old-deja/g++.brendan/crash8.C4
7 files changed, 234 insertions, 185 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 14194c7..3f05cb7 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,22 @@
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
* typeck.c (build_x_unary_op): Don't destroy the OFFSET_REF on a
single non-static member.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5069648..45b8fbf 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 401ccbf..3ff1ccc 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))
+ *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;
}
diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y
index 7339fe3..64f3dc1 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 <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; }
;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e75984c..96c503d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,10 @@
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.
* g++.dg/other/ptrmem2.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 0000000..7400534
--- /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 <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
+{
+};
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash8.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash8.C
index 4de66c6..46cc16f 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<int a, int b>
-class Elvis // ERROR - in template.*
-{
+class Elvis
+{ // ERROR - in template.*
} ;
template<int a>