diff options
author | Jason Merrill <jason@redhat.com> | 2008-01-22 14:50:37 -0500 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2008-01-22 14:50:37 -0500 |
commit | 7655e009c8f506454a5cc16bace7282b67513c00 (patch) | |
tree | d611d9e565111bcaa97ac42d5cbee302da3e523c | |
parent | b5ca4fd2f6927b6c2cc9ca3f315980b9cbf45605 (diff) | |
download | gcc-7655e009c8f506454a5cc16bace7282b67513c00.zip gcc-7655e009c8f506454a5cc16bace7282b67513c00.tar.gz gcc-7655e009c8f506454a5cc16bace7282b67513c00.tar.bz2 |
re PR c++/34912 (ICE with friend in local class)
PR c++/34912
* friend.c (do_friend): Check for prior declaration of a friend
function of a local class.
* name-lookup.c (lookup_name_innermost_nonclass_level):
No longer static.
* name-lookup.h: Declare it.
From-SVN: r131740
-rw-r--r-- | gcc/cp/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/cp/friend.c | 24 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 3 | ||||
-rw-r--r-- | gcc/cp/name-lookup.h | 1 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lookup/friend12.C | 10 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/parse/local-class1.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.jason/scoping12.C | 2 |
7 files changed, 42 insertions, 9 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 235f7cb..45297de 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2008-01-22 Jason Merrill <jason@redhat.com> + + PR c++/34912 + * friend.c (do_friend): Check for prior declaration of a friend + function of a local class. + * name-lookup.c (lookup_name_innermost_nonclass_level): + No longer static. + * name-lookup.h: Declare it. + 2008-01-22 Tom Tromey <tromey@redhat.com> PR c++/34829: diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index 094501b1..ffb0baa 100644 --- a/gcc/cp/friend.c +++ b/gcc/cp/friend.c @@ -526,11 +526,25 @@ do_friend (tree ctype, tree declarator, tree decl, is instantiated. */ decl = push_template_decl_real (decl, /*is_friend=*/true); else if (current_function_decl) - /* This must be a local class, so pushdecl will be ok, and - insert an unqualified friend into the local scope - (rather than the containing namespace scope, which the - next choice will do). */ - decl = pushdecl_maybe_friend (decl, /*is_friend=*/true); + { + /* This must be a local class. 11.5p11: + + If a friend declaration appears in a local class (9.8) and + the name specified is an unqualified name, a prior + declaration is looked up without considering scopes that + are outside the innermost enclosing non-class scope. For a + friend function declaration, if there is no prior + declaration, the program is ill-formed. */ + tree t = lookup_name_innermost_nonclass_level (DECL_NAME (decl)); + if (t) + decl = pushdecl_maybe_friend (decl, /*is_friend=*/true); + else + { + error ("friend declaration %qD in local class without " + "prior declaration", decl); + return error_mark_node; + } + } else { /* We can't use pushdecl, as we might be in a template diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index c21940c..ded1d2e 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -43,7 +43,6 @@ struct scope_binding { static cxx_scope *innermost_nonclass_level (void); static cxx_binding *binding_for_name (cxx_scope *, tree); -static tree lookup_name_innermost_nonclass_level (tree); static tree push_overloaded_decl (tree, int, bool); static bool lookup_using_namespace (tree, struct scope_binding *, tree, tree, int); @@ -4202,7 +4201,7 @@ lookup_type_scope (tree name, tag_scope scope) /* Similar to `lookup_name' but look only in the innermost non-class binding level. */ -static tree +tree lookup_name_innermost_nonclass_level (tree name) { struct cp_binding_level *b; diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 7da57be..a4c057e 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -319,6 +319,7 @@ extern bool hidden_name_p (tree); extern tree remove_hidden_names (tree); extern tree lookup_qualified_name (tree, tree, bool, bool); extern tree lookup_name_nonclass (tree); +extern tree lookup_name_innermost_nonclass_level (tree); extern tree lookup_function_nonclass (tree, tree, bool); extern void push_local_binding (tree, tree, int); extern bool pushdecl_class_level (tree); diff --git a/gcc/testsuite/g++.dg/lookup/friend12.C b/gcc/testsuite/g++.dg/lookup/friend12.C new file mode 100644 index 0000000..95cfd5f --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/friend12.C @@ -0,0 +1,10 @@ +// PR c++/34912 + +void foo() +{ + struct A + { + friend void bar(); // { dg-error "without prior declaration" } + }; + bar(); // { dg-error "not declared" } +} diff --git a/gcc/testsuite/g++.dg/parse/local-class1.C b/gcc/testsuite/g++.dg/parse/local-class1.C index 4fc7e6e..518dd7a 100644 --- a/gcc/testsuite/g++.dg/parse/local-class1.C +++ b/gcc/testsuite/g++.dg/parse/local-class1.C @@ -9,6 +9,6 @@ void f () { class c { - friend void g () { } // { dg-error "local class definition" "" } + friend void g () { } // { dg-error "local class" "" } }; } diff --git a/gcc/testsuite/g++.old-deja/g++.jason/scoping12.C b/gcc/testsuite/g++.old-deja/g++.jason/scoping12.C index 3a1060a..a783416 100644 --- a/gcc/testsuite/g++.old-deja/g++.jason/scoping12.C +++ b/gcc/testsuite/g++.old-deja/g++.jason/scoping12.C @@ -2,7 +2,7 @@ void f () { struct A { - friend void g (); + friend void g (); // { dg-error "without prior declaration" } }; } void h () { |