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

Reply via email to