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
This commit is contained in:
parent
28eca9e87b
commit
5dd236e238
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
So we pass fromtype as CTYPE to add_*_candidate. */
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
/* [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 (candidates != old_candidates)
|
||||
{
|
||||
tree ics = implicit_conversion
|
||||
(totype, TREE_TYPE (TREE_TYPE (candidates->fn)),
|
||||
0, convflags);
|
||||
|
||||
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 (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))
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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))
|
||||
|
|
39
gcc/cp/pt.c
39
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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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" "" }
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue