re PR c++/26912 (friend const member function specialization fails to compile)
authorMark Mitchell <mark@codesourcery.com>
Mon, 24 Apr 2006 03:50:31 +0000 (03:50 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Mon, 24 Apr 2006 03:50:31 +0000 (03:50 +0000)
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

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/friend.c
gcc/cp/method.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/friend41.C [new file with mode: 0644]

index a0a44a54075b757c6dedd2d341e9dc7efe69fc1a..0d24702efa844fe2fba372c4682fc365f194b12e 100644 (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.
index 34cccc0a911fab926c92cd93aeb5938e01475011..1e3c1b7807dbcd81b7b9caa44c939ee56f45dbae 100644 (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);
index d979fd3521a7e9adf9dec34b829cb2a60e690590..c7967c7709b40f2b03293bebf1c2874c02b8f996 100644 (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)
index ed26db2fe3414f2975f1f248e7d543604183de8b..fe5db71c653e06e25a9f5518ae1296deb52816e9 100644 (file)
@@ -103,33 +103,28 @@ tree static_ctors;
 tree static_dtors;
 
 \f
-/* 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)
index 0ae9130b61abb6d249ded687f137707388b1e616..ac73e5f4787625ea4af7dbf182ff7b2709017e91 100644 (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)
        {
index d2bee99dc5e182c3ada1a3ee8d4433d65ea6d878..68ec8ab418160eb3a4882fce30a9f85074e11851 100644 (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);
index 6e05f64362d4129bf6b07dadc93b57c621c99c9d..535d2f5b6321e9d91b4667220cccd9893f36f9b6 100644 (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.
diff --git a/gcc/testsuite/g++.dg/template/friend41.C b/gcc/testsuite/g++.dg/template/friend41.C
new file mode 100644 (file)
index 0000000..6d68601
--- /dev/null
@@ -0,0 +1,11 @@
+// PR c++/26912
+
+struct Foo { 
+  template<class T> int func() const; 
+}; 
+
+class Bar { 
+  friend int Foo::func<int>() const;
+}; 
+
+