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
This commit is contained in:
parent
b5ca4fd2f6
commit
7655e009c8
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
10
gcc/testsuite/g++.dg/lookup/friend12.C
Normal file
10
gcc/testsuite/g++.dg/lookup/friend12.C
Normal file
@ -0,0 +1,10 @@
|
||||
// PR c++/34912
|
||||
|
||||
void foo()
|
||||
{
|
||||
struct A
|
||||
{
|
||||
friend void bar(); // { dg-error "without prior declaration" }
|
||||
};
|
||||
bar(); // { dg-error "not declared" }
|
||||
}
|
@ -9,6 +9,6 @@ void f ()
|
||||
{
|
||||
class c
|
||||
{
|
||||
friend void g () { } // { dg-error "local class definition" "" }
|
||||
friend void g () { } // { dg-error "local class" "" }
|
||||
};
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
void f ()
|
||||
{
|
||||
struct A {
|
||||
friend void g ();
|
||||
friend void g (); // { dg-error "without prior declaration" }
|
||||
};
|
||||
}
|
||||
void h () {
|
||||
|
Loading…
Reference in New Issue
Block a user