re PR c++/19076 (Pointer to member function not matched to pointer to member template)
authorDouglas Gregor <dgregor@cs.indiana.edu>
Mon, 21 Feb 2005 23:12:27 +0000 (23:12 +0000)
committerPaolo Carlini <paolo@gcc.gnu.org>
Mon, 21 Feb 2005 23:12:27 +0000 (23:12 +0000)
2005-02-21  Douglas Gregor  <dgregor@cs.indiana.edu>

PR c++/19076
PR c++/6628
* cp-tree.h (cp_apply_type_quals_to_decl): Declared.
* decl.c (grokdeclarator): Pedwarn about qualifying a function
type.
Add qualifiers when declaring a typedef of a function type.
Member function pointers pick up the qualifiers of the typedef
used to declare them.
        Don't complain about creating cv-qualified function types.
Complain about qualified function typedefs that are used to
declare non-static member functions or free functions.
Use cp_apply_type_quals_to_decl.
(start_preparsed_function): Use cp_apply_type_quals_to_decl.
(grokclassfn): Use cp_apply_type_quals_to_decl.
* error.c (dump_type_suffix): Print qualifiers for function
types.
* pt.c (tsubst_decl): Use cp_apply_type_quals_to_decl.
(tsubst): When substituting a function type into a member
pointer type, pass along the qualifiers.
(unify): Unify member pointers to member function pointers.
* tree.c (cp_build_qualified_type_real): Function types may be
qualified. This includes restrict qualifiers.
* typeck.c (cp_apply_type_quals_to_decl): New function to replace
use of c_apply_type_quals_to_decl. Drops qualifiers that are being
added to function types.

From-SVN: r95356

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/error.c
gcc/cp/pt.c
gcc/cp/tree.c
gcc/cp/typeck.c

index e190787041be776205474e5247ea8f188090b47a..ae75f8fc23fecdad470cc2e68237c73a6a14e393 100644 (file)
@@ -1,3 +1,31 @@
+2005-02-21  Douglas Gregor  <dgregor@cs.indiana.edu>
+       
+       PR c++/19076
+       PR c++/6628
+       * cp-tree.h (cp_apply_type_quals_to_decl): Declared.
+       * decl.c (grokdeclarator): Pedwarn about qualifying a function
+       type. 
+       Add qualifiers when declaring a typedef of a function type.
+       Member function pointers pick up the qualifiers of the typedef
+       used to declare them.
+        Don't complain about creating cv-qualified function types.
+       Complain about qualified function typedefs that are used to
+       declare non-static member functions or free functions.
+       Use cp_apply_type_quals_to_decl.
+       (start_preparsed_function): Use cp_apply_type_quals_to_decl.
+       (grokclassfn): Use cp_apply_type_quals_to_decl.
+       * error.c (dump_type_suffix): Print qualifiers for function
+       types. 
+       * pt.c (tsubst_decl): Use cp_apply_type_quals_to_decl.
+       (tsubst): When substituting a function type into a member
+       pointer type, pass along the qualifiers.
+       (unify): Unify member pointers to member function pointers.
+       * tree.c (cp_build_qualified_type_real): Function types may be
+       qualified. This includes restrict qualifiers.
+       * typeck.c (cp_apply_type_quals_to_decl): New function to replace
+       use of c_apply_type_quals_to_decl. Drops qualifiers that are being
+       added to function types.
+
 2005-02-20  Zack Weinberg  <zack@codesourcery.com>
 
        PR 18785
index bd5d0eca14dad7ea8756030be70da60333950fbf..d99ae7f74c1d46d5f454ee49de63b58b687ffb7c 100644 (file)
@@ -4310,6 +4310,7 @@ extern tree build_ptrmemfunc                      (tree, tree, int, bool);
 extern int cp_type_quals                        (tree);
 extern bool cp_has_mutable_p                     (tree);
 extern bool at_least_as_qualified_p              (tree, tree);
+extern void cp_apply_type_quals_to_decl         (int, tree);
 extern tree build_ptrmemfunc1                   (tree, tree, tree);
 extern void expand_ptrmemfunc_cst               (tree, tree *, tree *);
 extern tree pfn_from_ptrmemfunc                 (tree);
index 2f6b98f42554c526b759715675e585bde6182d57..1613488acb73047555b9afbf67ac1d00e587b997 100644 (file)
@@ -6939,6 +6939,20 @@ grokdeclarator (const cp_declarator *declarator,
     error ("qualifiers are not allowed on declaration of %<operator %T%>",
            ctor_return_type);
 
+  if (TREE_CODE (type) == FUNCTION_TYPE 
+      && type_quals != TYPE_UNQUALIFIED)
+    {
+      /* This was an error in C++98 (cv-qualifiers cannot be added to
+         a function type), but DR 295 makes the code well-formed by
+         dropping the extra qualifiers. */
+      if (pedantic)
+        {
+          tree bad_type = build_qualified_type (type, type_quals);
+          pedwarn ("ignoring %qV qualifiers added to function type %qT",
+                   bad_type, type);
+        }
+      type_quals = TYPE_UNQUALIFIED;
+    }
   type_quals |= cp_type_quals (type);
   type = cp_build_qualified_type_real
     (type, type_quals, ((typedef_decl && !DECL_ARTIFICIAL (typedef_decl)
@@ -7300,6 +7314,7 @@ grokdeclarator (const cp_declarator *declarator,
              }
 
            type = build_function_type (type, arg_types);
+            type = cp_build_qualified_type (type, quals);
          }
          break;
 
@@ -7332,7 +7347,15 @@ grokdeclarator (const cp_declarator *declarator,
              && (TREE_CODE (type) == FUNCTION_TYPE
                  || (quals && TREE_CODE (type) == METHOD_TYPE)))
            {
-             tree dummy = build_decl (TYPE_DECL, NULL_TREE, type);
+             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);
@@ -7629,11 +7652,12 @@ grokdeclarator (const cp_declarator *declarator,
        {
          if (ctype == NULL_TREE)
            {
-             if (TREE_CODE (type) != METHOD_TYPE)
-               error ("%Jinvalid type qualifier for non-member function type",
-                      decl);
-             else
+              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);
@@ -7676,6 +7700,23 @@ grokdeclarator (const cp_declarator *declarator,
        }
 
       parms = nreverse (decls);
+
+      if (decl_context != TYPENAME)
+        {
+          /* A cv-qualifier-seq shall only be part of the function type
+             for a non-static member function. [8.3.5/4 dcl.fct] */ 
+          if (cp_type_quals (type) != TYPE_UNQUALIFIED
+              && (current_class_type == NULL_TREE || staticp) )
+            {
+              error ("qualified function types cannot be used to declare %s functions",
+                     (staticp? "static member" : "free"));
+              type = TYPE_MAIN_VARIANT (type);
+            }
+          
+          /* The qualifiers on the function type become the qualifiers on
+             the non-static member function. */
+          quals |= cp_type_quals (type);
+        }
     }
 
   /* If this is a type name (such as, in a cast or sizeof),
@@ -8211,7 +8252,7 @@ grokdeclarator (const cp_declarator *declarator,
        when processing a template; we'll do this for the instantiated
        declaration based on the type of DECL.  */
     if (!processing_template_decl)
-      c_apply_type_quals_to_decl (type_quals, decl);
+      cp_apply_type_quals_to_decl (type_quals, decl);
 
     return decl;
   }
@@ -9995,7 +10036,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
       DECL_IGNORED_P (resdecl) = 1;
       DECL_RESULT (decl1) = resdecl;
 
-      c_apply_type_quals_to_decl (cp_type_quals (restype), resdecl);
+      cp_apply_type_quals_to_decl (cp_type_quals (restype), resdecl);
     }
 
   /* Initialize RTL machinery.  We cannot do this until
index 113386a880f97a64d0da76b7dfc91dc7c79d5713..8243cb144654f1a7a333c6bb5336660c686786c6 100644 (file)
@@ -299,7 +299,7 @@ grokclassfn (tree ctype, tree function, enum overload_flags flags,
       this_quals |= TYPE_QUAL_CONST;
       qual_type = cp_build_qualified_type (type, this_quals);
       parm = build_artificial_parm (this_identifier, qual_type);
-      c_apply_type_quals_to_decl (this_quals, parm);
+      cp_apply_type_quals_to_decl (this_quals, parm);
       TREE_CHAIN (parm) = DECL_ARGUMENTS (function);
       DECL_ARGUMENTS (function) = parm;
     }
index ec332f2273ba1696e6a16847443352e2a9ef1acd..86ea7aa6edaaa047282df79c76c16cd8a530466b 100644 (file)
@@ -613,6 +613,8 @@ dump_type_suffix (tree t, int flags)
        if (TREE_CODE (t) == METHOD_TYPE)
           pp_cxx_cv_qualifier_seq
             (cxx_pp, TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))));
+        else
+          pp_cxx_cv_qualifier_seq(cxx_pp, t);
        dump_exception_spec (TYPE_RAISES_EXCEPTIONS (t), flags);
        dump_type_suffix (TREE_TYPE (t), flags);
        break;
index 7025deff7887d8d5696343593fc99a44fba20c40..0d83bc1a4d278f164dc63336ab4d27fa26b12ba2 100644 (file)
@@ -6469,7 +6469,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 
        type = tsubst (TREE_TYPE (t), args, complain, in_decl);
        TREE_TYPE (r) = type;
-       c_apply_type_quals_to_decl (cp_type_quals (type), r);
+       cp_apply_type_quals_to_decl (cp_type_quals (type), r);
 
        if (DECL_INITIAL (r))
          {
@@ -6499,7 +6499,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
        if (type == error_mark_node)
          return error_mark_node;
        TREE_TYPE (r) = type;
-       c_apply_type_quals_to_decl (cp_type_quals (type), r);
+       cp_apply_type_quals_to_decl (cp_type_quals (type), r);
 
        /* We don't have to set DECL_CONTEXT here; it is set by
           finish_member_declaration.  */
@@ -6599,7 +6599,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
        else if (DECL_SELF_REFERENCE_P (t))
          SET_DECL_SELF_REFERENCE_P (r);
        TREE_TYPE (r) = type;
-       c_apply_type_quals_to_decl (cp_type_quals (type), r);
+       cp_apply_type_quals_to_decl (cp_type_quals (type), r);
        DECL_CONTEXT (r) = ctx;
        /* Clear out the mangled name and RTL for the instantiation.  */
        SET_DECL_ASSEMBLER_NAME (r, NULL_TREE);
@@ -7218,22 +7218,18 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
        gcc_assert (TREE_CODE (type) != METHOD_TYPE);
        if (TREE_CODE (type) == FUNCTION_TYPE)
          {
-           /* This is really a method type. The cv qualifiers of the
-              this pointer should _not_ be determined by the cv
-              qualifiers of the class type.  They should be held
-              somewhere in the FUNCTION_TYPE, but we don't do that at
-              the moment.  Consider
-                 typedef void (Func) () const;
-
-                 template <typename T1> void Foo (Func T1::*);
-
-               */
+            /* The type of the implicit object parameter gets its
+               cv-qualifiers from the FUNCTION_TYPE. */
            tree method_type;
-
-           method_type = build_method_type_directly (TYPE_MAIN_VARIANT (r),
+            tree this_type = cp_build_qualified_type (TYPE_MAIN_VARIANT (r),
+                                                      cp_type_quals (type));
+            tree memptr;
+            method_type = build_method_type_directly (this_type,
                                                      TREE_TYPE (type),
                                                      TYPE_ARG_TYPES (type));
-           return build_ptrmemfunc_type (build_pointer_type (method_type));
+            memptr = build_ptrmemfunc_type (build_pointer_type (method_type));
+            return cp_build_qualified_type_real (memptr, cp_type_quals (t),
+                                                 complain);
          }
        else
          return cp_build_qualified_type_real (build_ptrmem_type (r, type),
@@ -10251,6 +10247,37 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
                                    DEDUCE_EXACT, 0, -1);
 
     case OFFSET_TYPE:
+      /* Unify a pointer to member with a pointer to member function, which
+         deduces the type of the member as a function type. */
+      if (TYPE_PTRMEMFUNC_P (arg))
+        {
+          tree method_type;
+          tree fntype;
+          cp_cv_quals cv_quals;
+
+          /* Check top-level cv qualifiers */
+          if (!check_cv_quals_for_unify (UNIFY_ALLOW_NONE, arg, parm))
+            return 1;
+
+          if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
+                     TYPE_PTRMEMFUNC_OBJECT_TYPE (arg), UNIFY_ALLOW_NONE))
+            return 1;
+
+          /* Determine the type of the function we are unifying against. */
+          method_type = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (arg));
+          fntype = 
+            build_function_type (TREE_TYPE (method_type),
+                                 TREE_CHAIN (TYPE_ARG_TYPES (method_type)));
+
+          /* Extract the cv-qualifiers of the member function from the
+             implicit object parameter and place them on the function
+             type to be restored later. */
+          cv_quals = 
+            cp_type_quals(TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (method_type))));
+          fntype = build_qualified_type (fntype, cv_quals);
+          return unify (tparms, targs, TREE_TYPE (parm), fntype, strict);
+        }
+
       if (TREE_CODE (arg) != OFFSET_TYPE)
        return 1;
       if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
index 8a264d7afa94e5b0bbe82ebd0bce3a79babe577e..321ba4bdbc7090e8d2977a21390f200214ef13cf 100644 (file)
@@ -499,11 +499,10 @@ cp_build_qualified_type_real (tree type,
       return build_ptrmemfunc_type (t);
     }
 
-  /* A reference, function or method type shall not be cv qualified.
+  /* A reference or method type shall not be cv qualified.
      [dcl.ref], [dct.fct]  */
   if (type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)
       && (TREE_CODE (type) == REFERENCE_TYPE
-         || TREE_CODE (type) == FUNCTION_TYPE
          || TREE_CODE (type) == METHOD_TYPE))
     {
       bad_quals |= type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
@@ -511,10 +510,11 @@ cp_build_qualified_type_real (tree type,
     }
 
   /* A restrict-qualified type must be a pointer (or reference)
-     to object or incomplete type */
+     to object or incomplete type, or a function type. */
   if ((type_quals & TYPE_QUAL_RESTRICT)
       && TREE_CODE (type) != TEMPLATE_TYPE_PARM
       && TREE_CODE (type) != TYPENAME_TYPE
+      && TREE_CODE (type) != FUNCTION_TYPE
       && !POINTER_TYPE_P (type))
     {
       bad_quals |= TYPE_QUAL_RESTRICT;
index e0dc1ebdb4936923546ed8291ec9f769e43688ab..4a6ded4c4a73c11c58175c3a443aa21e5b5746f6 100644 (file)
@@ -6383,6 +6383,35 @@ cp_has_mutable_p (tree type)
   return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type);
 }
 
+/* Apply the TYPE_QUALS to the new DECL.  */
+void
+cp_apply_type_quals_to_decl (int type_quals, tree decl)
+{
+  tree type = TREE_TYPE (decl);
+
+  if (type == error_mark_node)
+    return;
+
+  if (TREE_CODE (type) == FUNCTION_TYPE 
+      && type_quals != TYPE_UNQUALIFIED)
+    {
+      /* This was an error in C++98 (cv-qualifiers cannot be added to
+         a function type), but DR 295 makes the code well-formed by
+         dropping the extra qualifiers. */
+      if (pedantic)
+        {
+          tree bad_type = build_qualified_type (type, type_quals);
+          pedwarn ("ignoring %qV qualifiers added to function type %qT",
+                   bad_type, type);
+        }
+
+      TREE_TYPE (decl) = TYPE_MAIN_VARIANT (type);
+      return;
+    }
+
+  c_apply_type_quals_to_decl (type_quals, decl);
+}
+
 /* Subroutine of casts_away_constness.  Make T1 and T2 point at
    exemplar types such that casting T1 to T2 is casting away constness
    if and only if there is no implicit conversion from T1 to T2.  */