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:
Nathan Sidwell 2002-03-16 18:30:16 +00:00 committed by Nathan Sidwell
parent 28eca9e87b
commit 5dd236e238
13 changed files with 343 additions and 91 deletions

View 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.

View 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;
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))

View 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),

View 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))

View 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))

View 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);

View 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;
}
}

View 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);

View 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.

View File

@ -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>;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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" "" }
}
};