diff options
author | Nathan Sidwell <nathan@codesourcery.com> | 2002-03-16 18:30:16 +0000 |
---|---|---|
committer | Nathan Sidwell <nathan@gcc.gnu.org> | 2002-03-16 18:30:16 +0000 |
commit | 5dd236e238bbea08ee2134d00306e03befd7e25b (patch) | |
tree | fe6bb32d28da75dc1021968451c83d5aba03ffe7 | |
parent | 28eca9e87b9e4b0f6f30fda48d2b550299b1cc4b (diff) | |
download | gcc-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/ChangeLog | 27 | ||||
-rw-r--r-- | gcc/cp/call.c | 84 | ||||
-rw-r--r-- | gcc/cp/class.c | 71 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 20 | ||||
-rw-r--r-- | gcc/cp/lex.c | 3 | ||||
-rw-r--r-- | gcc/cp/pt.c | 39 | ||||
-rw-r--r-- | gcc/cp/search.c | 26 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 20 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/conv1.C | 28 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/conv2.C | 39 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/conv3.C | 43 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/conv4.C | 27 |
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" "" } + } +}; + |