re PR c++/4361 (bogus ambiguity taking the address of a member template)
authorNathan Sidwell <nathan@codesourcery.com>
Sat, 16 Mar 2002 18:30:16 +0000 (18:30 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Sat, 16 Mar 2002 18:30:16 +0000 (18:30 +0000)
cp:
PR c++/4361
* cp-tree.h (CLASSTYPE_METHOD_VEC): Document where templated
conversion operators go.
(struct lang_decl_flags): Add template_conv_p and unused
bitfields.
(DECL_TEMPLATE_CONV_FN_P): New macro.
* call.c (build_user_type_conversion_1): Don't check second type
conversion of overload set first.
* class.c (add_method): Make sure templated conversion operators
all end up on slot 2.
* lex.c (do_identifier): A conversion operator token might be
satisfied by a templated conversion operator.
* mangle.c (struct globals) Add internal_mangling_p member.
(write_template_param): Do internal mangling, if needed.
(mangle_conv_op_name_for_type): Request internal mangling.
* pt.c (check_explicit_specialization): Use
CLASSTYPE_FIRST_CONVERSION_SLOT.
(template_parm_this_level_p): New function.
(push_template_decl_real): Determine DECL_TEMPLATE_CONV_FN_P.
* search.c (lookup_fn_fields_1): Template conversions will be on
the first slot.
* typeck.c (build_component_ref): Preserve the type of an
conversion operator name on the overload type.
(build_x_function_call): Retrieve the conversion operator name.
testsuite:
* g++.dg/template/conv1.C: New test.
* g++.dg/template/conv2.C: New test.
* g++.dg/template/conv3.C: New test.
* g++.dg/template/conv4.C: New test.

From-SVN: r50889

13 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/lex.c
gcc/cp/pt.c
gcc/cp/search.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/conv1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/conv2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/conv3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/conv4.C [new file with mode: 0644]

index 660e202b56293d94d8baabb74b0e09d86e381043..b5d947a2e666f774ac5aa533fe9de057a867aa80 100644 (file)
@@ -1,3 +1,30 @@
+2002-03-16  Nathan Sidwell  <nathan@codesourcery.com>
+
+       PR c++/4361
+       * cp-tree.h (CLASSTYPE_METHOD_VEC): Document where templated
+       conversion operators go.
+       (struct lang_decl_flags): Add template_conv_p and unused
+       bitfields.
+       (DECL_TEMPLATE_CONV_FN_P): New macro.
+       * call.c (build_user_type_conversion_1): Don't check second type
+       conversion of overload set first.
+       * class.c (add_method): Make sure templated conversion operators
+       all end up on slot 2.
+       * lex.c (do_identifier): A conversion operator token might be
+       satisfied by a templated conversion operator.
+       * mangle.c (struct globals) Add internal_mangling_p member.
+       (write_template_param): Do internal mangling, if needed.
+       (mangle_conv_op_name_for_type): Request internal mangling.
+       * pt.c (check_explicit_specialization): Use
+       CLASSTYPE_FIRST_CONVERSION_SLOT.
+       (template_parm_this_level_p): New function.
+       (push_template_decl_real): Determine DECL_TEMPLATE_CONV_FN_P.
+       * search.c (lookup_fn_fields_1): Template conversions will be on
+       the first slot.
+       * typeck.c (build_component_ref): Preserve the type of an
+       conversion operator name on the overload type.
+       (build_x_function_call): Retrieve the conversion operator name.
+
 2002-03-15  Richard Henderson  <rth@redhat.com>
 
        * init.c (build_new_1): Use size_binop instead of cp_build_binary_op.
index 6f67e3d7b51172f50aeee731fe48fa98d04ba17f..357c0683e0b93a2b1134054e5ea63a6dc42a17c2 100644 (file)
@@ -2444,7 +2444,6 @@ build_user_type_conversion_1 (totype, expr, flags)
     {
       tree fns = TREE_VALUE (convs);
       int convflags = LOOKUP_NO_CONVERSION;
-      tree ics;
 
       /* If we are called to convert to a reference type, we are trying to
         find an lvalue binding, so don't even consider temporaries.  If
@@ -2452,57 +2451,46 @@ build_user_type_conversion_1 (totype, expr, flags)
         look for a temporary binding.  */
       if (TREE_CODE (totype) == REFERENCE_TYPE)
        convflags |= LOOKUP_NO_TEMP_BIND;
+      
+      for (; fns; fns = OVL_NEXT (fns))
+       {
+         tree fn = OVL_CURRENT (fns);
+         struct z_candidate *old_candidates = candidates;
+         
+         /* [over.match.funcs] For conversion functions, the function
+            is considered to be a member of the class of the implicit
+            object argument for the purpose of defining the type of
+            the implicit object parameter.
 
-      if (TREE_CODE (OVL_CURRENT (fns)) != TEMPLATE_DECL)
-       ics = implicit_conversion
-         (totype, TREE_TYPE (TREE_TYPE (OVL_CURRENT (fns))), 0, convflags);
-      else
-       /* We can't compute this yet.  */
-       ics = error_mark_node;
-
-      if (TREE_CODE (totype) == REFERENCE_TYPE && ics && ICS_BAD_FLAG (ics))
-       /* ignore the near match.  */;
-      else if (ics)
-       for (; fns; fns = OVL_NEXT (fns))
-         {
-           tree fn = OVL_CURRENT (fns);
-           struct z_candidate *old_candidates = candidates;
-
-           /* [over.match.funcs] For conversion functions, the function is
-              considered to be a member of the class of the implicit object
-              argument for the purpose of defining the type of the implicit
-              object parameter.
+            So we pass fromtype as CTYPE to add_*_candidate.  */
 
-              So we pass fromtype as CTYPE to add_*_candidate.  */
+         if (TREE_CODE (fn) == TEMPLATE_DECL)
+           {
+             templates = tree_cons (NULL_TREE, fn, templates);
+             candidates = 
+               add_template_candidate (candidates, fn, fromtype, NULL_TREE,
+                                       args, totype, flags,
+                                       DEDUCE_CONV);
+           } 
+         else 
+           candidates = add_function_candidate (candidates, fn, fromtype,
+                                                args, flags); 
 
-           if (TREE_CODE (fn) == TEMPLATE_DECL)
-             {
-               templates = tree_cons (NULL_TREE, fn, templates);
-               candidates = 
-                 add_template_candidate (candidates, fn, fromtype, NULL_TREE,
-                                         args, totype, flags,
-                                         DEDUCE_CONV);
-             } 
-           else 
-             candidates = add_function_candidate (candidates, fn, fromtype,
-                                                  args, flags); 
+         if (candidates != old_candidates)
+           {
+             tree ics = implicit_conversion
+               (totype, TREE_TYPE (TREE_TYPE (candidates->fn)),
+                0, convflags);
 
-           if (candidates != old_candidates)
-             {
-               if (TREE_CODE (fn) == TEMPLATE_DECL)
-                 ics = implicit_conversion
-                   (totype, TREE_TYPE (TREE_TYPE (candidates->fn)),
-                    0, convflags);
-
-               candidates->second_conv = ics;
-               candidates->basetype_path = TYPE_BINFO (fromtype);
-
-               if (ics == NULL_TREE)
-                 candidates->viable = 0;
-               else if (candidates->viable == 1 && ICS_BAD_FLAG (ics))
-                 candidates->viable = -1;
-             }
-         }
+             candidates->second_conv = ics;
+             candidates->basetype_path = TYPE_BINFO (fromtype);
+             
+             if (ics == NULL_TREE)
+               candidates->viable = 0;
+             else if (candidates->viable == 1 && ICS_BAD_FLAG (ics))
+               candidates->viable = -1;
+           }
+       }
     }
 
   if (! any_viable (candidates))
index 9e3c110a2e504116ebff5c3af62e0dbcdca339c0..ae8b34e159254eeb40e5ba1d429e6f84ee87ccd3 100644 (file)
@@ -856,6 +856,8 @@ add_method (type, method, error_p)
   int len;
   int slot;
   tree method_vec;
+  int template_conv_p = (TREE_CODE (method) == TEMPLATE_DECL
+                        && DECL_TEMPLATE_CONV_FN_P (method));
 
   if (!CLASSTYPE_METHOD_VEC (type))
     /* Make a new method vector.  We start with 8 entries.  We must
@@ -880,14 +882,36 @@ add_method (type, method, error_p)
     slot = CLASSTYPE_DESTRUCTOR_SLOT;
   else
     {
+      int have_template_convs_p = 0;
+      
       /* See if we already have an entry with this name.  */
       for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; slot < len; ++slot)
-       if (!TREE_VEC_ELT (method_vec, slot)
-           || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, 
-                                                     slot))) 
-               == DECL_NAME (method)))
-         break;
-               
+       {
+         tree m = TREE_VEC_ELT (method_vec, slot);
+
+         if (!m)
+           break;
+         m = OVL_CURRENT (m);
+         
+         if (template_conv_p)
+           {
+             have_template_convs_p = (TREE_CODE (m) == TEMPLATE_DECL
+                                      && DECL_TEMPLATE_CONV_FN_P (m));
+             
+             /* If we need to move things up, see if there's
+                space. */
+             if (!have_template_convs_p)
+               {
+                 slot = len - 1;
+                 if (TREE_VEC_ELT (method_vec, slot))
+                   slot++;
+               }
+             break;
+           }
+         if (DECL_NAME (m) == DECL_NAME (method))
+           break;
+       }
+      
       if (slot == len)
        {
          /* We need a bigger method vector.  */
@@ -920,22 +944,27 @@ add_method (type, method, error_p)
             slide some of the vector elements up.  In theory, this
             makes this algorithm O(N^2) but we don't expect many
             conversion operators.  */
-         for (slot = 2; slot < len; ++slot)
-           {
-             tree fn = TREE_VEC_ELT (method_vec, slot);
+         if (template_conv_p)
+           slot = CLASSTYPE_FIRST_CONVERSION_SLOT;
+         else
+           for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; slot < len; ++slot)
+             {
+               tree fn = TREE_VEC_ELT (method_vec, slot);
   
-             if (!fn)
-               /* There are no more entries in the vector, so we
-                  can insert the new conversion operator here.  */
-               break;
+               if (!fn)
+                 /* There are no more entries in the vector, so we
+                    can insert the new conversion operator here.  */
+                 break;
                  
-             if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
-               /* We can insert the new function right at the
-                  SLOTth position.  */
-               break;
-           }
-  
-         if (!TREE_VEC_ELT (method_vec, slot))
+               if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
+                 /* We can insert the new function right at the
+                    SLOTth position.  */
+                 break;
+             }
+
+         if (template_conv_p && have_template_convs_p)
+           /*OK*/;
+         else if (!TREE_VEC_ELT (method_vec, slot))
            /* There is nothing in the Ith slot, so we can avoid
               moving anything.  */
                ; 
@@ -1036,7 +1065,7 @@ add_method (type, method, error_p)
   TREE_VEC_ELT (method_vec, slot) 
     = build_overload (method, TREE_VEC_ELT (method_vec, slot));
 
-      /* Add the new binding.  */ 
+  /* Add the new binding.  */ 
   if (!DECL_CONSTRUCTOR_P (method)
       && !DECL_DESTRUCTOR_P (method))
     push_class_level_binding (DECL_NAME (method),
index 68a141c5b5673a4578c8073080a98f86bc4b3b1b..fac6a9d3ccbc2cf21f2e932dce4fece481e8f278 100644 (file)
@@ -1358,8 +1358,14 @@ struct lang_type
    either a FUNCTION_DECL, a TEMPLATE_DECL, or an OVERLOAD.  All
    functions with the same name end up in the same slot.  The first
    two elements are for constructors, and destructors, respectively.
-   Any conversion operators are next, followed by ordinary member
-   functions.  There may be empty entries at the end of the vector.  */
+   All template conversion operators to innermost template dependent
+   types are overloaded on the next slot, if they exist.  Note, the
+   names for these functions will not all be the same.  The
+   non-template conversion operators & templated conversions to
+   non-innermost template types are next, followed by ordinary member
+   functions.  There may be empty entries at the end of the vector.
+   The conversion operators are unsorted. The ordinary member
+   functions are sorted, once the class is complete.  */
 #define CLASSTYPE_METHOD_VEC(NODE) (TYPE_LANG_SPECIFIC (NODE)->methods)
 
 /* The slot in the CLASSTYPE_METHOD_VEC where constructors go.  */
@@ -1761,7 +1767,9 @@ struct lang_decl_flags
   unsigned global_dtor_p : 1;
   unsigned assignment_operator_p : 1;
   unsigned anticipated_p : 1;
-  /* Four unused bits.  */
+  unsigned template_conv_p : 1;
+  
+  unsigned unused : 3; /* Three unused bits.  */
 
   union {
     /* In a FUNCTION_DECL, VAR_DECL, TYPE_DECL, or TEMPLATE_DECL, this
@@ -1949,6 +1957,12 @@ struct lang_decl
 #define DECL_CONV_FN_P(NODE) \
   (IDENTIFIER_TYPENAME_P (DECL_NAME (NODE)))
 
+/* Non-zero if NODE, which is a TEMPLATE_DECL, is a template
+   conversion operator to a type dependent on the innermost template
+   args.  */
+#define DECL_TEMPLATE_CONV_FN_P(NODE) \
+  (DECL_LANG_SPECIFIC (NODE)->decl_flags.template_conv_p)
+
 /* Set the overloaded operator code for NODE to CODE.  */
 #define SET_OVERLOADED_OPERATOR_CODE(NODE, CODE) \
   (DECL_LANG_SPECIFIC (NODE)->u2.operator_code = (CODE))
index 5990df946e1bb18d6a5f02592df572f9dfd1cd16..7290a360db6b09f77cf48ff211cdaf5a3cd81f61 100644 (file)
@@ -1199,6 +1199,9 @@ do_identifier (token, parsing, args)
     {
       if (current_template_parms)
        return build_min_nt (LOOKUP_EXPR, token);
+      else if (IDENTIFIER_TYPENAME_P (token))
+       /* A templated conversion operator might exist.  */
+       return token;
       else if (IDENTIFIER_OPNAME_P (token))
        {
          if (token != ansi_opname (ERROR_MARK))
index 152ac0e3820289a2156392fc0529ecbd485a8f0a..7e82b44cd613808b8040eeccdf6b46d1946d82ff 100644 (file)
@@ -132,6 +132,7 @@ static int unregister_specialization PARAMS ((tree, tree));
 static tree reduce_template_parm_level PARAMS ((tree, tree, int));
 static tree build_template_decl PARAMS ((tree, tree));
 static int mark_template_parm PARAMS ((tree, void *));
+static int template_parm_this_level_p PARAMS ((tree, void *));
 static tree tsubst_friend_function PARAMS ((tree, tree));
 static tree tsubst_friend_class PARAMS ((tree, tree));
 static tree get_bindings_real PARAMS ((tree, tree, tree, int, int, int));
@@ -1579,7 +1580,8 @@ check_explicit_specialization (declarator, decl, template_count, flags)
 
              methods = CLASSTYPE_METHOD_VEC (ctype);
              if (methods)
-               for (idx = 2; idx < TREE_VEC_LENGTH (methods); ++idx) 
+               for (idx = CLASSTYPE_FIRST_CONVERSION_SLOT;
+                    idx < TREE_VEC_LENGTH (methods); ++idx) 
                  {
                    tree ovl = TREE_VEC_ELT (methods, idx);
 
@@ -2496,6 +2498,26 @@ check_default_tmpl_args (decl, parms, is_primary, is_partial)
     }
 }
 
+/* Worker for push_template_decl_real, called via
+   for_each_template_parm.  DATA is really an int, indicating the
+   level of the parameters we are interested in.  If T is a template
+   parameter of that level, return non-zero.  */
+
+static int
+template_parm_this_level_p (t, data)
+     tree t;
+     void *data;
+{
+  int this_level = (int)data;
+  int level;
+
+  if (TREE_CODE (t) == TEMPLATE_PARM_INDEX)
+    level = TEMPLATE_PARM_LEVEL (t);
+  else
+    level = TEMPLATE_TYPE_LEVEL (t);
+  return level == this_level;
+}
+
 /* Creates a TEMPLATE_DECL for the indicated DECL using the template
    parameters given by current_template_args, or reuses a
    previously existing one, if appropriate.  Returns the DECL, or an
@@ -2718,7 +2740,20 @@ push_template_decl_real (decl, is_friend)
     tmpl = pushdecl_namespace_level (tmpl);
 
   if (primary)
-    DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
+    {
+      DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
+      if (DECL_CONV_FN_P (tmpl))
+       {
+         /* It is a conversion operator. See if the type converted to
+            depends on innermost template operands.  */
+         
+         if (for_each_template_parm
+             (TREE_TYPE (TREE_TYPE (tmpl)),
+              template_parm_this_level_p,
+              (void *)TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))))
+           DECL_TEMPLATE_CONV_FN_P (tmpl) = 1;
+       }
+    }
 
   info = tree_cons (tmpl, args, NULL_TREE);
 
index 018dfaaec575759ba47c130fcbbcf2efeef07531..adcb07642f37de71ecbf363b7963a8b1ad9a603c 100644 (file)
@@ -1522,8 +1522,9 @@ int
 lookup_fnfields_1 (type, name)
      tree type, name;
 {
-  tree method_vec 
-    = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
+  tree method_vec = (CLASS_TYPE_P (type)
+                    ? CLASSTYPE_METHOD_VEC (type)
+                    : NULL_TREE);
 
   if (method_vec != 0)
     {
@@ -1586,22 +1587,19 @@ lookup_fnfields_1 (type, name)
        }
 
       /* If we didn't find it, it might have been a template
-        conversion operator.  (Note that we don't look for this case
-        above so that we will always find specializations first.)  */
+        conversion operator to a templated type.  If there are any,
+        such template conversion operators will all be overloaded on
+        the first conversion slot.  (Note that we don't look for this
+        case above so that we will always find specializations
+        first.)  */
       if (IDENTIFIER_TYPENAME_P (name)) 
        {
-         for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; 
-              i < len && methods[i]; 
-              ++i)
+         i = CLASSTYPE_FIRST_CONVERSION_SLOT;
+         if (i < len && methods[i])
            {
              tmp = OVL_CURRENT (methods[i]);
-             if (! DECL_CONV_FN_P (tmp))
-               {
-                 /* Since all conversion operators come first, we know
-                    there is no such operator.  */
-                 break;
-               }
-             else if (TREE_CODE (tmp) == TEMPLATE_DECL)
+             if (TREE_CODE (tmp) == TEMPLATE_DECL
+                 && DECL_TEMPLATE_CONV_FN_P (tmp))
                return i;
            }
        }
index a8a424a7b59a2a5ff0378b5f2a013da386f8f8b4..f0c9255e9784fdb710b4490ad74f667dc7ed7a77 100644 (file)
@@ -2095,7 +2095,7 @@ build_component_ref (datum, component, basetype_path, protect)
                 now.  Otherwise, we have to wait and see what context it is
                 used in; a component_ref involving a non-static member
                 function can only be used in a call (expr.ref).  */
-
+             
              if (TREE_CHAIN (fndecls) == NULL_TREE
                  && TREE_CODE (TREE_VALUE (fndecls)) == FUNCTION_DECL)
                {
@@ -2119,7 +2119,16 @@ build_component_ref (datum, component, basetype_path, protect)
 
              fndecls = TREE_VALUE (fndecls);
              
-             if (TREE_CODE (component) == TEMPLATE_ID_EXPR)
+             if (IDENTIFIER_TYPENAME_P (name))
+               {
+                 /* We want for a conversion op. We need to remember
+                    the actual type we wanted, in case we got a set of
+                    templated conversion operators back.  */
+                 fndecls = ovl_cons (OVL_CURRENT (fndecls),
+                                     OVL_NEXT (fndecls));
+                 TREE_TYPE (fndecls) = TREE_TYPE (name);
+               }
+             else if (TREE_CODE (component) == TEMPLATE_ID_EXPR)
                fndecls = build_nt (TEMPLATE_ID_EXPR,
                                    fndecls, TREE_OPERAND (component, 1));
              
@@ -2684,7 +2693,12 @@ build_x_function_call (function, params, decl)
       decl = TREE_OPERAND (function, 0);
       function = TREE_OPERAND (function, 1);
 
-      if (TREE_CODE (function) == TEMPLATE_ID_EXPR)
+      if (TREE_CODE (function) == OVERLOAD
+         && TREE_TYPE (function) != unknown_type_node)
+       /* It was a conversion operator. We can't use DECL_NAME, as
+          that might refer to a templated function.  */
+       function = mangle_conv_op_name_for_type (TREE_TYPE (function));
+      else if (TREE_CODE (function) == TEMPLATE_ID_EXPR)
        {
          my_friendly_assert (!template_id, 20011228);
 
index 60d858e45882682de9ef79d039584351bba61f98..13772f100970893fdef8b74437b2055d90673349 100644 (file)
@@ -1,3 +1,10 @@
+2002-03-16  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * g++.dg/template/conv1.C: New test.
+       * g++.dg/template/conv2.C: New test.
+       * g++.dg/template/conv3.C: New test.
+       * g++.dg/template/conv4.C: New test.
+
 2002-03-15  Mark Mitchell  <mark@codesourcery.com>
 
        * g++.dg/template/qualttp20.C: Remove unnecessary error tags.
diff --git a/gcc/testsuite/g++.dg/template/conv1.C b/gcc/testsuite/g++.dg/template/conv1.C
new file mode 100644 (file)
index 0000000..e0c7492
--- /dev/null
@@ -0,0 +1,28 @@
+// { dg-do compile }
+
+// Copyright (C) 2001 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 29 Dec 2001 <nathan@codesourcery.com>
+
+// PR 4361. Template conversion operators were not overloaded.
+
+template <class T> struct Second;
+
+template<class T> struct First
+{
+  int Foo ();
+  
+  template <class U> operator Second<U>();
+  template <class U> operator First<U>();
+};
+
+template <class T> int First<T>::Foo ()
+{} // This is here to make sure we didn't smash Foo's decl in the
+   // method vector
+
+struct B { };
+struct D { };
+
+void Foo ()
+{
+  First<B> (First<D>::*pf)() = &First<D>::operator First<B>;
+}
diff --git a/gcc/testsuite/g++.dg/template/conv2.C b/gcc/testsuite/g++.dg/template/conv2.C
new file mode 100644 (file)
index 0000000..a0d08df
--- /dev/null
@@ -0,0 +1,39 @@
+// { dg-do run }
+
+// Copyright (C) 2001 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 29 Dec 2001 <nathan@codesourcery.com>
+
+// PR 4361. Template conversion operators were not overloaded.
+
+class C
+{
+public:
+
+  operator float () {return 2;}
+  
+  operator int () 
+  {
+    return 0;
+  }
+  
+  template<typename T>
+  operator int ()
+  { return 1;
+  }
+};
+
+int main ()
+{
+  C p;
+  int r;
+
+  r = p.operator int ();
+  if (r)
+    return r;
+  r = static_cast <int> (p);
+
+  if (r)
+    return r + 2;
+  
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/template/conv3.C b/gcc/testsuite/g++.dg/template/conv3.C
new file mode 100644 (file)
index 0000000..a6b0f63
--- /dev/null
@@ -0,0 +1,43 @@
+// { dg-do run }
+
+// Copyright (C) 2001 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 29 Dec 2001 <nathan@codesourcery.com>
+
+// PR 4361. Template conversion operators were not overloaded.
+
+template <typename T> struct C
+{
+  operator T () 
+  {
+    return 0;
+  }
+  template <typename T2> operator T2 ()
+  {
+    return 1;
+  }
+  int Foo ()
+  {
+    return operator T ();
+  }
+  template <typename T2> int Baz ()
+  {
+    return static_cast <int> (operator T2 ());
+  }
+};
+
+int main ()
+{
+  int r;
+  C<int> c;
+
+  r = c.Foo ();
+  if (r)
+    return 1;
+  r = c.Baz<int> ();
+  if (r)
+    return 2;
+  r = c.Baz<float> ();
+  if (!r)
+    return 3;
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/template/conv4.C b/gcc/testsuite/g++.dg/template/conv4.C
new file mode 100644 (file)
index 0000000..4db3dca
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do compile }
+
+// Copyright (C) 2001 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 29 Dec 2001 <nathan@codesourcery.com>
+
+// PR 4361. Template conversion operators were not overloaded.
+
+struct C
+{
+  template <typename T2> operator T2 ()
+  {
+    return 1;
+  }
+  int Foo ()
+  {
+    return operator int ();
+  }
+};
+
+struct D
+{
+  int Foo ()
+  {
+    return operator int (); // { dg-error "no matching function" "" }
+  }
+};
+