aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2002-03-16 18:30:16 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2002-03-16 18:30:16 +0000
commit5dd236e238bbea08ee2134d00306e03befd7e25b (patch)
treefe6bb32d28da75dc1021968451c83d5aba03ffe7
parent28eca9e87b9e4b0f6f30fda48d2b550299b1cc4b (diff)
downloadgcc-5dd236e238bbea08ee2134d00306e03befd7e25b.zip
gcc-5dd236e238bbea08ee2134d00306e03befd7e25b.tar.gz
gcc-5dd236e238bbea08ee2134d00306e03befd7e25b.tar.bz2
re PR c++/4361 (bogus ambiguity taking the address of a member template)
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
-rw-r--r--gcc/cp/ChangeLog27
-rw-r--r--gcc/cp/call.c84
-rw-r--r--gcc/cp/class.c71
-rw-r--r--gcc/cp/cp-tree.h20
-rw-r--r--gcc/cp/lex.c3
-rw-r--r--gcc/cp/pt.c39
-rw-r--r--gcc/cp/search.c26
-rw-r--r--gcc/cp/typeck.c20
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/g++.dg/template/conv1.C28
-rw-r--r--gcc/testsuite/g++.dg/template/conv2.C39
-rw-r--r--gcc/testsuite/g++.dg/template/conv3.C43
-rw-r--r--gcc/testsuite/g++.dg/template/conv4.C27
13 files changed, 343 insertions, 91 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 660e202..b5d947a 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 6f67e3d..357c068 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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))
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 9e3c110..ae8b34e 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -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),
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 68a141c..fac6a9d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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))
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 5990df9..7290a36 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -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))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 152ac0e..7e82b44 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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);
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 018dfaa..adcb076 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -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;
}
}
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index a8a424a..f0c9255 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 60d858e..13772f1 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..e0c7492
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/conv1.C
@@ -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
index 0000000..a0d08df
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/conv2.C
@@ -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
index 0000000..a6b0f63
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/conv3.C
@@ -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
index 0000000..4db3dca
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/conv4.C
@@ -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" "" }
+ }
+};
+