Hi,
today I noticed that when we implemented the resolution we failed to
handle static member functions. The below tested x86_64-linux.
While working on this I noticed that we don't use the
DECL_NONSTATIC_MEMBER_FUNCTION_P macro much, should we apply something
like the attached?
Finally, if you are wondering instead how I noticed the former ;) I have
been working on c++/15339, which seems relatively easy to resolve. Ie,
rejecting in duplicate_decls
template<typename> void fun(int);
template<typename> void fun(int = 0);
however, handling correctly the member case:
class A
{
template<typename> void fun(int);
};
template<typename> void A::fun(int = 0) { }
is more tricky because we don't want to start rejecting:
class A
{
void fun(int);
};
void A::fun(int = 0) { }
which is well formed. The problem is that when grokfndecl calls
duplicate_decls in such member cases it looks through TEMPLATE_DECLs, eg:
if (TREE_CODE (old_decl) == TEMPLATE_DECL)
/* Because grokfndecl is always supposed to return a
FUNCTION_DECL, we pull out the DECL_TEMPLATE_RESULT
here. We depend on our callers to figure out that its
really a template that's being returned. */
old_decl = DECL_TEMPLATE_RESULT (old_decl);
and then telling apart the two cases above is tough, both are
FUNCTION_DECLs :(
Ideas about the best way to handle that? Anything less delicate than
trying *not* to use DECL_TEMPLATE_RESULT that early and passing the
TEMPLATE_DECLs as they are to duplicate_decls and then using it only
right before returning from grokfndecl?
Thanks!
Paolo.
///////////////////////////
/cp
2014-07-31 Paolo Carlini <paolo.carl...@oracle.com>
DR 217 again
* decl.c (duplicate_decls): Handle static member functions too.
/testsuite
2014-07-31 Paolo Carlini <paolo.carl...@oracle.com>
DR 217 again
* g++.dg/tc1/dr217-2.C: New.
Index: cp/decl.c
===================================================================
--- cp/decl.c (revision 213379)
+++ cp/decl.c (working copy)
@@ -1710,10 +1710,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool
tree t2 = TYPE_ARG_TYPES (TREE_TYPE (newdecl));
int i = 1;
- if (TREE_CODE (TREE_TYPE (newdecl)) == METHOD_TYPE)
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (newdecl))
t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2);
- if (TREE_CODE (TREE_TYPE (newdecl)) == METHOD_TYPE
+ if (DECL_FUNCTION_MEMBER_P (newdecl)
&& CLASSTYPE_TEMPLATE_INFO (CP_DECL_CONTEXT (newdecl)))
{
/* C++11 8.3.6/6.
Index: testsuite/g++.dg/tc1/dr217-2.C
===================================================================
--- testsuite/g++.dg/tc1/dr217-2.C (revision 0)
+++ testsuite/g++.dg/tc1/dr217-2.C (working copy)
@@ -0,0 +1,13 @@
+// { dg-do compile }
+// DR217: Default arguments for non-template member functions of class
+// templates
+
+template <class T>
+struct S
+{
+ static void foo (int);
+};
+
+template <class T>
+void S<T>::foo (int = 0) // { dg-error "" "default arguments for parameters
of member functions of class templates can be specified in the initial
declaration only" }
+{ }
Index: call.c
===================================================================
--- call.c (revision 213379)
+++ call.c (working copy)
@@ -7038,7 +7038,7 @@ build_over_call (struct z_candidate *cand, int fla
}
}
/* Bypass access control for 'this' parameter. */
- else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
+ else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
{
tree parmtype = TREE_VALUE (parm);
tree arg = build_this (first_arg != NULL_TREE
@@ -8026,7 +8026,7 @@ build_new_method_call_1 (tree instance, tree fns,
fn);
}
- if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
&& !DECL_CONSTRUCTOR_P (fn)
&& is_dummy_object (instance))
{
@@ -8071,7 +8071,7 @@ build_new_method_call_1 (tree instance, tree fns,
/* In an expression of the form `a->f()' where `f' turns
out to be a static member function, `a' is
none-the-less evaluated. */
- if (TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
+ if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
&& !is_dummy_object (instance)
&& TREE_SIDE_EFFECTS (instance))
call = build2 (COMPOUND_EXPR, TREE_TYPE (call),
Index: class.c
===================================================================
--- class.c (revision 213379)
+++ class.c (working copy)
@@ -7306,7 +7306,7 @@ resolve_address_of_overloaded_function (tree targe
pointer-to-member types, not the internal POINTER_TYPE to
METHOD_TYPE representation. */
gcc_assert (!TYPE_PTR_P (target_type)
- || TREE_CODE (TREE_TYPE (target_type)) != METHOD_TYPE);
+ || !DECL_NONSTATIC_MEMBER_FUNCTION_P (target_type));
gcc_assert (is_overloaded_fn (overload));
@@ -7355,8 +7355,7 @@ resolve_address_of_overloaded_function (tree targe
/* We're not looking for templates just yet. */
continue;
- if ((TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
- != is_ptrmem)
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) != is_ptrmem)
/* We're looking for a non-static member, and this isn't
one, or vice versa. */
continue;
@@ -7405,8 +7404,7 @@ resolve_address_of_overloaded_function (tree targe
/* We're only looking for templates. */
continue;
- if ((TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
- != is_ptrmem)
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) != is_ptrmem)
/* We're not looking for a non-static member, and this is
one, or vice versa. */
continue;
Index: cp-tree.h
===================================================================
--- cp-tree.h (revision 213379)
+++ cp-tree.h (working copy)
@@ -3555,7 +3555,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_a
#define TYPE_PTROBV_P(NODE) \
(TYPE_PTR_P (NODE) \
&& !(TREE_CODE (TREE_TYPE (NODE)) == FUNCTION_TYPE \
- || TREE_CODE (TREE_TYPE (NODE)) == METHOD_TYPE))
+ || DECL_NONSTATIC_MEMBER_FUNCTION_P (NODE)))
/* Returns true if NODE is a pointer to function. */
#define TYPE_PTRFN_P(NODE) \
Index: cvt.c
===================================================================
--- cvt.c (revision 213379)
+++ cvt.c (working copy)
@@ -1475,7 +1475,7 @@ convert_force (tree type, tree expr, int convtype,
/* From typeck.c convert_for_assignment */
if (((TYPE_PTR_P (TREE_TYPE (e)) && TREE_CODE (e) == ADDR_EXPR
- && TREE_CODE (TREE_TYPE (TREE_TYPE (e))) == METHOD_TYPE)
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (TREE_TYPE (e)))
|| integer_zerop (e)
|| TYPE_PTRMEMFUNC_P (TREE_TYPE (e)))
&& TYPE_PTRMEMFUNC_P (type))
Index: decl.c
===================================================================
--- decl.c (revision 213379)
+++ decl.c (working copy)
@@ -7849,7 +7849,7 @@ grokfndecl (tree ctype,
old_decl = DECL_TEMPLATE_RESULT (old_decl);
if (DECL_STATIC_FUNCTION_P (old_decl)
- && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
{
/* Remove the `this' parm added by grokclassfn. */
revert_static_member_fn (decl);
@@ -11525,7 +11525,7 @@ grok_op_properties (tree decl, bool complain)
{
tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
tree argtype;
- int methodp = (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE);
+ int methodp = DECL_NONSTATIC_MEMBER_FUNCTION_P (decl);
tree name = DECL_NAME (decl);
enum tree_code operator_code;
int arity;
@@ -13205,7 +13205,7 @@ start_preparsed_function (tree decl1, tree attrs,
/* Sometimes we don't notice that a function is a static member, and
build a METHOD_TYPE for it. Fix that up now. */
gcc_assert (!(ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1)
- && TREE_CODE (TREE_TYPE (decl1)) == METHOD_TYPE));
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1)));
/* Set up current_class_type, and enter the scope of the class, if
appropriate. */
Index: decl2.c
===================================================================
--- decl2.c (revision 213379)
+++ decl2.c (working copy)
@@ -691,7 +691,7 @@ check_classfn (tree ctype, tree function, tree tem
/* Get rid of the this parameter on functions that become
static. */
if (DECL_STATIC_FUNCTION_P (fndecl)
- && TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE)
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (function))
p1 = TREE_CHAIN (p1);
/* A member template definition only matches a member template
@@ -957,7 +957,7 @@ grokfield (const cp_declarator *declarator,
}
else if (TREE_CODE (init) == DEFAULT_ARG)
error ("invalid initializer for member function %qD", value);
- else if (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE)
+ else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (value))
{
if (integer_zerop (init))
DECL_PURE_VIRTUAL_P (value) = 1;
@@ -4728,7 +4728,7 @@ build_offset_ref_call_from_tree (tree fn, vec<tree
because we depend on the form of FN. */
make_args_non_dependent (*args);
object = build_non_dependent_expr (object);
- if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
{
if (TREE_CODE (fn) == DOTSTAR_EXPR)
object = cp_build_addr_expr (object, complain);
@@ -4772,7 +4772,7 @@ check_default_args (tree x)
{
tree arg = TYPE_ARG_TYPES (TREE_TYPE (x));
bool saw_def = false;
- int i = 0 - (TREE_CODE (TREE_TYPE (x)) == METHOD_TYPE);
+ int i = 0 - DECL_NONSTATIC_MEMBER_FUNCTION_P (x);
for (; arg && arg != void_list_node; arg = TREE_CHAIN (arg), ++i)
{
if (TREE_PURPOSE (arg))
Index: semantics.c
===================================================================
--- semantics.c (revision 213379)
+++ semantics.c (working copy)
@@ -1438,7 +1438,7 @@ finish_asm_stmt (int volatile_p, tree string, tree
/* Functions are not modifiable, even though they are
lvalues. */
|| TREE_CODE (TREE_TYPE (operand)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (operand)) == METHOD_TYPE
+ || DECL_NONSTATIC_MEMBER_FUNCTION_P (operand)
/* If it's an aggregate and any field is const, then it is
effectively const. */
|| (CLASS_TYPE_P (TREE_TYPE (operand))
@@ -3807,7 +3807,7 @@ finish_offsetof (tree expr)
return error_mark_node;
}
if (TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE
+ || DECL_NONSTATIC_MEMBER_FUNCTION_P (expr)
|| TREE_TYPE (expr) == unknown_type_node)
{
if (INDIRECT_REF_P (expr))
Index: tree.c
===================================================================
--- tree.c (revision 213379)
+++ tree.c (working copy)
@@ -1130,7 +1130,7 @@ cp_build_qualified_type_real (tree type,
between the unqualified and qualified types. */
if (result != type
&& TYPE_PTR_P (type)
- && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (type)
&& TYPE_LANG_SPECIFIC (result) == TYPE_LANG_SPECIFIC (type))
TYPE_LANG_SPECIFIC (result) = NULL;
@@ -1139,7 +1139,7 @@ cp_build_qualified_type_real (tree type,
sharing problem described above. */
if (TYPE_CANONICAL (result) != TYPE_CANONICAL (type)
&& TYPE_PTR_P (type)
- && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (type)
&& (TYPE_LANG_SPECIFIC (TYPE_CANONICAL (result))
== TYPE_LANG_SPECIFIC (TYPE_CANONICAL (type))))
TYPE_LANG_SPECIFIC (TYPE_CANONICAL (result)) = NULL;
Index: typeck.c
===================================================================
--- typeck.c (revision 213379)
+++ typeck.c (working copy)
@@ -3495,7 +3495,7 @@ cp_build_function_call_vec (tree function, vec<tre
}
is_method = (TYPE_PTR_P (fntype)
- && TREE_CODE (TREE_TYPE (fntype)) == METHOD_TYPE);
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (fntype));
if (!(TYPE_PTRFN_P (fntype)
|| is_method
@@ -3554,7 +3554,7 @@ warn_args_num (location_t loc, tree fndecl, bool t
{
if (fndecl)
{
- if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl))
{
if (DECL_NAME (fndecl) == NULL_TREE
|| IDENTIFIER_HAS_TYPE_VALUE (DECL_NAME (fndecl)))
@@ -3651,7 +3651,7 @@ convert_arguments (tree typelist, vec<tree, va_gc>
{
if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
+ || DECL_NONSTATIC_MEMBER_FUNCTION_P (val))
val = decay_conversion (val, complain);
}
@@ -5151,7 +5151,7 @@ build_x_unary_op (location_t loc, enum tree_code c
/* A pointer to member-function can be formed only by saying
&X::mf. */
- if (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE
+ if (!flag_ms_extensions && DECL_NONSTATIC_MEMBER_FUNCTION_P (xarg)
&& (TREE_CODE (xarg) != OFFSET_REF || !PTRMEM_OK_P (xarg)))
{
if (TREE_CODE (xarg) != OFFSET_REF
@@ -5183,7 +5183,7 @@ build_x_unary_op (location_t loc, enum tree_code c
ptrmem = PTRMEM_OK_P (xarg);
if (!ptrmem && !flag_ms_extensions
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (xarg, 1))) == METHOD_TYPE)
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (TREE_OPERAND (xarg, 1)))
{
/* A single non-static member, make sure we don't allow a
pointer-to-member. */
@@ -5545,7 +5545,7 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue
}
if (TYPE_PTR_P (argtype)
- && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (argtype))
{
build_ptrmemfunc_type (argtype);
val = build_ptrmemfunc (argtype, val, 0,
@@ -5937,7 +5937,7 @@ unary_complex_lvalue (enum tree_code code, tree ar
}
if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (arg)) == METHOD_TYPE
+ || DECL_NONSTATIC_MEMBER_FUNCTION_P (arg)
|| TREE_CODE (arg) == OFFSET_REF)
return NULL_TREE;
@@ -7473,7 +7473,7 @@ cp_build_modify_expr (tree lhs, enum tree_code mod
/* Functions are not modifiable, even though they are
lvalues. */
|| TREE_CODE (TREE_TYPE (lhs)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (lhs)) == METHOD_TYPE
+ || DECL_NONSTATIC_MEMBER_FUNCTION_P (lhs)
/* If it's an aggregate and any field is const, then it is
effectively const. */
|| (CLASS_TYPE_P (lhstype)
@@ -8245,7 +8245,7 @@ convert_for_initialization (tree exp, tree type, t
|| TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE))
|| (TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE
&& !TYPE_REFFN_P (type))
- || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
+ || DECL_NONSTATIC_MEMBER_FUNCTION_P (rhs))
rhs = decay_conversion (rhs, complain);
rhstype = TREE_TYPE (rhs);
Index: typeck2.c
===================================================================
--- typeck2.c (revision 213379)
+++ typeck2.c (working copy)
@@ -338,7 +338,7 @@ abstract_virtuals_error_sfinae (tree decl, tree ty
error ("cannot declare field %q+D to be of abstract type %qT",
decl, type);
else if (TREE_CODE (decl) == FUNCTION_DECL
- && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
error ("invalid abstract return type for member function %q+#D", decl);
else if (TREE_CODE (decl) == FUNCTION_DECL)
error ("invalid abstract return type for function %q+#D", decl);