re PR c++/26912 (friend const member function specialization fails to compile)

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.

From-SVN: r113213
This commit is contained in:
Mark Mitchell 2006-04-24 03:50:31 +00:00 committed by Mark Mitchell
parent d24b23bb89
commit e2537f2c03
8 changed files with 163 additions and 146 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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)
{

View File

@ -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);

View File

@ -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.

View File

@ -0,0 +1,11 @@
// PR c++/26912
struct Foo {
template<class T> int func() const;
};
class Bar {
friend int Foo::func<int>() const;
};