mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-14 20:51:17 +08:00
re PR c++/7874 (g++ finds friend functions defined in class-definition but not declared in the enclosing namespace)
./ PR g++/7874 * c.opt (ffriend-injection): New C++ option. * doc/invoke.texi (Option Summary): Mention -ffriend-injection. (C++ Dialect Options): Document -ffriend-injection. cp/ PR g++/7874 * cp-tree.h (struct lang_decl_flags): Add hidden_friend_p bitfield. Make dummy bitfield one bit smaller. (DECL_HIDDEN_FRIEND_P): Define. (pushdecl_maybe_friend): Declare. (pushdecl_top_level_maybe_friend): Declare. * decl.c (duplicate_decls): Add newdecl_is_friend parameter. Change prototype and all callers. Add assertion that a DECL_ARTIFICIAL FUNCTION_DECL is not DECL_HIDDEN_FRIEND_P. Set DECL_ANTICIPATED and DECL_HIDDEN_FRIEND_P in duplicated decl if appropriate. * name-lookup.c (supplement_binding): Don't ignore a DECL_HIDDEN_FRIEND_P. (pushdecl_maybe_friend): Break out contents of pushdecl. Add is_friend parameter. Set DECL_ANTICIPATED and DECL_HIDDEN_FRIEND_P for a friend function. (pushdecl): Just call pushdecl_maybe_friend. (pushdecl_with_scope): Add is_friend parameter. Change prototype and all callers. (pushdecl_namespace_level): Likewise. (push_overloaded_decl): Likewise. Check DECL_HIDDEN_FRIEND_P as well as DECL_ANTICIPATED when checking for a builtin. (do_nonmember_using_decl): Check DECL_HIDDEN_FRIEND_P as well as DECL_ANTICIPATED when checking for a builtin. (do_nonmember_using_decl): Likewise. (pushdecl_top_level_1): Add is_friend parameter. Change all callers. (pushdecl_top_level_maybe_friend): New function. (remove_hidden_names): New function. (struct arg_lookup): Add args field. (friend_of_associated_class_p): New static function. (arg_assoc_namespace): Ignore hidden functions which are not friends of an associated class of some argument. (lookup_arg_dependent): Remove hidden functions from list passed in. Initialize k.args. * name-lookup.h (remove_hidden_names): Declare. * friend.c (do_friend): Call pushdecl_maybe_friend instead of pushdecl. * call.c (add_function_candidate): Change DECL_ANTICIPATED test to an assertion, with a check for DECL_HIDDEN_FRIEND_P. (build_new_function_call): Add koenig_p parameter. Change prototype and callers. * pt.c (register_specialization): Add is_friend parameter. Change all callers. (push_template_decl_real): Change is_friend parameter to bool. Change prototype and all callers. (tsubst_friend_class): Call pushdecl_top_level_maybe_friend instead of pushdecl_top_level. testsuite/ PR g++/7874 * g++.dg/lookup/friend7.C: New test. * g++.dg/lookup/friend8.C: New test. * g++.dg/parse/defarg4.C: Add a parameter to the friend function, so that it will be found via argument dependent lookup. * g++.old-deja/g++.brendan/crash56.C: Don't expect errors for friend functions which will no longer be found. * g++.old-deja/g++.jason/friend.C: Add a parameter to the friend function g, so that it will be found via argument dependent lookup. * g++.old-deja/g++.jason/scoping15.C: Use -ffriend-injection. * g++.old-deja/g++.mike/net43.C: Likewise. From-SVN: r104188
This commit is contained in:
parent
dbc564aea3
commit
d63d5d0c32
@ -1,3 +1,10 @@
|
||||
2005-09-12 Ian Lance Taylor <ian@airs.com>
|
||||
|
||||
PR g++/7874
|
||||
* c.opt (ffriend-injection): New C++ option.
|
||||
* doc/invoke.texi (Option Summary): Mention -ffriend-injection.
|
||||
(C++ Dialect Options): Document -ffriend-injection.
|
||||
|
||||
2005-09-12 Josh Conner <jconner@apple.com>
|
||||
|
||||
PR middle-end/23237
|
||||
|
@ -554,6 +554,10 @@ fimplicit-templates
|
||||
C++ ObjC++
|
||||
Emit implicit instantiations of templates
|
||||
|
||||
ffriend-injection
|
||||
C++ Var(flag_friend_injection)
|
||||
Inject friend functions into enclosing namespace
|
||||
|
||||
flabels-ok
|
||||
C++ ObjC++
|
||||
|
||||
|
@ -1,3 +1,54 @@
|
||||
2005-09-12 Ian Lance Taylor <ian@airs.com>
|
||||
|
||||
PR g++/7874
|
||||
* cp-tree.h (struct lang_decl_flags): Add hidden_friend_p
|
||||
bitfield. Make dummy bitfield one bit smaller.
|
||||
(DECL_HIDDEN_FRIEND_P): Define.
|
||||
(pushdecl_maybe_friend): Declare.
|
||||
(pushdecl_top_level_maybe_friend): Declare.
|
||||
* decl.c (duplicate_decls): Add newdecl_is_friend parameter.
|
||||
Change prototype and all callers. Add assertion that a
|
||||
DECL_ARTIFICIAL FUNCTION_DECL is not DECL_HIDDEN_FRIEND_P. Set
|
||||
DECL_ANTICIPATED and DECL_HIDDEN_FRIEND_P in duplicated decl if
|
||||
appropriate.
|
||||
* name-lookup.c (supplement_binding): Don't ignore a
|
||||
DECL_HIDDEN_FRIEND_P.
|
||||
(pushdecl_maybe_friend): Break out contents of pushdecl. Add
|
||||
is_friend parameter. Set DECL_ANTICIPATED and
|
||||
DECL_HIDDEN_FRIEND_P for a friend function.
|
||||
(pushdecl): Just call pushdecl_maybe_friend.
|
||||
(pushdecl_with_scope): Add is_friend parameter. Change prototype
|
||||
and all callers.
|
||||
(pushdecl_namespace_level): Likewise.
|
||||
(push_overloaded_decl): Likewise. Check DECL_HIDDEN_FRIEND_P as
|
||||
well as DECL_ANTICIPATED when checking for a builtin.
|
||||
(do_nonmember_using_decl): Check DECL_HIDDEN_FRIEND_P as well as
|
||||
DECL_ANTICIPATED when checking for a builtin.
|
||||
(do_nonmember_using_decl): Likewise.
|
||||
(pushdecl_top_level_1): Add is_friend parameter. Change all
|
||||
callers.
|
||||
(pushdecl_top_level_maybe_friend): New function.
|
||||
(remove_hidden_names): New function.
|
||||
(struct arg_lookup): Add args field.
|
||||
(friend_of_associated_class_p): New static function.
|
||||
(arg_assoc_namespace): Ignore hidden functions which are not
|
||||
friends of an associated class of some argument.
|
||||
(lookup_arg_dependent): Remove hidden functions from list passed
|
||||
in. Initialize k.args.
|
||||
* name-lookup.h (remove_hidden_names): Declare.
|
||||
* friend.c (do_friend): Call pushdecl_maybe_friend instead of
|
||||
pushdecl.
|
||||
* call.c (add_function_candidate): Change DECL_ANTICIPATED test to
|
||||
an assertion, with a check for DECL_HIDDEN_FRIEND_P.
|
||||
(build_new_function_call): Add koenig_p parameter. Change
|
||||
prototype and callers.
|
||||
* pt.c (register_specialization): Add is_friend parameter. Change
|
||||
all callers.
|
||||
(push_template_decl_real): Change is_friend parameter to bool.
|
||||
Change prototype and all callers.
|
||||
(tsubst_friend_class): Call pushdecl_top_level_maybe_friend
|
||||
instead of pushdecl_top_level.
|
||||
|
||||
2005-09-11 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* decl2.c (build_anon_union_vars): Copy attributes from the base addr.
|
||||
|
@ -1309,10 +1309,10 @@ add_function_candidate (struct z_candidate **candidates,
|
||||
tree orig_arglist;
|
||||
int viable = 1;
|
||||
|
||||
/* Built-in functions that haven't been declared don't really
|
||||
exist. */
|
||||
if (DECL_ANTICIPATED (fn))
|
||||
return NULL;
|
||||
/* At this point we should not see any functions which haven't been
|
||||
explicitly declared, except for friend functions which will have
|
||||
been found using argument dependent lookup. */
|
||||
gcc_assert (!DECL_ANTICIPATED (fn) || DECL_HIDDEN_FRIEND_P (fn));
|
||||
|
||||
/* The `this', `in_chrg' and VTT arguments to constructors are not
|
||||
considered in overload resolution. */
|
||||
@ -2758,7 +2758,7 @@ perform_overload_resolution (tree fn,
|
||||
or a static member function) with the ARGS. */
|
||||
|
||||
tree
|
||||
build_new_function_call (tree fn, tree args)
|
||||
build_new_function_call (tree fn, tree args, bool koenig_p)
|
||||
{
|
||||
struct z_candidate *candidates, *cand;
|
||||
bool any_viable_p;
|
||||
@ -2769,6 +2769,22 @@ build_new_function_call (tree fn, tree args)
|
||||
if (args == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
/* If this function was found without using argument dependent
|
||||
lookup, then we want to ignore any undeclared friend
|
||||
functions. */
|
||||
if (!koenig_p)
|
||||
{
|
||||
tree orig_fn = fn;
|
||||
|
||||
fn = remove_hidden_names (fn);
|
||||
if (!fn)
|
||||
{
|
||||
error ("no matching function for call to %<%D(%A)%>",
|
||||
DECL_NAME (OVL_CURRENT (orig_fn)), args);
|
||||
return error_mark_node;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
||||
p = conversion_obstack_alloc (0);
|
||||
|
||||
|
@ -5645,7 +5645,8 @@ resolve_address_of_overloaded_function (tree target_type,
|
||||
one, or vice versa. */
|
||||
continue;
|
||||
|
||||
/* Ignore anticipated decls of undeclared builtins. */
|
||||
/* Ignore functions which haven't been explicitly
|
||||
declared. */
|
||||
if (DECL_ANTICIPATED (fn))
|
||||
continue;
|
||||
|
||||
|
@ -1512,7 +1512,8 @@ struct lang_decl_flags GTY(())
|
||||
unsigned thunk_p : 1;
|
||||
unsigned this_thunk_p : 1;
|
||||
unsigned repo_available_p : 1;
|
||||
unsigned dummy : 3;
|
||||
unsigned hidden_friend_p : 1;
|
||||
unsigned dummy : 2;
|
||||
|
||||
union lang_decl_u {
|
||||
/* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
|
||||
@ -1814,9 +1815,8 @@ struct lang_decl GTY(())
|
||||
#define DECL_INITIALIZED_IN_CLASS_P(DECL) \
|
||||
(DECL_LANG_SPECIFIC (DECL)->decl_flags.initialized_in_class)
|
||||
|
||||
/* Nonzero for FUNCTION_DECL means that this decl is just a
|
||||
friend declaration, and should not be added to the list of
|
||||
member functions for this class. */
|
||||
/* Nonzero for DECL means that this decl is just a friend declaration,
|
||||
and should not be added to the list of members for this class. */
|
||||
#define DECL_FRIEND_P(NODE) (DECL_LANG_SPECIFIC (NODE)->decl_flags.friend_attr)
|
||||
|
||||
/* A TREE_LIST of the types which have befriended this FUNCTION_DECL. */
|
||||
@ -2321,11 +2321,19 @@ extern void decl_shadowed_for_var_insert (tree, tree);
|
||||
#define DECL_LOCAL_FUNCTION_P(NODE) \
|
||||
DECL_LANG_FLAG_0 (FUNCTION_DECL_CHECK (NODE))
|
||||
|
||||
/* Nonzero if NODE is a FUNCTION_DECL for a built-in function, and we have
|
||||
not yet seen a prototype for that function. */
|
||||
/* Nonzero if NODE is a DECL which we know about but which has not
|
||||
been explicitly declared, such as a built-in function or a friend
|
||||
declared inside a class. In the latter case DECL_HIDDEN_FRIEND_P
|
||||
will be set. */
|
||||
#define DECL_ANTICIPATED(NODE) \
|
||||
(DECL_LANG_SPECIFIC (DECL_COMMON_CHECK (NODE))->decl_flags.anticipated_p)
|
||||
|
||||
/* Nonzero if NODE is a FUNCTION_DECL which was declared as a friend
|
||||
within a class but has not been declared in the surrounding scope.
|
||||
The function is invisible except via argument dependent lookup. */
|
||||
#define DECL_HIDDEN_FRIEND_P(NODE) \
|
||||
(DECL_LANG_SPECIFIC (DECL_COMMON_CHECK (NODE))->decl_flags.hidden_friend_p)
|
||||
|
||||
/* Record whether a typedef for type `int' was actually `signed int'. */
|
||||
#define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP)
|
||||
|
||||
@ -3644,7 +3652,7 @@ extern bool null_ptr_cst_p (tree);
|
||||
extern bool sufficient_parms_p (tree);
|
||||
extern tree type_decays_to (tree);
|
||||
extern tree build_user_type_conversion (tree, tree, int);
|
||||
extern tree build_new_function_call (tree, tree);
|
||||
extern tree build_new_function_call (tree, tree, bool);
|
||||
extern tree build_operator_new_call (tree, tree, tree *, tree *);
|
||||
extern tree build_new_method_call (tree, tree, tree, tree, int);
|
||||
extern tree build_special_member_call (tree, tree, tree, tree, int);
|
||||
@ -3743,6 +3751,7 @@ extern void adjust_clone_args (tree);
|
||||
extern tree poplevel (int, int, int);
|
||||
extern void insert_block (tree);
|
||||
extern tree pushdecl (tree);
|
||||
extern tree pushdecl_maybe_friend (tree, bool);
|
||||
extern void cxx_init_decl_processing (void);
|
||||
enum cp_tree_node_structure_enum cp_tree_node_structure
|
||||
(union lang_tree_node *);
|
||||
@ -3756,8 +3765,9 @@ extern void pop_switch (void);
|
||||
extern tree pushtag (tree, tree, tag_scope);
|
||||
extern tree make_anon_name (void);
|
||||
extern int decls_match (tree, tree);
|
||||
extern tree duplicate_decls (tree, tree);
|
||||
extern tree duplicate_decls (tree, tree, bool);
|
||||
extern tree pushdecl_top_level (tree);
|
||||
extern tree pushdecl_top_level_maybe_friend (tree, bool);
|
||||
extern tree pushdecl_top_level_and_finish (tree, tree);
|
||||
extern tree push_using_decl (tree, tree);
|
||||
extern tree declare_local_label (tree);
|
||||
@ -3983,7 +3993,7 @@ extern tree end_template_parm_list (tree);
|
||||
extern void end_template_decl (void);
|
||||
extern tree current_template_args (void);
|
||||
extern tree push_template_decl (tree);
|
||||
extern tree push_template_decl_real (tree, int);
|
||||
extern tree push_template_decl_real (tree, bool);
|
||||
extern void redeclare_class_template (tree, tree);
|
||||
extern tree lookup_template_class (tree, tree, tree, tree,
|
||||
int, tsubst_flags_t);
|
||||
|
@ -1009,13 +1009,15 @@ warn_extern_redeclared_static (tree newdecl, tree olddecl)
|
||||
error_mark_node is returned. Otherwise, OLDDECL is returned.
|
||||
|
||||
If NEWDECL is not a redeclaration of OLDDECL, NULL_TREE is
|
||||
returned. */
|
||||
returned.
|
||||
|
||||
NEWDECL_IS_FRIEND is true if NEWDECL was declared as a friend. */
|
||||
|
||||
tree
|
||||
duplicate_decls (tree newdecl, tree olddecl)
|
||||
duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
|
||||
{
|
||||
unsigned olddecl_uid = DECL_UID (olddecl);
|
||||
int olddecl_friend = 0, types_match = 0;
|
||||
int olddecl_friend = 0, types_match = 0, hidden_friend = 0;
|
||||
int new_defines_function = 0;
|
||||
|
||||
if (newdecl == olddecl)
|
||||
@ -1069,9 +1071,11 @@ duplicate_decls (tree newdecl, tree olddecl)
|
||||
if (TREE_CODE (olddecl) == FUNCTION_DECL
|
||||
&& DECL_ARTIFICIAL (olddecl))
|
||||
{
|
||||
gcc_assert (!DECL_HIDDEN_FRIEND_P (olddecl));
|
||||
if (TREE_CODE (newdecl) != FUNCTION_DECL)
|
||||
{
|
||||
/* Avoid warnings redeclaring anticipated built-ins. */
|
||||
/* Avoid warnings redeclaring built-ins which have not been
|
||||
explicitly declared. */
|
||||
if (DECL_ANTICIPATED (olddecl))
|
||||
return NULL_TREE;
|
||||
|
||||
@ -1102,7 +1106,8 @@ duplicate_decls (tree newdecl, tree olddecl)
|
||||
}
|
||||
else if (!types_match)
|
||||
{
|
||||
/* Avoid warnings redeclaring anticipated built-ins. */
|
||||
/* Avoid warnings redeclaring built-ins which have not been
|
||||
explicitly declared. */
|
||||
if (DECL_ANTICIPATED (olddecl))
|
||||
{
|
||||
/* Deal with fileptr_type_node. FILE type is not known
|
||||
@ -1131,7 +1136,8 @@ duplicate_decls (tree newdecl, tree olddecl)
|
||||
= TYPE_ARG_TYPES (TREE_TYPE (newdecl));
|
||||
types_match = decls_match (newdecl, olddecl);
|
||||
if (types_match)
|
||||
return duplicate_decls (newdecl, olddecl);
|
||||
return duplicate_decls (newdecl, olddecl,
|
||||
newdecl_is_friend);
|
||||
TYPE_ARG_TYPES (TREE_TYPE (olddecl)) = oldargs;
|
||||
}
|
||||
}
|
||||
@ -1163,8 +1169,9 @@ duplicate_decls (tree newdecl, tree olddecl)
|
||||
/* Replace the old RTL to avoid problems with inlining. */
|
||||
COPY_DECL_RTL (newdecl, olddecl);
|
||||
}
|
||||
/* Even if the types match, prefer the new declarations type
|
||||
for anticipated built-ins, for exception lists, etc... */
|
||||
/* Even if the types match, prefer the new declarations type for
|
||||
built-ins which have not been explicitly declared, for
|
||||
exception lists, etc... */
|
||||
else if (DECL_ANTICIPATED (olddecl))
|
||||
{
|
||||
tree type = TREE_TYPE (newdecl);
|
||||
@ -1460,7 +1467,7 @@ duplicate_decls (tree newdecl, tree olddecl)
|
||||
/* Don't warn about extern decl followed by definition. */
|
||||
&& !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl))
|
||||
/* Don't warn about friends, let add_friend take care of it. */
|
||||
&& ! (DECL_FRIEND_P (newdecl) || DECL_FRIEND_P (olddecl)))
|
||||
&& ! (newdecl_is_friend || DECL_FRIEND_P (olddecl)))
|
||||
{
|
||||
warning (0, "redundant redeclaration of %qD in same scope", newdecl);
|
||||
warning (0, "previous declaration of %q+D", olddecl);
|
||||
@ -1685,6 +1692,9 @@ duplicate_decls (tree newdecl, tree olddecl)
|
||||
DECL_INITIALIZED_IN_CLASS_P (newdecl)
|
||||
|= DECL_INITIALIZED_IN_CLASS_P (olddecl);
|
||||
olddecl_friend = DECL_FRIEND_P (olddecl);
|
||||
hidden_friend = (DECL_ANTICIPATED (olddecl)
|
||||
&& DECL_HIDDEN_FRIEND_P (olddecl)
|
||||
&& newdecl_is_friend);
|
||||
|
||||
/* Only functions have DECL_BEFRIENDING_CLASSES. */
|
||||
if (TREE_CODE (newdecl) == FUNCTION_DECL
|
||||
@ -1898,6 +1908,11 @@ duplicate_decls (tree newdecl, tree olddecl)
|
||||
DECL_UID (olddecl) = olddecl_uid;
|
||||
if (olddecl_friend)
|
||||
DECL_FRIEND_P (olddecl) = 1;
|
||||
if (hidden_friend)
|
||||
{
|
||||
DECL_ANTICIPATED (olddecl) = 1;
|
||||
DECL_HIDDEN_FRIEND_P (olddecl) = 1;
|
||||
}
|
||||
|
||||
/* NEWDECL contains the merged attribute lists.
|
||||
Update OLDDECL to be the same. */
|
||||
@ -3142,7 +3157,7 @@ cp_make_fname_decl (tree id, int type_dep)
|
||||
struct cp_binding_level *b = current_binding_level;
|
||||
while (b->level_chain->kind != sk_function_parms)
|
||||
b = b->level_chain;
|
||||
pushdecl_with_scope (decl, b);
|
||||
pushdecl_with_scope (decl, b, /*is_friend=*/false);
|
||||
cp_finish_decl (decl, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
|
||||
}
|
||||
else
|
||||
@ -3185,8 +3200,9 @@ builtin_function_1 (const char* name,
|
||||
if (libname)
|
||||
SET_DECL_ASSEMBLER_NAME (decl, get_identifier (libname));
|
||||
|
||||
/* Warn if a function in the namespace for users
|
||||
is used without an occasion to consider it declared. */
|
||||
/* A function in the user's namespace should have an explicit
|
||||
declaration before it is used. Mark the built-in function as
|
||||
anticipated but not actually declared. */
|
||||
if (name[0] != '_' || name[1] != '_')
|
||||
DECL_ANTICIPATED (decl) = 1;
|
||||
|
||||
@ -3720,7 +3736,7 @@ start_decl (const cp_declarator *declarator,
|
||||
if (DECL_INITIAL (decl)
|
||||
&& DECL_INITIALIZED_IN_CLASS_P (field))
|
||||
error ("duplicate initialization of %qD", decl);
|
||||
if (duplicate_decls (decl, field))
|
||||
if (duplicate_decls (decl, field, /*newdecl_is_friend=*/false))
|
||||
decl = field;
|
||||
}
|
||||
}
|
||||
@ -3731,7 +3747,8 @@ start_decl (const cp_declarator *declarator,
|
||||
> template_class_depth (context))
|
||||
? current_template_parms
|
||||
: NULL_TREE);
|
||||
if (field && duplicate_decls (decl, field))
|
||||
if (field && duplicate_decls (decl, field,
|
||||
/*newdecl_is_friend=*/false))
|
||||
decl = field;
|
||||
}
|
||||
|
||||
@ -5871,7 +5888,7 @@ grokfndecl (tree ctype,
|
||||
/* Attempt to merge the declarations. This can fail, in
|
||||
the case of some invalid specialization declarations. */
|
||||
pushed_scope = push_scope (ctype);
|
||||
ok = duplicate_decls (decl, old_decl);
|
||||
ok = duplicate_decls (decl, old_decl, friendp);
|
||||
if (pushed_scope)
|
||||
pop_scope (pushed_scope);
|
||||
if (!ok)
|
||||
|
@ -480,7 +480,7 @@ do_friend (tree ctype, tree declarator, tree decl,
|
||||
else if (class_template_depth)
|
||||
/* We rely on tsubst_friend_function to check the
|
||||
validity of the declaration later. */
|
||||
decl = push_template_decl_real (decl, /*is_friend=*/1);
|
||||
decl = push_template_decl_real (decl, /*is_friend=*/true);
|
||||
else
|
||||
decl = check_classfn (ctype, decl,
|
||||
template_member_p
|
||||
@ -527,13 +527,13 @@ do_friend (tree ctype, tree declarator, tree decl,
|
||||
general, such a declaration depends on template
|
||||
parameters. Instead, we call pushdecl when the class
|
||||
is instantiated. */
|
||||
decl = push_template_decl_real (decl, /*is_friend=*/1);
|
||||
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 (decl);
|
||||
decl = pushdecl_maybe_friend (decl, /*is_friend=*/true);
|
||||
else
|
||||
{
|
||||
/* We can't use pushdecl, as we might be in a template
|
||||
@ -543,7 +543,7 @@ do_friend (tree ctype, tree declarator, tree decl,
|
||||
tree ns = decl_namespace_context (decl);
|
||||
|
||||
push_nested_namespace (ns);
|
||||
decl = pushdecl_namespace_level (decl);
|
||||
decl = pushdecl_namespace_level (decl, /*is_friend=*/true);
|
||||
pop_nested_namespace (ns);
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ static cxx_scope *innermost_nonclass_level (void);
|
||||
static tree select_decl (const struct scope_binding *, int);
|
||||
static cxx_binding *binding_for_name (cxx_scope *, tree);
|
||||
static tree lookup_name_innermost_nonclass_level (tree);
|
||||
static tree push_overloaded_decl (tree, int);
|
||||
static tree push_overloaded_decl (tree, int, bool);
|
||||
static bool lookup_using_namespace (tree, struct scope_binding *, tree,
|
||||
tree, int);
|
||||
static bool qualified_lookup_using_namespace (tree, tree,
|
||||
@ -437,10 +437,11 @@ supplement_binding (cxx_binding *binding, tree decl)
|
||||
error recovery purpose, pretend this was the intended
|
||||
declaration for that name. */
|
||||
|| bval == error_mark_node
|
||||
/* If BVAL is a built-in that has not yet been declared,
|
||||
/* If BVAL is anticipated but has not yet been declared,
|
||||
pretend it is not there at all. */
|
||||
|| (TREE_CODE (bval) == FUNCTION_DECL
|
||||
&& DECL_ANTICIPATED (bval)))
|
||||
&& DECL_ANTICIPATED (bval)
|
||||
&& !DECL_HIDDEN_FRIEND_P (bval)))
|
||||
binding->value = decl;
|
||||
else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval))
|
||||
{
|
||||
@ -487,7 +488,7 @@ supplement_binding (cxx_binding *binding, tree decl)
|
||||
&& DECL_EXTERNAL (decl) && DECL_EXTERNAL (bval)
|
||||
&& !DECL_CLASS_SCOPE_P (decl))
|
||||
{
|
||||
duplicate_decls (decl, binding->value);
|
||||
duplicate_decls (decl, binding->value, /*newdecl_is_friend=*/false);
|
||||
ok = false;
|
||||
}
|
||||
else if (TREE_CODE (decl) == NAMESPACE_DECL
|
||||
@ -551,14 +552,15 @@ add_decl_to_level (tree decl, cxx_scope *b)
|
||||
|
||||
/* Record a decl-node X as belonging to the current lexical scope.
|
||||
Check for errors (such as an incompatible declaration for the same
|
||||
name already seen in the same scope).
|
||||
name already seen in the same scope). IS_FRIEND is true if X is
|
||||
declared as a friend.
|
||||
|
||||
Returns either X or an old decl for the same name.
|
||||
If an old decl is returned, it may have been smashed
|
||||
to agree with what X says. */
|
||||
|
||||
tree
|
||||
pushdecl (tree x)
|
||||
pushdecl_maybe_friend (tree x, bool is_friend)
|
||||
{
|
||||
tree t;
|
||||
tree name;
|
||||
@ -679,7 +681,7 @@ pushdecl (tree x)
|
||||
gcc_assert (DECL_CONTEXT (t));
|
||||
|
||||
/* Check for duplicate params. */
|
||||
if (duplicate_decls (x, t))
|
||||
if (duplicate_decls (x, t, is_friend))
|
||||
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
|
||||
}
|
||||
else if ((DECL_EXTERN_C_FUNCTION_P (x)
|
||||
@ -697,7 +699,7 @@ pushdecl (tree x)
|
||||
}
|
||||
else
|
||||
{
|
||||
tree olddecl = duplicate_decls (x, t);
|
||||
tree olddecl = duplicate_decls (x, t, is_friend);
|
||||
|
||||
/* If the redeclaration failed, we can stop at this
|
||||
point. */
|
||||
@ -742,7 +744,7 @@ pushdecl (tree x)
|
||||
|
||||
if (DECL_NON_THUNK_FUNCTION_P (x) && ! DECL_FUNCTION_MEMBER_P (x))
|
||||
{
|
||||
t = push_overloaded_decl (x, PUSH_LOCAL);
|
||||
t = push_overloaded_decl (x, PUSH_LOCAL, is_friend);
|
||||
if (t != x)
|
||||
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
|
||||
if (!namespace_bindings_p ())
|
||||
@ -753,7 +755,7 @@ pushdecl (tree x)
|
||||
}
|
||||
else if (DECL_FUNCTION_TEMPLATE_P (x) && DECL_NAMESPACE_SCOPE_P (x))
|
||||
{
|
||||
t = push_overloaded_decl (x, PUSH_GLOBAL);
|
||||
t = push_overloaded_decl (x, PUSH_GLOBAL, is_friend);
|
||||
if (t == x)
|
||||
add_decl_to_level (x, NAMESPACE_LEVEL (CP_DECL_CONTEXT (t)));
|
||||
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
|
||||
@ -815,6 +817,16 @@ pushdecl (tree x)
|
||||
}
|
||||
}
|
||||
|
||||
if (TREE_CODE (x) == FUNCTION_DECL
|
||||
&& is_friend
|
||||
&& !flag_friend_injection)
|
||||
{
|
||||
/* This is a new declaration of a friend function, so hide
|
||||
it from ordinary function lookup. */
|
||||
DECL_ANTICIPATED (x) = 1;
|
||||
DECL_HIDDEN_FRIEND_P (x) = 1;
|
||||
}
|
||||
|
||||
/* This name is new in its binding level.
|
||||
Install the new declaration and return it. */
|
||||
if (namespace_bindings_p ())
|
||||
@ -997,6 +1009,14 @@ pushdecl (tree x)
|
||||
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);
|
||||
}
|
||||
|
||||
/* Record a decl-node X as belonging to the current lexical scope. */
|
||||
|
||||
tree
|
||||
pushdecl (tree x)
|
||||
{
|
||||
return pushdecl_maybe_friend (x, false);
|
||||
}
|
||||
|
||||
/* Enter DECL into the symbol table, if that's appropriate. Returns
|
||||
DECL, or a modified version thereof. */
|
||||
|
||||
@ -1795,7 +1815,7 @@ push_using_decl (tree scope, tree name)
|
||||
caller to set DECL_CONTEXT properly. */
|
||||
|
||||
tree
|
||||
pushdecl_with_scope (tree x, cxx_scope *level)
|
||||
pushdecl_with_scope (tree x, cxx_scope *level, bool is_friend)
|
||||
{
|
||||
struct cp_binding_level *b;
|
||||
tree function_decl = current_function_decl;
|
||||
@ -1813,7 +1833,7 @@ pushdecl_with_scope (tree x, cxx_scope *level)
|
||||
{
|
||||
b = current_binding_level;
|
||||
current_binding_level = level;
|
||||
x = pushdecl (x);
|
||||
x = pushdecl_maybe_friend (x, is_friend);
|
||||
current_binding_level = b;
|
||||
}
|
||||
current_function_decl = function_decl;
|
||||
@ -1835,12 +1855,14 @@ pushdecl_with_scope (tree x, cxx_scope *level)
|
||||
PUSH_USING: DECL is being pushed as the result of a using
|
||||
declaration.
|
||||
|
||||
IS_FRIEND is true if this is a friend declaration.
|
||||
|
||||
The value returned may be a previous declaration if we guessed wrong
|
||||
about what language DECL should belong to (C or C++). Otherwise,
|
||||
it's always DECL (and never something that's not a _DECL). */
|
||||
|
||||
static tree
|
||||
push_overloaded_decl (tree decl, int flags)
|
||||
push_overloaded_decl (tree decl, int flags, bool is_friend)
|
||||
{
|
||||
tree name = DECL_NAME (decl);
|
||||
tree old;
|
||||
@ -1880,7 +1902,7 @@ push_overloaded_decl (tree decl, int flags)
|
||||
error ("%q#D conflicts with previous using declaration %q#D",
|
||||
decl, fn);
|
||||
|
||||
if (duplicate_decls (decl, fn) == fn)
|
||||
if (duplicate_decls (decl, fn, is_friend) == fn)
|
||||
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, fn);
|
||||
}
|
||||
|
||||
@ -1888,7 +1910,8 @@ push_overloaded_decl (tree decl, int flags)
|
||||
may fail to merge the decls if the new decl is e.g. a
|
||||
template function. */
|
||||
if (TREE_CODE (old) == FUNCTION_DECL
|
||||
&& DECL_ANTICIPATED (old))
|
||||
&& DECL_ANTICIPATED (old)
|
||||
&& !DECL_HIDDEN_FRIEND_P (old))
|
||||
old = NULL;
|
||||
}
|
||||
else if (old == error_mark_node)
|
||||
@ -2037,7 +2060,8 @@ do_nonmember_using_decl (tree scope, tree name, tree oldval, tree oldtype,
|
||||
is a built-in, then we can just pretend it isn't there. */
|
||||
if (oldval
|
||||
&& TREE_CODE (oldval) == FUNCTION_DECL
|
||||
&& DECL_ANTICIPATED (oldval))
|
||||
&& DECL_ANTICIPATED (oldval)
|
||||
&& !DECL_HIDDEN_FRIEND_P (oldval))
|
||||
oldval = NULL_TREE;
|
||||
|
||||
/* Check for using functions. */
|
||||
@ -2075,7 +2099,8 @@ do_nonmember_using_decl (tree scope, tree name, tree oldval, tree oldtype,
|
||||
else if (compparms (TYPE_ARG_TYPES (TREE_TYPE (new_fn)),
|
||||
TYPE_ARG_TYPES (TREE_TYPE (old_fn))))
|
||||
{
|
||||
gcc_assert (!DECL_ANTICIPATED (old_fn));
|
||||
gcc_assert (!DECL_ANTICIPATED (old_fn)
|
||||
|| DECL_HIDDEN_FRIEND_P (old_fn));
|
||||
|
||||
/* There was already a non-using declaration in
|
||||
this scope with the same parameter types. If both
|
||||
@ -2168,7 +2193,8 @@ do_local_using_decl (tree decl, tree scope, tree name)
|
||||
for (fn = newval; fn && OVL_CURRENT (fn) != term;
|
||||
fn = OVL_NEXT (fn))
|
||||
push_overloaded_decl (OVL_CURRENT (fn),
|
||||
PUSH_LOCAL | PUSH_USING);
|
||||
PUSH_LOCAL | PUSH_USING,
|
||||
false);
|
||||
}
|
||||
else
|
||||
push_local_binding (name, newval, PUSH_USING);
|
||||
@ -3058,13 +3084,13 @@ do_namespace_alias (tree alias, tree namespace)
|
||||
if appropriate. */
|
||||
|
||||
tree
|
||||
pushdecl_namespace_level (tree x)
|
||||
pushdecl_namespace_level (tree x, bool is_friend)
|
||||
{
|
||||
struct cp_binding_level *b = current_binding_level;
|
||||
tree t;
|
||||
|
||||
timevar_push (TV_NAME_LOOKUP);
|
||||
t = pushdecl_with_scope (x, NAMESPACE_LEVEL (current_namespace));
|
||||
t = pushdecl_with_scope (x, NAMESPACE_LEVEL (current_namespace), is_friend);
|
||||
|
||||
/* Now, the type_shadowed stack may screw us. Munge it so it does
|
||||
what we want. */
|
||||
@ -3247,11 +3273,11 @@ parse_using_directive (tree namespace, tree attribs)
|
||||
*INIT, if INIT is non-NULL. */
|
||||
|
||||
static tree
|
||||
pushdecl_top_level_1 (tree x, tree *init)
|
||||
pushdecl_top_level_1 (tree x, tree *init, bool is_friend)
|
||||
{
|
||||
timevar_push (TV_NAME_LOOKUP);
|
||||
push_to_top_level ();
|
||||
x = pushdecl_namespace_level (x);
|
||||
x = pushdecl_namespace_level (x, is_friend);
|
||||
if (init)
|
||||
cp_finish_decl (x, *init, NULL_TREE, 0);
|
||||
pop_from_top_level ();
|
||||
@ -3263,7 +3289,15 @@ pushdecl_top_level_1 (tree x, tree *init)
|
||||
tree
|
||||
pushdecl_top_level (tree x)
|
||||
{
|
||||
return pushdecl_top_level_1 (x, NULL);
|
||||
return pushdecl_top_level_1 (x, NULL, false);
|
||||
}
|
||||
|
||||
/* Like pushdecl_top_level, but adding the IS_FRIEND parameter. */
|
||||
|
||||
tree
|
||||
pushdecl_top_level_maybe_friend (tree x, bool is_friend)
|
||||
{
|
||||
return pushdecl_top_level_1 (x, NULL, is_friend);
|
||||
}
|
||||
|
||||
/* Like pushdecl, only it places X in the global scope if
|
||||
@ -3273,7 +3307,7 @@ pushdecl_top_level (tree x)
|
||||
tree
|
||||
pushdecl_top_level_and_finish (tree x, tree init)
|
||||
{
|
||||
return pushdecl_top_level_1 (x, &init);
|
||||
return pushdecl_top_level_1 (x, &init, false);
|
||||
}
|
||||
|
||||
/* Combines two sets of overloaded functions into an OVERLOAD chain, removing
|
||||
@ -3440,7 +3474,7 @@ qualify_lookup (tree val, int flags)
|
||||
}
|
||||
|
||||
/* Given a lookup that returned VAL, decide if we want to ignore it or
|
||||
not based on DECL_ANTICIPATED_P. */
|
||||
not based on DECL_ANTICIPATED. */
|
||||
|
||||
bool
|
||||
hidden_name_p (tree val)
|
||||
@ -3452,6 +3486,38 @@ hidden_name_p (tree val)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Remove any hidden friend functions from a possibly overloaded set
|
||||
of functions. */
|
||||
|
||||
tree
|
||||
remove_hidden_names (tree fns)
|
||||
{
|
||||
if (!fns)
|
||||
return fns;
|
||||
|
||||
if (TREE_CODE (fns) == FUNCTION_DECL && hidden_name_p (fns))
|
||||
fns = NULL_TREE;
|
||||
else if (TREE_CODE (fns) == OVERLOAD)
|
||||
{
|
||||
tree o;
|
||||
|
||||
for (o = fns; o; o = OVL_NEXT (o))
|
||||
if (hidden_name_p (OVL_CURRENT (o)))
|
||||
break;
|
||||
if (o)
|
||||
{
|
||||
tree n = NULL_TREE;
|
||||
|
||||
for (o = fns; o; o = OVL_NEXT (o))
|
||||
if (!hidden_name_p (OVL_CURRENT (o)))
|
||||
n = build_overload (OVL_CURRENT (o), n);
|
||||
fns = n;
|
||||
}
|
||||
}
|
||||
|
||||
return fns;
|
||||
}
|
||||
|
||||
/* Look up NAME in the NAMESPACE. */
|
||||
|
||||
tree
|
||||
@ -4112,6 +4178,7 @@ lookup_type_current_level (tree name)
|
||||
struct arg_lookup
|
||||
{
|
||||
tree name;
|
||||
tree args;
|
||||
tree namespaces;
|
||||
tree classes;
|
||||
tree functions;
|
||||
@ -4190,6 +4257,53 @@ is_associated_namespace (tree current, tree scope)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return whether FN is a friend of an associated class of ARG. */
|
||||
|
||||
static bool
|
||||
friend_of_associated_class_p (tree arg, tree fn)
|
||||
{
|
||||
tree type;
|
||||
|
||||
if (TYPE_P (arg))
|
||||
type = arg;
|
||||
else if (type_unknown_p (arg))
|
||||
return false;
|
||||
else
|
||||
type = TREE_TYPE (arg);
|
||||
|
||||
/* If TYPE is a class, the class itself and all base classes are
|
||||
associated classes. */
|
||||
if (CLASS_TYPE_P (type))
|
||||
{
|
||||
if (is_friend (type, fn))
|
||||
return true;
|
||||
|
||||
if (TYPE_BINFO (type))
|
||||
{
|
||||
tree binfo, base_binfo;
|
||||
int i;
|
||||
|
||||
for (binfo = TYPE_BINFO (type), i = 0;
|
||||
BINFO_BASE_ITERATE (binfo, i, base_binfo);
|
||||
i++)
|
||||
if (is_friend (BINFO_TYPE (base_binfo), fn))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* If TYPE is a class member, the class of which it is a member is
|
||||
an associated class. */
|
||||
if ((CLASS_TYPE_P (type)
|
||||
|| TREE_CODE (type) == UNION_TYPE
|
||||
|| TREE_CODE (type) == ENUMERAL_TYPE)
|
||||
&& TYPE_CONTEXT (type)
|
||||
&& CLASS_TYPE_P (TYPE_CONTEXT (type))
|
||||
&& is_friend (TYPE_CONTEXT (type), fn))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add functions of a namespace to the lookup structure.
|
||||
Returns true on error. */
|
||||
|
||||
@ -4213,8 +4327,25 @@ arg_assoc_namespace (struct arg_lookup *k, tree scope)
|
||||
return false;
|
||||
|
||||
for (; value; value = OVL_NEXT (value))
|
||||
if (add_function (k, OVL_CURRENT (value)))
|
||||
return true;
|
||||
{
|
||||
/* We don't want to find arbitrary hidden functions via argument
|
||||
dependent lookup. We only want to find friends of associated
|
||||
classes. */
|
||||
if (hidden_name_p (OVL_CURRENT (value)))
|
||||
{
|
||||
tree args;
|
||||
|
||||
for (args = k->args; args; args = TREE_CHAIN (args))
|
||||
if (friend_of_associated_class_p (TREE_VALUE (args),
|
||||
OVL_CURRENT (value)))
|
||||
break;
|
||||
if (!args)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (add_function (k, OVL_CURRENT (value)))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -4485,7 +4616,14 @@ lookup_arg_dependent (tree name, tree fns, tree args)
|
||||
struct arg_lookup k;
|
||||
|
||||
timevar_push (TV_NAME_LOOKUP);
|
||||
|
||||
/* Remove any hidden friend functions from the list of functions
|
||||
found so far. They will be added back by arg_assoc_class as
|
||||
appropriate. */
|
||||
fns = remove_hidden_names (fns);
|
||||
|
||||
k.name = name;
|
||||
k.args = args;
|
||||
k.functions = fns;
|
||||
k.classes = NULL_TREE;
|
||||
|
||||
@ -4699,7 +4837,7 @@ pushtag (tree name, tree type, tag_scope scope)
|
||||
pushdecl_class_level (decl);
|
||||
}
|
||||
else if (b->kind != sk_template_parms)
|
||||
decl = pushdecl_with_scope (decl, b);
|
||||
decl = pushdecl_with_scope (decl, b, /*is_friend=*/false);
|
||||
|
||||
TYPE_CONTEXT (type) = DECL_CONTEXT (decl);
|
||||
|
||||
|
@ -311,20 +311,21 @@ extern void push_nested_namespace (tree);
|
||||
extern void pop_nested_namespace (tree);
|
||||
extern void pushlevel_class (void);
|
||||
extern void poplevel_class (void);
|
||||
extern tree pushdecl_with_scope (tree, cxx_scope *);
|
||||
extern tree pushdecl_with_scope (tree, cxx_scope *, bool);
|
||||
extern tree lookup_name (tree, int);
|
||||
extern tree lookup_name_real (tree, int, int, bool, int, int);
|
||||
extern tree lookup_type_scope (tree, tag_scope);
|
||||
extern tree namespace_binding (tree, tree);
|
||||
extern void set_namespace_binding (tree, tree, tree);
|
||||
extern bool hidden_name_p (tree);
|
||||
extern tree remove_hidden_names (tree);
|
||||
extern tree lookup_namespace_name (tree, tree);
|
||||
extern tree lookup_qualified_name (tree, tree, bool, bool);
|
||||
extern tree lookup_name_nonclass (tree);
|
||||
extern tree lookup_function_nonclass (tree, tree, bool);
|
||||
extern void push_local_binding (tree, tree, int);
|
||||
extern bool pushdecl_class_level (tree);
|
||||
extern tree pushdecl_namespace_level (tree);
|
||||
extern tree pushdecl_namespace_level (tree, bool);
|
||||
extern bool push_class_level_binding (tree, tree);
|
||||
extern tree getdecls (void);
|
||||
extern tree cp_namespace_decls (tree);
|
||||
|
38
gcc/cp/pt.c
38
gcc/cp/pt.c
@ -1114,11 +1114,12 @@ is_specialization_of_friend (tree decl, tree friend)
|
||||
}
|
||||
|
||||
/* Register the specialization SPEC as a specialization of TMPL with
|
||||
the indicated ARGS. Returns SPEC, or an equivalent prior
|
||||
declaration, if available. */
|
||||
the indicated ARGS. IS_FRIEND indicates whether the specialization
|
||||
is actually just a friend declaration. Returns SPEC, or an
|
||||
equivalent prior declaration, if available. */
|
||||
|
||||
static tree
|
||||
register_specialization (tree spec, tree tmpl, tree args)
|
||||
register_specialization (tree spec, tree tmpl, tree args, bool is_friend)
|
||||
{
|
||||
tree fn;
|
||||
|
||||
@ -1185,14 +1186,14 @@ register_specialization (tree spec, tree tmpl, tree args)
|
||||
for the specialization, we want this to look as if
|
||||
there were no definition, and vice versa. */
|
||||
DECL_INITIAL (fn) = NULL_TREE;
|
||||
duplicate_decls (spec, fn);
|
||||
duplicate_decls (spec, fn, is_friend);
|
||||
|
||||
return fn;
|
||||
}
|
||||
}
|
||||
else if (DECL_TEMPLATE_SPECIALIZATION (fn))
|
||||
{
|
||||
if (!duplicate_decls (spec, fn) && DECL_INITIAL (spec))
|
||||
if (!duplicate_decls (spec, fn, is_friend) && DECL_INITIAL (spec))
|
||||
/* Dup decl failed, but this is a new definition. Set the
|
||||
line number so any errors match this new
|
||||
definition. */
|
||||
@ -2108,7 +2109,7 @@ check_explicit_specialization (tree declarator,
|
||||
|
||||
/* Register this specialization so that we can find it
|
||||
again. */
|
||||
decl = register_specialization (decl, gen_tmpl, targs);
|
||||
decl = register_specialization (decl, gen_tmpl, targs, is_friend);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2882,10 +2883,10 @@ template_parm_this_level_p (tree t, void* data)
|
||||
previously existing one, if appropriate. Returns the DECL, or an
|
||||
equivalent one, if it is replaced via a call to duplicate_decls.
|
||||
|
||||
If IS_FRIEND is nonzero, DECL is a friend declaration. */
|
||||
If IS_FRIEND is true, DECL is a friend declaration. */
|
||||
|
||||
tree
|
||||
push_template_decl_real (tree decl, int is_friend)
|
||||
push_template_decl_real (tree decl, bool is_friend)
|
||||
{
|
||||
tree tmpl;
|
||||
tree args;
|
||||
@ -2906,7 +2907,8 @@ push_template_decl_real (tree decl, int is_friend)
|
||||
&& TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
|
||||
&& CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)));
|
||||
|
||||
is_friend |= (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl));
|
||||
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl))
|
||||
is_friend = true;
|
||||
|
||||
if (is_friend)
|
||||
/* For a friend, we want the context of the friend function, not
|
||||
@ -3081,7 +3083,8 @@ push_template_decl_real (tree decl, int is_friend)
|
||||
|
||||
register_specialization (new_tmpl,
|
||||
most_general_template (tmpl),
|
||||
args);
|
||||
args,
|
||||
is_friend);
|
||||
return decl;
|
||||
}
|
||||
|
||||
@ -3132,7 +3135,7 @@ push_template_decl_real (tree decl, int is_friend)
|
||||
if (new_template_p && !ctx
|
||||
&& !(is_friend && template_class_depth (current_class_type) > 0))
|
||||
{
|
||||
tmpl = pushdecl_namespace_level (tmpl);
|
||||
tmpl = pushdecl_namespace_level (tmpl, is_friend);
|
||||
if (tmpl == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
@ -3187,7 +3190,7 @@ push_template_decl_real (tree decl, int is_friend)
|
||||
tree
|
||||
push_template_decl (tree decl)
|
||||
{
|
||||
return push_template_decl_real (decl, 0);
|
||||
return push_template_decl_real (decl, false);
|
||||
}
|
||||
|
||||
/* Called when a class template TYPE is redeclared with the indicated
|
||||
@ -5175,7 +5178,7 @@ tsubst_friend_function (tree decl, tree args)
|
||||
into the namespace of the template. */
|
||||
ns = decl_namespace_context (new_friend);
|
||||
push_nested_namespace (ns);
|
||||
old_decl = pushdecl_namespace_level (new_friend);
|
||||
old_decl = pushdecl_namespace_level (new_friend, /*is_friend=*/true);
|
||||
pop_nested_namespace (ns);
|
||||
|
||||
if (old_decl != new_friend)
|
||||
@ -5387,7 +5390,7 @@ tsubst_friend_class (tree friend_tmpl, tree args)
|
||||
= INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl)));
|
||||
|
||||
/* Inject this template into the global scope. */
|
||||
friend_type = TREE_TYPE (pushdecl_top_level (tmpl));
|
||||
friend_type = TREE_TYPE (pushdecl_top_level_maybe_friend (tmpl, true));
|
||||
}
|
||||
|
||||
if (context)
|
||||
@ -6302,7 +6305,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
|
||||
if (TREE_CODE (decl) != TYPE_DECL)
|
||||
/* Record this non-type partial instantiation. */
|
||||
register_specialization (r, t,
|
||||
DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)));
|
||||
DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),
|
||||
false);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -6477,7 +6481,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
|
||||
DECL_TEMPLATE_INFO (r)
|
||||
= tree_cons (gen_tmpl, argvec, NULL_TREE);
|
||||
SET_DECL_IMPLICIT_INSTANTIATION (r);
|
||||
register_specialization (r, gen_tmpl, argvec);
|
||||
register_specialization (r, gen_tmpl, argvec, false);
|
||||
|
||||
/* We're not supposed to instantiate default arguments
|
||||
until they are called, for a template. But, for a
|
||||
@ -6706,7 +6710,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
|
||||
processing here. */
|
||||
DECL_EXTERNAL (r) = 1;
|
||||
|
||||
register_specialization (r, gen_tmpl, argvec);
|
||||
register_specialization (r, gen_tmpl, argvec, false);
|
||||
DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE);
|
||||
SET_DECL_IMPLICIT_INSTANTIATION (r);
|
||||
}
|
||||
|
@ -1822,7 +1822,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
|
||||
|
||||
if (!result)
|
||||
/* A call to a namespace-scope function. */
|
||||
result = build_new_function_call (fn, args);
|
||||
result = build_new_function_call (fn, args, koenig_p);
|
||||
}
|
||||
else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
|
||||
{
|
||||
|
@ -171,7 +171,7 @@ in the following sections.
|
||||
@item C++ Language Options
|
||||
@xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
|
||||
@gccoptlist{-fabi-version=@var{n} -fno-access-control -fcheck-new @gol
|
||||
-fconserve-space -fno-const-strings @gol
|
||||
-fconserve-space -ffriend-injection -fno-const-strings @gol
|
||||
-fno-elide-constructors @gol
|
||||
-fno-enforce-eh-specs @gol
|
||||
-ffor-scope -fno-for-scope -fno-gnu-keywords @gol
|
||||
@ -1425,6 +1425,20 @@ two definitions were merged.
|
||||
This option is no longer useful on most targets, now that support has
|
||||
been added for putting variables into BSS without making them common.
|
||||
|
||||
@item -ffriend-injection
|
||||
@opindex ffriend-injection
|
||||
Inject friend functions into the enclosing namespace, so that they are
|
||||
visible outside the scope of the class in which they are declared.
|
||||
Friend functions were documented to work this way in the old Annotated
|
||||
C++ Reference Manual, and versions of G++ before 4.1 always worked
|
||||
that way. However, in ISO C++ a friend function which is not declared
|
||||
in an enclosing scope can only be found using argument dependent
|
||||
lookup. This option causes friends to be injected as they were in
|
||||
earlier releases.
|
||||
|
||||
This option is for compatibility, and may be removed in a future
|
||||
release of G++.
|
||||
|
||||
@item -fno-const-strings
|
||||
@opindex fno-const-strings
|
||||
Give string constants type @code{char *} instead of type @code{const
|
||||
|
@ -1,3 +1,18 @@
|
||||
2005-09-12 Ian Lance Taylor <ian@airs.com>
|
||||
|
||||
PR g++/7874
|
||||
* g++.dg/lookup/friend7.C: New test.
|
||||
* g++.dg/lookup/friend8.C: New test.
|
||||
* g++.dg/parse/defarg4.C: Add a parameter to the friend function,
|
||||
so that it will be found via argument dependent lookup.
|
||||
* g++.old-deja/g++.brendan/crash56.C: Don't expect errors for
|
||||
friend functions which will no longer be found.
|
||||
* g++.old-deja/g++.jason/friend.C: Add a parameter to the friend
|
||||
function g, so that it will be found via argument dependent
|
||||
lookup.
|
||||
* g++.old-deja/g++.jason/scoping15.C: Use -ffriend-injection.
|
||||
* g++.old-deja/g++.mike/net43.C: Likewise.
|
||||
|
||||
2005-09-12 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
PR c++/23691
|
||||
|
19
gcc/testsuite/g++.dg/lookup/friend7.C
Normal file
19
gcc/testsuite/g++.dg/lookup/friend7.C
Normal file
@ -0,0 +1,19 @@
|
||||
// { dg-do compile }
|
||||
// PR c++/7874: Don't inject friend functions into global name space.
|
||||
|
||||
namespace N { template<typename T> struct A { friend void f(A) { }; }; }
|
||||
int main()
|
||||
{
|
||||
N::A<int> a;
|
||||
N::f(a); // { dg-error "not a member" }
|
||||
}
|
||||
|
||||
struct S { friend void g(); friend void h(S); };
|
||||
struct T { friend void g(); friend void h(T); };
|
||||
void i() {
|
||||
g(); // { dg-error "not declared" }
|
||||
S s;
|
||||
h(s);
|
||||
T t;
|
||||
h(t);
|
||||
}
|
12
gcc/testsuite/g++.dg/lookup/friend8.C
Normal file
12
gcc/testsuite/g++.dg/lookup/friend8.C
Normal file
@ -0,0 +1,12 @@
|
||||
// Test that we look up a friend declared at top level ahead of an
|
||||
// undeclared friend found by argument dependent lookup.
|
||||
|
||||
// { dg-do run }
|
||||
|
||||
int f(int) { return 0; }
|
||||
|
||||
struct S {
|
||||
friend int f(char) { return 1; }
|
||||
};
|
||||
|
||||
int main () { return f('a'); }
|
@ -6,9 +6,10 @@
|
||||
// PR c++ 9162. default args got left unprocessed
|
||||
|
||||
struct S {
|
||||
friend int foo (int = 100);
|
||||
friend int foo (const S&, int = 100);
|
||||
};
|
||||
int i = foo ();
|
||||
S s;
|
||||
int i = foo (s);
|
||||
|
||||
struct R
|
||||
{
|
||||
|
@ -20,15 +20,15 @@ public:
|
||||
class Vix {
|
||||
public:
|
||||
Vix();
|
||||
friend int operator==(void *v, const Vix& x) // { dg-error "operator==" }
|
||||
friend int operator==(void *v, const Vix& x)
|
||||
{ return v == x.item; }
|
||||
friend int operator==(const Vix& x, void *v) // { dg-error "operator==" }
|
||||
friend int operator==(const Vix& x, void *v)
|
||||
{ return v == x.item; }
|
||||
friend int operator!=(void *v, const Vix& x)
|
||||
{ return v != x.item; }
|
||||
friend int operator!=(const Vix& x, void *v)
|
||||
{ return v != x.item; }
|
||||
friend int operator==(const Vix& x1, const Vix& x2) // { dg-error "operator==" }
|
||||
friend int operator==(const Vix& x1, const Vix& x2)
|
||||
{ return x1.owner == x2.owner && x1.item == x2.item; }
|
||||
friend int operator!=(const Vix& x1, const Vix& x2)
|
||||
{ return x1.owner != x2.owner || x1.item != x2.item; }
|
||||
|
@ -10,10 +10,11 @@ struct A {
|
||||
|
||||
struct B {
|
||||
static void f () { exit (0); }
|
||||
friend void g () { f (); }
|
||||
friend void g (B) { f (); }
|
||||
};
|
||||
|
||||
int main ()
|
||||
{
|
||||
g ();
|
||||
B b;
|
||||
g (b);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
// { dg-do assemble }
|
||||
// { dg-options "-ffriend-injection" }
|
||||
// Bug: g++ ignores the :: qualification and dies trying to treat an integer
|
||||
// variable as a list of functions.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// { dg-do assemble }
|
||||
// { dg-options "-ffriend-injection" }
|
||||
|
||||
class foo {
|
||||
public:
|
||||
|
Loading…
x
Reference in New Issue
Block a user