summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>2006-04-24 03:50:31 +0000
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>2006-04-24 03:50:31 +0000
commit7873fcd66afba8cb976f4a8d438c39af1dcd592e (patch)
treeaef78361996e61e02ee5a14c7f9d6f1ab2a35d52
parent8de62358358a2a0e0e40bc0813aecba662fa5a6e (diff)
downloadgcc-7873fcd66afba8cb976f4a8d438c39af1dcd592e.tar.gz
PR c++/26912
* cp-tree.h (build_this_parm): Declare. (grok_method_quals): Remove. (build_memfn_type): Declare. (build_artificial_parm): Declare. (do_friend): Remove quals parameter. * decl.c (build_this_parm): New function. (grokfndecl): Use it. Do not pass quals to grokclassfn. (grokdeclarator): Rename quals to memfn_quals. Avoid allocating unnecessary TYPE_DECLs. Correct qualification of member function types. Tidy. * method.c (implicitly_declare_fn): Use build_this_parm. * friend.c (do_friend): Remove quals parameter. * decl2.c (grok_method_quals): Remove. (build_memfn_type): New function. (build_artificial_parm): Give it external linkage. (grokclassfn): Remove quals parameter. Do not build "this" PARM_DECL here. PR c++/26912 * g++.dg/template/friend41.C: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@113213 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/cp/ChangeLog19
-rw-r--r--gcc/cp/cp-tree.h9
-rw-r--r--gcc/cp/decl.c192
-rw-r--r--gcc/cp/decl2.c55
-rw-r--r--gcc/cp/friend.c9
-rw-r--r--gcc/cp/method.c11
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/template/friend41.C11
8 files changed, 164 insertions, 147 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a0a44a54075..0d24702efa8 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,24 @@
2006-04-23 Mark Mitchell <mark@codesourcery.com>
+ PR c++/26912
+ * cp-tree.h (build_this_parm): Declare.
+ (grok_method_quals): Remove.
+ (build_memfn_type): Declare.
+ (build_artificial_parm): Declare.
+ (do_friend): Remove quals parameter.
+ * decl.c (build_this_parm): New function.
+ (grokfndecl): Use it. Do not pass quals to grokclassfn.
+ (grokdeclarator): Rename quals to memfn_quals. Avoid allocating
+ unnecessary TYPE_DECLs. Correct qualification of member function
+ types. Tidy.
+ * method.c (implicitly_declare_fn): Use build_this_parm.
+ * friend.c (do_friend): Remove quals parameter.
+ * decl2.c (grok_method_quals): Remove.
+ (build_memfn_type): New function.
+ (build_artificial_parm): Give it external linkage.
+ (grokclassfn): Remove quals parameter. Do not build "this"
+ PARM_DECL here.
+
PR c++/26534
* cp-tree.h (is_bitfield_expr_with_lowered_type): New function.
* typeck.c (is_bitfield_expr_with_lowered_type): New function.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 34cccc0a911..1e3c1b7807d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3842,6 +3842,7 @@ extern int cp_complete_array_type (tree *, tree, bool);
extern tree build_ptrmemfunc_type (tree);
extern tree build_ptrmem_type (tree, tree);
/* the grokdeclarator prototype is in decl.h */
+extern tree build_this_parm (tree, cp_cv_quals);
extern int copy_fn_p (tree);
extern tree get_scope_of_declarator (const cp_declarator *);
extern void grok_special_member_properties (tree);
@@ -3899,12 +3900,11 @@ extern bool have_extern_spec;
/* in decl2.c */
extern bool check_java_method (tree);
-extern cp_cv_quals grok_method_quals (tree, tree, cp_cv_quals);
+extern tree build_memfn_type (tree, tree, cp_cv_quals);
extern void maybe_retrofit_in_chrg (tree);
extern void maybe_make_one_only (tree);
extern void grokclassfn (tree, tree,
- enum overload_flags,
- cp_cv_quals);
+ enum overload_flags);
extern tree grok_array_decl (tree, tree);
extern tree delete_sanity (tree, tree, bool, int);
extern tree check_classfn (tree, tree, tree);
@@ -3934,6 +3934,7 @@ extern tree cxx_callgraph_analyze_expr (tree *, int *, tree);
extern void mark_needed (tree);
extern bool decl_needed_p (tree);
extern void note_vague_linkage_fn (tree);
+extern tree build_artificial_parm (tree, tree);
/* in error.c */
extern void init_error (void);
@@ -3966,7 +3967,7 @@ extern tree cplus_expand_constant (tree);
extern int is_friend (tree, tree);
extern void make_friend_class (tree, tree, bool);
extern void add_friend (tree, tree, bool);
-extern tree do_friend (tree, tree, tree, tree, enum overload_flags, cp_cv_quals, bool);
+extern tree do_friend (tree, tree, tree, tree, enum overload_flags, bool);
/* in init.c */
extern tree expand_member_init (tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index d979fd3521a..c7967c7709b 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5808,6 +5808,28 @@ check_class_member_definition_namespace (tree decl)
decl, DECL_CONTEXT (decl));
}
+/* Build a PARM_DECL for the "this" parameter. TYPE is the
+ METHOD_TYPE for a non-static member function; QUALS are the
+ cv-qualifiers that apply to the function. */
+
+tree
+build_this_parm (tree type, cp_cv_quals quals)
+{
+ tree this_type;
+ tree qual_type;
+ tree parm;
+ cp_cv_quals this_quals;
+
+ this_type = TREE_VALUE (TYPE_ARG_TYPES (type));
+ /* The `this' parameter is implicitly `const'; it cannot be
+ assigned to. */
+ this_quals = (quals & TYPE_QUAL_RESTRICT) | TYPE_QUAL_CONST;
+ qual_type = cp_build_qualified_type (this_type, this_quals);
+ parm = build_artificial_parm (this_identifier, qual_type);
+ cp_apply_type_quals_to_decl (this_quals, parm);
+ return parm;
+}
+
/* CTYPE is class type, or null if non-class.
TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE
or METHOD_TYPE.
@@ -5854,6 +5876,13 @@ grokfndecl (tree ctype,
type = build_exception_variant (type, raises);
decl = build_lang_decl (FUNCTION_DECL, declarator, type);
+ if (TREE_CODE (type) == METHOD_TYPE)
+ {
+ tree parm;
+ parm = build_this_parm (type, quals);
+ TREE_CHAIN (parm) = parms;
+ parms = parm;
+ }
DECL_ARGUMENTS (decl) = parms;
/* Propagate volatile out from type to decl. */
if (TYPE_VOLATILE (type))
@@ -6057,7 +6086,7 @@ grokfndecl (tree ctype,
if (sfk == sfk_constructor)
DECL_CONSTRUCTOR_P (decl) = 1;
- grokclassfn (ctype, decl, flags, quals);
+ grokclassfn (ctype, decl, flags);
}
decl = check_explicit_specialization (orig_declarator, decl,
@@ -6765,7 +6794,6 @@ grokdeclarator (const cp_declarator *declarator,
{
tree type = NULL_TREE;
int longlong = 0;
- int type_quals;
int virtualp, explicitp, friendp, inlinep, staticp;
int explicit_int = 0;
int explicit_char = 0;
@@ -6792,7 +6820,11 @@ grokdeclarator (const cp_declarator *declarator,
tree dname = NULL_TREE;
tree ctor_return_type = NULL_TREE;
enum overload_flags flags = NO_SPECIAL;
- cp_cv_quals quals = TYPE_UNQUALIFIED;
+ /* cv-qualifiers that apply to the declarator, for a declaration of
+ a member function. */
+ cp_cv_quals memfn_quals = TYPE_UNQUALIFIED;
+ /* cv-qualifiers that apply to the type specified by the DECLSPECS. */
+ int type_quals;
tree raises = NULL_TREE;
int template_count = 0;
tree returned_attrs = NULL_TREE;
@@ -7451,7 +7483,7 @@ grokdeclarator (const cp_declarator *declarator,
}
/* Pick up type qualifiers which should be applied to `this'. */
- quals = declarator->u.function.qualifiers;
+ memfn_quals = declarator->u.function.qualifiers;
/* Pick up the exception specifications. */
raises = declarator->u.function.exception_specification;
@@ -7473,53 +7505,44 @@ grokdeclarator (const cp_declarator *declarator,
is the same as the class name, and we are defining
a function, then it is a constructor/destructor, and
therefore returns a void type. */
-
- if (flags == DTOR_FLAG)
+
+ /* ISO C++ 12.4/2. A destructor may not be declared
+ const or volatile. A destructor may not be
+ static.
+
+ ISO C++ 12.1. A constructor may not be declared
+ const or volatile. A constructor may not be
+ virtual. A constructor may not be static. */
+ if (staticp == 2)
+ error ((flags == DTOR_FLAG)
+ ? "destructor cannot be static member function"
+ : "constructor cannot be static member function");
+ if (memfn_quals)
{
- /* ISO C++ 12.4/2. A destructor may not be
- declared const or volatile. A destructor may
- not be static. */
- if (staticp == 2)
- error ("destructor cannot be static member function");
- if (quals)
- {
- error ("destructors may not be cv-qualified");
- quals = TYPE_UNQUALIFIED;
- }
- if (decl_context == FIELD)
- {
- if (! member_function_or_else (ctype,
- current_class_type,
- flags))
- return void_type_node;
- }
+ error ((flags == DTOR_FLAG)
+ ? "destructors may not be cv-qualified"
+ : "constructors may not be cv-qualified");
+ memfn_quals = TYPE_UNQUALIFIED;
}
- else /* It's a constructor. */
+
+ if (decl_context == FIELD
+ && !member_function_or_else (ctype,
+ current_class_type,
+ flags))
+ return void_type_node;
+
+ if (flags != DTOR_FLAG)
{
+ /* It's a constructor. */
if (explicitp == 1)
explicitp = 2;
- /* ISO C++ 12.1. A constructor may not be
- declared const or volatile. A constructor may
- not be virtual. A constructor may not be
- static. */
- if (staticp == 2)
- error ("constructor cannot be static member function");
if (virtualp)
{
pedwarn ("constructors cannot be declared virtual");
virtualp = 0;
}
- if (quals)
- {
- error ("constructors may not be cv-qualified");
- quals = TYPE_UNQUALIFIED;
- }
if (decl_context == FIELD)
{
- if (! member_function_or_else (ctype,
- current_class_type,
- flags))
- return void_type_node;
TYPE_HAS_CONSTRUCTOR (ctype) = 1;
if (sfk != sfk_constructor)
return NULL_TREE;
@@ -7560,7 +7583,6 @@ grokdeclarator (const cp_declarator *declarator,
}
type = build_function_type (type, arg_types);
- type = cp_build_qualified_type (type, quals);
}
break;
@@ -7590,22 +7612,13 @@ grokdeclarator (const cp_declarator *declarator,
type_quals = TYPE_UNQUALIFIED;
if (declarator->kind == cdk_ptrmem
- && (TREE_CODE (type) == FUNCTION_TYPE
- || (quals && TREE_CODE (type) == METHOD_TYPE)))
+ && (TREE_CODE (type) == FUNCTION_TYPE || memfn_quals))
{
- tree dummy;
-
- /* If the type is a FUNCTION_TYPE, pick up the
- qualifiers from that function type. No other
- qualifiers may be supplied. */
- if (TREE_CODE (type) == FUNCTION_TYPE)
- quals = cp_type_quals (type);
-
- dummy = build_decl (TYPE_DECL, NULL_TREE, type);
- grok_method_quals (declarator->u.pointer.class_type,
- dummy, quals);
- type = TREE_TYPE (dummy);
- quals = TYPE_UNQUALIFIED;
+ memfn_quals |= cp_type_quals (type);
+ type = build_memfn_type (type,
+ declarator->u.pointer.class_type,
+ memfn_quals);
+ memfn_quals = TYPE_UNQUALIFIED;
}
if (declarator->kind == cdk_reference)
@@ -7743,9 +7756,7 @@ grokdeclarator (const cp_declarator *declarator,
are always static functions. */
;
else
- type = build_method_type_directly (ctype,
- TREE_TYPE (type),
- TYPE_ARG_TYPES (type));
+ type = build_memfn_type (type, ctype, memfn_quals);
}
else if (declspecs->specs[(int)ds_typedef]
&& current_class_type)
@@ -7837,6 +7848,18 @@ grokdeclarator (const cp_declarator *declarator,
in typenames, fields or parameters. */
if (current_lang_name == lang_name_java)
TYPE_FOR_JAVA (type) = 1;
+
+ /* This declaration:
+
+ typedef void f(int) const;
+
+ declares a function type which is not a member of any
+ particular class, but which is cv-qualified; for
+ example "f S::*" declares a pointer to a const-qualified
+ member function of S. We record the cv-qualification in the
+ function type. */
+ if (memfn_quals && TREE_CODE (type) == FUNCTION_TYPE)
+ type = cp_build_qualified_type (type, memfn_quals);
if (decl_context == FIELD)
decl = build_lang_decl (TYPE_DECL, unqualified_id, type);
@@ -7898,26 +7921,17 @@ grokdeclarator (const cp_declarator *declarator,
type with external linkage have external linkage. */
}
- if (quals)
- {
- if (ctype == NULL_TREE)
- {
- if (TREE_CODE (type) == METHOD_TYPE)
- ctype = TYPE_METHOD_BASETYPE (type);
- /* Any qualifiers on a function type typedef have
- already been dealt with. */
- else if (TREE_CODE (type) == FUNCTION_TYPE)
- quals = TYPE_UNQUALIFIED;
- }
- if (ctype != NULL_TREE)
- grok_method_quals (ctype, decl, quals);
- }
+ /* Any qualifiers on a function type typedef have already been
+ dealt with. */
+ if (memfn_quals && !ctype && TREE_CODE (type) == FUNCTION_TYPE)
+ memfn_quals = TYPE_UNQUALIFIED;
if (signed_p
|| (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))
C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
- bad_specifiers (decl, "type", virtualp, quals != TYPE_UNQUALIFIED,
+ bad_specifiers (decl, "type", virtualp,
+ memfn_quals != TYPE_UNQUALIFIED,
inlinep, friendp, raises != NULL_TREE);
return decl;
@@ -7965,7 +7979,7 @@ grokdeclarator (const cp_declarator *declarator,
/* The qualifiers on the function type become the qualifiers on
the non-static member function. */
- quals |= cp_type_quals (type);
+ memfn_quals |= cp_type_quals (type);
}
}
@@ -8022,7 +8036,7 @@ grokdeclarator (const cp_declarator *declarator,
type = void_type_node;
}
}
- else if (quals)
+ else if (memfn_quals)
{
if (ctype == NULL_TREE)
{
@@ -8032,11 +8046,7 @@ grokdeclarator (const cp_declarator *declarator,
ctype = TYPE_METHOD_BASETYPE (type);
}
if (ctype)
- {
- tree dummy = build_decl (TYPE_DECL, unqualified_id, type);
- grok_method_quals (ctype, dummy, quals);
- type = TREE_TYPE (dummy);
- }
+ type = build_memfn_type (type, ctype, memfn_quals);
}
return type;
@@ -8094,7 +8104,8 @@ grokdeclarator (const cp_declarator *declarator,
{
decl = cp_build_parm_decl (unqualified_id, type);
- bad_specifiers (decl, "parameter", virtualp, quals != TYPE_UNQUALIFIED,
+ bad_specifiers (decl, "parameter", virtualp,
+ memfn_quals != TYPE_UNQUALIFIED,
inlinep, friendp, raises != NULL_TREE);
}
else if (decl_context == FIELD)
@@ -8156,9 +8167,7 @@ grokdeclarator (const cp_declarator *declarator,
}
}
else if (staticp < 2)
- type = build_method_type_directly (ctype,
- TREE_TYPE (type),
- TYPE_ARG_TYPES (type));
+ type = build_memfn_type (type, ctype, memfn_quals);
}
/* Check that the name used for a destructor makes sense. */
@@ -8193,7 +8202,7 @@ grokdeclarator (const cp_declarator *declarator,
? unqualified_id : dname,
parms,
unqualified_id,
- virtualp, flags, quals, raises,
+ virtualp, flags, memfn_quals, raises,
friendp ? -1 : 0, friendp, publicp, inlinep,
sfk,
funcdef_flag, template_count, in_namespace, attrlist);
@@ -8241,7 +8250,7 @@ grokdeclarator (const cp_declarator *declarator,
? unqualified_id : dname,
parms,
unqualified_id,
- virtualp, flags, quals, raises,
+ virtualp, flags, memfn_quals, raises,
friendp ? -1 : 0, friendp, 1, 0, sfk,
funcdef_flag, template_count, in_namespace,
attrlist);
@@ -8298,7 +8307,8 @@ grokdeclarator (const cp_declarator *declarator,
}
decl = do_friend (ctype, unqualified_id, decl,
- *attrlist, flags, quals, funcdef_flag);
+ *attrlist, flags,
+ funcdef_flag);
return decl;
}
else
@@ -8377,7 +8387,8 @@ grokdeclarator (const cp_declarator *declarator,
}
}
- bad_specifiers (decl, "field", virtualp, quals != TYPE_UNQUALIFIED,
+ bad_specifiers (decl, "field", virtualp,
+ memfn_quals != TYPE_UNQUALIFIED,
inlinep, friendp, raises != NULL_TREE);
}
}
@@ -8438,7 +8449,7 @@ grokdeclarator (const cp_declarator *declarator,
|| storage_class != sc_static);
decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
- virtualp, flags, quals, raises,
+ virtualp, flags, memfn_quals, raises,
1, friendp,
publicp, inlinep, sfk, funcdef_flag,
template_count, in_namespace, attrlist);
@@ -8481,7 +8492,8 @@ grokdeclarator (const cp_declarator *declarator,
initialized,
(type_quals & TYPE_QUAL_CONST) != 0,
ctype ? ctype : in_namespace);
- bad_specifiers (decl, "variable", virtualp, quals != TYPE_UNQUALIFIED,
+ bad_specifiers (decl, "variable", virtualp,
+ memfn_quals != TYPE_UNQUALIFIED,
inlinep, friendp, raises != NULL_TREE);
if (ctype)
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index ed26db2fe34..fe5db71c653 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -103,33 +103,28 @@ tree static_ctors;
tree static_dtors;
-/* Incorporate `const' and `volatile' qualifiers for member functions.
- FUNCTION is a TYPE_DECL or a FUNCTION_DECL.
- QUALS is a list of qualifiers. Returns any explicit
- top-level qualifiers of the method's this pointer, anything other than
- TYPE_UNQUALIFIED will be an extension. */
-
-int
-grok_method_quals (tree ctype, tree function, cp_cv_quals quals)
+
+/* Return a member function type (a METHOD_TYPE), given FNTYPE (a
+ FUNCTION_TYPE), CTYPE (class type), and QUALS (the cv-qualifiers
+ that apply to the function). */
+
+tree
+build_memfn_type (tree fntype, tree ctype, cp_cv_quals quals)
{
- tree fntype = TREE_TYPE (function);
- tree raises = TYPE_RAISES_EXCEPTIONS (fntype);
- int type_quals = TYPE_UNQUALIFIED;
- int this_quals = TYPE_UNQUALIFIED;
+ tree raises;
+ int type_quals;
type_quals = quals & ~TYPE_QUAL_RESTRICT;
- this_quals = quals & TYPE_QUAL_RESTRICT;
-
ctype = cp_build_qualified_type (ctype, type_quals);
fntype = build_method_type_directly (ctype, TREE_TYPE (fntype),
(TREE_CODE (fntype) == METHOD_TYPE
? TREE_CHAIN (TYPE_ARG_TYPES (fntype))
: TYPE_ARG_TYPES (fntype)));
+ raises = TYPE_RAISES_EXCEPTIONS (fntype);
if (raises)
fntype = build_exception_variant (fntype, raises);
- TREE_TYPE (function) = fntype;
- return this_quals;
+ return fntype;
}
/* Build a PARM_DECL with NAME and TYPE, and set DECL_ARG_TYPE
@@ -149,7 +144,7 @@ cp_build_parm_decl (tree name, tree type)
/* Returns a PARM_DECL for a parameter of the indicated TYPE, with the
indicated NAME. */
-static tree
+tree
build_artificial_parm (tree name, tree type)
{
tree parm = cp_build_parm_decl (name, type);
@@ -257,11 +252,9 @@ maybe_retrofit_in_chrg (tree fn)
QUALS are the qualifiers for the this pointer. */
void
-grokclassfn (tree ctype, tree function, enum overload_flags flags,
- cp_cv_quals quals)
+grokclassfn (tree ctype, tree function, enum overload_flags flags)
{
tree fn_name = DECL_NAME (function);
- cp_cv_quals this_quals = TYPE_UNQUALIFIED;
/* Even within an `extern "C"' block, members get C++ linkage. See
[dcl.link] for details. */
@@ -274,28 +267,6 @@ grokclassfn (tree ctype, tree function, enum overload_flags flags,
DECL_NAME (function) = fn_name;
}
- if (quals)
- this_quals = grok_method_quals (ctype, function, quals);
-
- if (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE)
- {
- /* Must add the class instance variable up front. */
- /* Right now we just make this a pointer. But later
- we may wish to make it special. */
- tree type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (function)));
- tree qual_type;
- tree parm;
-
- /* The `this' parameter is implicitly `const'; it cannot be
- assigned to. */
- this_quals |= TYPE_QUAL_CONST;
- qual_type = cp_build_qualified_type (type, this_quals);
- parm = build_artificial_parm (this_identifier, qual_type);
- cp_apply_type_quals_to_decl (this_quals, parm);
- TREE_CHAIN (parm) = DECL_ARGUMENTS (function);
- DECL_ARGUMENTS (function) = parm;
- }
-
DECL_CONTEXT (function) = ctype;
if (flags == DTOR_FLAG)
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 0ae9130b61a..ac73e5f4787 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -399,15 +399,11 @@ make_friend_class (tree type, tree friend_type, bool complain)
DECL is the FUNCTION_DECL that the friend is.
- FLAGS is just used for `grokclassfn'.
-
- QUALS say what special qualifies should apply to the object
- pointed to by `this'. */
+ FLAGS is just used for `grokclassfn'. */
tree
do_friend (tree ctype, tree declarator, tree decl,
tree attrlist, enum overload_flags flags,
- cp_cv_quals quals,
bool funcdef_flag)
{
/* Every decl that gets here is a friend of something. */
@@ -456,8 +452,7 @@ do_friend (tree ctype, tree declarator, tree decl,
if (flags == NO_SPECIAL && declarator == cname)
DECL_CONSTRUCTOR_P (decl) = 1;
- /* This will set up DECL_ARGUMENTS for us. */
- grokclassfn (ctype, decl, flags, quals);
+ grokclassfn (ctype, decl, flags);
if (friend_depth)
{
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index d2bee99dc5e..68ec8ab4181 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -978,6 +978,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
tree fn_type;
tree raises = empty_except_spec;
tree rhs_parm_type = NULL_TREE;
+ tree this_parm;
tree name;
HOST_WIDE_INT saved_processing_template_decl;
@@ -1067,8 +1068,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
DECL_ASSIGNMENT_OPERATOR_P (fn) = 1;
SET_OVERLOADED_OPERATOR_CODE (fn, NOP_EXPR);
}
- /* Create the argument list. The call to "grokclassfn" will add the
- "this" parameter and any other implicit parameters. */
+ /* Create the explicit arguments. */
if (rhs_parm_type)
{
/* Note that this parameter is *not* marked DECL_ARTIFICIAL; we
@@ -1077,9 +1077,12 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
DECL_ARGUMENTS (fn) = cp_build_parm_decl (NULL_TREE, rhs_parm_type);
TREE_READONLY (DECL_ARGUMENTS (fn)) = 1;
}
+ /* Add the "this" parameter. */
+ this_parm = build_this_parm (fn_type, TYPE_UNQUALIFIED);
+ TREE_CHAIN (this_parm) = DECL_ARGUMENTS (fn);
+ DECL_ARGUMENTS (fn) = this_parm;
- grokclassfn (type, fn, kind == sfk_destructor ? DTOR_FLAG : NO_SPECIAL,
- TYPE_UNQUALIFIED);
+ grokclassfn (type, fn, kind == sfk_destructor ? DTOR_FLAG : NO_SPECIAL);
grok_special_member_properties (fn);
set_linkage_according_to_type (type, fn);
rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 6e05f64362d..535d2f5b632 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2006-04-23 Mark Mitchell <mark@codesourcery.com>
+
+ PR c++/26912
+ * g++.dg/template/friend41.C: New test.
+
2006-04-23 David Edelsohn <edelsohn@gnu.org>
* g++.dg/opt/pr15551.C: Include cstdio.
diff --git a/gcc/testsuite/g++.dg/template/friend41.C b/gcc/testsuite/g++.dg/template/friend41.C
new file mode 100644
index 00000000000..6d686019d9a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend41.C
@@ -0,0 +1,11 @@
+// PR c++/26912
+
+struct Foo {
+ template<class T> int func() const;
+};
+
+class Bar {
+ friend int Foo::func<int>() const;
+};
+
+