This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++ PATCH] [PR14389] Find correct declaration for overloaded member template


Hello,

check_classfn is used to find a declaration for a member of a class, and emit
an error message if the declaration cannot be found. It constructs a list of
all the declarations at class scope with a given name, and then go through them
looking for the one that matches the function passed as argument. It is
supposed to work also for member templates, but in that case it was missing an
important check: it was not comparing template parameters.

This means that it was failing to disambiguate between two member templates
whose difference is only in the template header. For instance:

struct S {
   template <class T> void foo(void);
   template <class T, class U> void foo(void);
   template <int N> void foo(void);
};

The attacched testcase manages to ICE the C++ frontend in two different ways by
exploiting this wrong match between definition and declaration.

This patch cures this by asking the callers to pass the template parameters to
check_classfn, so that it can compare them against the existing member
declarations. Notice that check_classfn cannot always use
DECL_TEMPLATE_PARAMETERS to extract the template parameters by itself, because
in some cases the member template has not been build yet as a TEMPLATE_DECL,
and check_classfn is called with the member in its FUNCTION_DECL form.

Tested on i686-pc-linux-gnu with no new regressions, OK for mainline?

Giovanni Bajo


cp/
2004-03-03  Giovanni Bajo  <giovannibajo@gcc.gnu.org>

        PR c++/14389
        * decl2.c (check_classfn): For member templates, compare also the
        template parameters to match the declaration.
        * cp-tree.h: Adjust declaration of check_classfn.
        * decl.c (start_decl, grokfndecl): Adjust callers of check_classfn.
        * friend.c (do_friend): Likewise.
        * pt.c (tsubst_friend_function): Likewise.

testsuite/
2004-03-03  Giovanni Bajo  <giovannibajo@gcc.gnu.org>

        PR c++/14389
        * g++.dg/template/member5.C: New test.


Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.954
diff -c -3 -p -r1.954 cp-tree.h
*** cp-tree.h 17 Feb 2004 18:32:41 -0000 1.954
--- cp-tree.h 3 Mar 2004 18:11:12 -0000
*************** extern void maybe_make_one_only (tree);
*** 3704,3710 ****
  extern void grokclassfn (tree, tree, enum overload_flags, tree);
  extern tree grok_array_decl (tree, tree);
  extern tree delete_sanity (tree, tree, bool, int);
! extern tree check_classfn (tree, tree, bool);
  extern void check_member_template (tree);
  extern tree grokfield (tree, tree, tree, tree, tree);
  extern tree grokbitfield (tree, tree, tree);
--- 3704,3710 ----
  extern void grokclassfn (tree, tree, enum overload_flags, tree);
  extern tree grok_array_decl (tree, tree);
  extern tree delete_sanity (tree, tree, bool, int);
! extern tree check_classfn (tree, tree, tree);
  extern void check_member_template (tree);
  extern tree grokfield (tree, tree, tree, tree, tree);
  extern tree grokbitfield (tree, tree, tree);
Index: decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.699
diff -c -3 -p -r1.699 decl2.c
*** decl2.c 14 Feb 2004 00:49:12 -0000 1.699
--- decl2.c 3 Mar 2004 18:11:14 -0000
*************** check_java_method (tree method)
*** 612,626 ****

  /* Sanity check: report error if this function FUNCTION is not
     really a member of the class (CTYPE) it is supposed to belong to.
!    CNAME is the same here as it is for grokclassfn above.
!    TEMPLATE_HEADER_P is true when this declaration comes with a
!    template header.  */

  tree
! check_classfn (tree ctype, tree function, bool template_header_p)
  {
    int ix;
!   int is_template;

    if (DECL_USE_TEMPLATE (function)
        && !(TREE_CODE (function) == TEMPLATE_DECL
--- 612,630 ----

  /* Sanity check: report error if this function FUNCTION is not
     really a member of the class (CTYPE) it is supposed to belong to.
!    TEMPLATE_PARMS is used to specifiy the template parameters of a member
!    template passed as FUNCTION_DECL. If the member template is passed as a
!    TEMPLATE_DECL, it can be NULL since the parameters can be extracted
!    from the declaration. If the function is not a function template, it
!    must be NULL.
!    It returns the original declaration for the function, or NULL_TREE
!    if no declaration was found (and an error was emitted).  */

  tree
! check_classfn (tree ctype, tree function, tree template_parms)
  {
    int ix;
!   bool is_template;

    if (DECL_USE_TEMPLATE (function)
        && !(TREE_CODE (function) == TEMPLATE_DECL
*************** check_classfn (tree ctype, tree function
*** 638,646 ****
         find the method, but we don't complain.  */
      return NULL_TREE;

    /* OK, is this a definition of a member template?  */
!   is_template = (TREE_CODE (function) == TEMPLATE_DECL
!    || template_header_p);

    ix = lookup_fnfields_1 (complete_type (ctype),
       DECL_CONSTRUCTOR_P (function) ? ctor_identifier :
--- 642,661 ----
         find the method, but we don't complain.  */
      return NULL_TREE;

+   /* Basic sanity check: for a template function, the template parameters
+      either were not passed, or they are the same of DECL_TEMPLATE_PARMS.  */
+   if (TREE_CODE (function) == TEMPLATE_DECL)
+     {
+       my_friendly_assert (!template_parms
+      || comp_template_parms
+          (template_parms,
+           DECL_TEMPLATE_PARMS (function)),
+      20040303);
+       template_parms = DECL_TEMPLATE_PARMS (function);
+     }
+
    /* OK, is this a definition of a member template?  */
!   is_template = (template_parms != NULL_TREE);

    ix = lookup_fnfields_1 (complete_type (ctype),
       DECL_CONSTRUCTOR_P (function) ? ctor_identifier :
*************** check_classfn (tree ctype, tree function
*** 683,688 ****
--- 698,706 ----
     if (same_type_p (TREE_TYPE (TREE_TYPE (function)),
        TREE_TYPE (TREE_TYPE (fndecl)))
         && compparms (p1, p2)
+        && (!is_template
+     || comp_template_parms (template_parms,
+        DECL_TEMPLATE_PARMS (fndecl)))
         && (DECL_TEMPLATE_SPECIALIZATION (function)
      == DECL_TEMPLATE_SPECIALIZATION (fndecl))
         && (!DECL_TEMPLATE_SPECIALIZATION (function)
Index: decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1187
diff -c -3 -p -r1.1187 decl.c
*** decl.c 17 Feb 2004 21:33:40 -0000 1.1187
--- decl.c 3 Mar 2004 18:11:21 -0000
*************** start_decl (tree declarator,
*** 3778,3785 ****
        else
   {
     tree field = check_classfn (context, decl,
!           processing_template_decl
!           > template_class_depth (context));
     if (field && duplicate_decls (decl, field))
       decl = field;
   }
--- 3778,3787 ----
        else
   {
     tree field = check_classfn (context, decl,
!           (processing_template_decl
!            > template_class_depth (context))
!           ? current_template_parms
!           : NULL_TREE);
     if (field && duplicate_decls (decl, field))
       decl = field;
   }
*************** grokfndecl (tree ctype,
*** 5717,5724 ****
        tree old_decl;

        old_decl = check_classfn (ctype, decl,
!     processing_template_decl
!     > template_class_depth (ctype));

        if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
   /* Because grokfndecl is always supposed to return a
--- 5719,5728 ----
        tree old_decl;

        old_decl = check_classfn (ctype, decl,
!     (processing_template_decl
!      > template_class_depth (ctype))
!     ? current_template_parms
!     : NULL_TREE);

        if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
   /* Because grokfndecl is always supposed to return a
Index: friend.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/friend.c,v
retrieving revision 1.93
diff -c -3 -p -r1.93 friend.c
*** friend.c 19 Dec 2003 23:28:06 -0000 1.93
--- friend.c 3 Mar 2004 18:11:21 -0000
*************** do_friend (tree ctype, tree declarator,
*** 401,407 ****
          validity of the declaration later.  */
       decl = push_template_decl_real (decl, /*is_friend=*/1);
     else
!      decl = check_classfn (ctype, decl, template_member_p);

     if (template_member_p && decl && TREE_CODE (decl) == FUNCTION_DECL)
       decl = DECL_TI_TEMPLATE (decl);
--- 401,410 ----
          validity of the declaration later.  */
       decl = push_template_decl_real (decl, /*is_friend=*/1);
     else
!      decl = check_classfn (ctype, decl,
!       template_member_p
!       ? current_template_parms
!       : NULL_TREE);

     if (template_member_p && decl && TREE_CODE (decl) == FUNCTION_DECL)
       decl = DECL_TI_TEMPLATE (decl);
Index: pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.830
diff -c -3 -p -r1.830 pt.c
*** pt.c 14 Feb 2004 11:28:59 -0000 1.830
--- pt.c 3 Mar 2004 18:11:27 -0000
*************** tsubst_friend_function (tree decl, tree
*** 5135,5142 ****
      {
        /* Check to see that the declaration is really present, and,
    possibly obtain an improved declaration.  */
!       tree fn = check_classfn (DECL_CONTEXT (new_friend),
!           new_friend, false);

        if (fn)
   new_friend = fn;
--- 5135,5142 ----
      {
        /* Check to see that the declaration is really present, and,
    possibly obtain an improved declaration.  */
!       tree fn = check_classfn (DECL_CONTEXT (new_friend),
!           new_friend, NULL_TREE);

        if (fn)
   new_friend = fn;



// { dg-do compile }
// Contributed by: <fasbjx at free dot fr>
// PR c++/14389: Disambiguate overloaded member templates which differ only
//  in the template argument list.

namespace N1 {

  struct S {
      template< typename B, typename A > void foo();
      template< typename A >             void foo();
  };

  template< typename A >             void S::foo() {}
  template< typename B, typename A > void S::foo() {}

  template void S::foo<void> ();
  template void S::foo<void,void> ();

}

namespace N2 {

  struct S {
    template< typename _A > void foo();
    template< int _i >      void foo();
  };

  template< typename _A > void S::foo() {}

  template void S::foo< 0 >();    // { dg-error "no definition
available|instantiated from here" }

}



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]