From: jason Date: Tue, 22 Jan 2008 19:50:37 +0000 (+0000) Subject: PR c++/34912 X-Git-Tag: upstream/4.9.2~44035 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0bd414df9c57a5ae04871149d75557548728add5;p=platform%2Fupstream%2Flinaro-gcc.git 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@131740 138bc75d-0d04-0410-961f-82ee72b054a4 --- 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 + + 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 PR c++/34829: diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index 094501b..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 () {