cp-tree.h (CLASSTYPE_METHOD_VEC): Adjust comment.

1999-02-19  Mark Mitchell  <mark@markmitchell.com>
	* cp-tree.h (CLASSTYPE_METHOD_VEC): Adjust comment.
	(fn_type_unification): Adjust prototype.
	(lookup_fnfields_1): Declare.
	* call.c (add_template_candidate_real): Adjust call to
	fn_type_unification.
	* class.c (add_method): Don't allow duplicate declarations of
	constructors or destructors.
	(resolve_address_of_overloaded_function): Remove unused variable.
	Adjust call to fn_type_unification.
	* decl.c (grokfndecl): Be more robust in the face of illegal
	specializations.
	* decl2.c (check_classfn): Remove hokey handling of member
	templates.
	* pt.c (determine_specialization): Improve comments.  Adjust to
	handle template argument deduction as per the standard.
	(check_explicit_specialization): Fix comment spacing.  Handle
	type-conversion operators correctly.  Improve error-recovery.
	(fn_type_unification): Remove EXTRA_FN_ARG parameter.
	(get_bindings_real): Simplify handling of static members.
	* search.c (lookup_fnfields_1): Make it have external linkage.
	* typeck.c (compparms): Fix comment.
	(build_unary_op): Don't try to figure out which template
	specialization is being referred to when when the address-of
	operator is used with a template function.

From-SVN: r25347
This commit is contained in:
Mark Mitchell 1999-02-21 16:38:23 +00:00 committed by Mark Mitchell
parent 939d7216dc
commit 0301787454
18 changed files with 451 additions and 300 deletions

View File

@ -1,3 +1,30 @@
1999-02-19 Mark Mitchell <mark@markmitchell.com>
* cp-tree.h (CLASSTYPE_METHOD_VEC): Adjust comment.
(fn_type_unification): Adjust prototype.
(lookup_fnfields_1): Declare.
* call.c (add_template_candidate_real): Adjust call to
fn_type_unification.
* class.c (add_method): Don't allow duplicate declarations of
constructors or destructors.
(resolve_address_of_overloaded_function): Remove unused variable.
Adjust call to fn_type_unification.
* decl.c (grokfndecl): Be more robust in the face of illegal
specializations.
* decl2.c (check_classfn): Remove hokey handling of member
templates.
* pt.c (determine_specialization): Improve comments. Adjust to
handle template argument deduction as per the standard.
(check_explicit_specialization): Fix comment spacing. Handle
type-conversion operators correctly. Improve error-recovery.
(fn_type_unification): Remove EXTRA_FN_ARG parameter.
(get_bindings_real): Simplify handling of static members.
* search.c (lookup_fnfields_1): Make it have external linkage.
* typeck.c (compparms): Fix comment.
(build_unary_op): Don't try to figure out which template
specialization is being referred to when when the address-of
operator is used with a template function.
Thu Feb 18 23:40:01 1999 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* cp-tree.h (lvalue_or_else): Qualify a char* with the `const'

View File

@ -1948,7 +1948,7 @@ add_template_candidate_real (candidates, tmpl, explicit_targs,
tree fn;
i = fn_type_unification (tmpl, explicit_targs, targs, arglist,
return_type, strict, NULL_TREE);
return_type, strict);
if (i != 0)
return candidates;

View File

@ -1136,6 +1136,7 @@ add_method (type, fields, method)
else
{
int len;
int slot;
tree method_vec;
if (!CLASSTYPE_METHOD_VEC (type))
@ -1157,27 +1158,20 @@ add_method (type, fields, method)
len = TREE_VEC_LENGTH (method_vec);
if (DECL_NAME (method) == constructor_name (type))
{
/* A new constructor or destructor. Constructors go in
slot 0; destructors go in slot 1. */
int slot
= DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method)) ? 1 : 0;
TREE_VEC_ELT (method_vec, slot)
= build_overload (method, TREE_VEC_ELT (method_vec, slot));
}
/* A new constructor or destructor. Constructors go in
slot 0; destructors go in slot 1. */
slot = DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method)) ? 1 : 0;
else
{
int i;
/* See if we already have an entry with this name. */
for (i = 2; i < len; ++i)
if (!TREE_VEC_ELT (method_vec, i)
|| (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, i)))
for (slot = 2; slot < len; ++slot)
if (!TREE_VEC_ELT (method_vec, slot)
|| (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec,
slot)))
== DECL_NAME (method)))
break;
if (i == len)
if (slot == len)
{
/* We need a bigger method vector. */
tree new_vec = make_method_vec (2 * len);
@ -1188,76 +1182,8 @@ add_method (type, fields, method)
len = 2 * len;
method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec;
}
else if (template_class_depth (type))
/* TYPE is a template class. Don't issue any errors now;
wait until instantiation time to complain. */
;
else
{
tree fns;
/* Check to see if we've already got this method. */
for (fns = TREE_VEC_ELT (method_vec, i);
fns;
fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
if (TREE_CODE (fn) != TREE_CODE (method))
continue;
if (TREE_CODE (method) != TEMPLATE_DECL)
{
/* [over.load] Member function declarations with the
same name and the same parameter types cannot be
overloaded if any of them is a static member
function declaration. */
if (DECL_STATIC_FUNCTION_P (fn)
!= DECL_STATIC_FUNCTION_P (method))
{
tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn));
tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (method));
if (! DECL_STATIC_FUNCTION_P (fn))
parms1 = TREE_CHAIN (parms1);
else
parms2 = TREE_CHAIN (parms2);
if (compparms (parms1, parms2))
cp_error ("`%#D' and `%#D' cannot be overloaded",
fn, method);
}
/* Since this is an ordinary function in a
non-template class, it's mangled name can be
used as a unique identifier. This technique
is only an optimization; we would get the
same results if we just used decls_match
here. */
if (DECL_ASSEMBLER_NAME (fn)
!= DECL_ASSEMBLER_NAME (method))
continue;
}
else if (!decls_match (fn, method))
continue;
/* There has already been a declaration of this
method or member template. */
cp_error_at ("`%D' has already been declared in `%T'",
method, type);
/* We don't call duplicate_decls here to merege the
declarations because that will confuse things if
the methods have inline definitions In
particular, we will crash while processing the
definitions. */
return;
}
}
if (TREE_VEC_ELT (method_vec, i))
/* We found a match. */;
else if (DECL_CONV_FN_P (method))
if (DECL_CONV_FN_P (method) && !TREE_VEC_ELT (method_vec, slot))
{
/* Type conversion operators have to come before
ordinary methods; add_conversions depends on this to
@ -1265,42 +1191,107 @@ add_method (type, fields, method)
necessary, we 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 (i = 2; i < len; ++i)
for (slot = 2; slot < len; ++slot)
{
tree fn = TREE_VEC_ELT (method_vec, i);
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 (! DECL_CONV_FN_P (OVL_CURRENT (fn)))
/* We can insert the new function right at the Ith
position. */
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, i))
if (!TREE_VEC_ELT (method_vec, slot))
/* There is nothing in the Ith slot, so we can avoid
moving anything. */
;
else
{
/* We know the last slot in the vector is empty
because we know that at this point there's room for
a new function. */
bcopy ((PTR) &TREE_VEC_ELT (method_vec, i),
(PTR) &TREE_VEC_ELT (method_vec, i + 1),
(len - i - 1) * sizeof (tree));
TREE_VEC_ELT (method_vec, i) = NULL_TREE;
because we know that at this point there's room
for a new function. */
bcopy ((PTR) &TREE_VEC_ELT (method_vec, slot),
(PTR) &TREE_VEC_ELT (method_vec, slot + 1),
(len - slot - 1) * sizeof (tree));
TREE_VEC_ELT (method_vec, slot) = NULL_TREE;
}
}
/* Actually insert the new method. */
TREE_VEC_ELT (method_vec, i)
= build_overload (method, TREE_VEC_ELT (method_vec, i));
}
if (template_class_depth (type))
/* TYPE is a template class. Don't issue any errors now; wait
until instantiation time to complain. */
;
else
{
tree fns;
/* Check to see if we've already got this method. */
for (fns = TREE_VEC_ELT (method_vec, slot);
fns;
fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
if (TREE_CODE (fn) != TREE_CODE (method))
continue;
if (TREE_CODE (method) != TEMPLATE_DECL)
{
/* [over.load] Member function declarations with the
same name and the same parameter types cannot be
overloaded if any of them is a static member
function declaration. */
if (DECL_STATIC_FUNCTION_P (fn)
!= DECL_STATIC_FUNCTION_P (method))
{
tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn));
tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (method));
if (! DECL_STATIC_FUNCTION_P (fn))
parms1 = TREE_CHAIN (parms1);
else
parms2 = TREE_CHAIN (parms2);
if (compparms (parms1, parms2))
cp_error ("`%#D' and `%#D' cannot be overloaded",
fn, method);
}
/* Since this is an ordinary function in a
non-template class, it's mangled name can be used
as a unique identifier. This technique is only
an optimization; we would get the same results if
we just used decls_match here. */
if (DECL_ASSEMBLER_NAME (fn)
!= DECL_ASSEMBLER_NAME (method))
continue;
}
else if (!decls_match (fn, method))
continue;
/* There has already been a declaration of this method
or member template. */
cp_error_at ("`%D' has already been declared in `%T'",
method, type);
/* We don't call duplicate_decls here to merge the
declarations because that will confuse things if the
methods have inline definitions In particular, we
will crash while processing the definitions. */
return;
}
}
/* Actually insert the new method. */
TREE_VEC_ELT (method_vec, slot)
= build_overload (method, TREE_VEC_ELT (method_vec, slot));
if (TYPE_BINFO_BASETYPES (type) && CLASSTYPE_BASELINK_VEC (type))
{
/* ??? May be better to know whether these can be extended? */
@ -5115,7 +5106,6 @@ resolve_address_of_overloaded_function (target_type,
for (fns = overload; fns; fns = OVL_CHAIN (fns))
{
tree fn = OVL_FUNCTION (fns);
tree fn_arg_types;
tree instantiation;
tree instantiation_type;
tree targs;
@ -5134,7 +5124,7 @@ resolve_address_of_overloaded_function (target_type,
targs = make_scratch_vec (DECL_NTPARMS (fn));
if (fn_type_unification (fn, explicit_targs, targs,
target_arg_types, NULL_TREE,
DEDUCE_EXACT, NULL_TREE) != 0)
DEDUCE_EXACT) != 0)
/* Argument deduction failed. */
continue;

View File

@ -887,11 +887,11 @@ struct lang_type
#define TYPE_USES_VIRTUAL_BASECLASSES(NODE) (TREE_LANG_FLAG_3(NODE))
/* Vector member functions defined in this class. Each element is
either a FUNCTION_DECL, a TEMPLATE_DECL, or an OVERLOAD. The first
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 user-defined conversion operators follow these. These are
followed by ordinary member functions. There may be empty entries
at the end of the vector. */
These are followed by ordinary member functions. There may be
empty entries at the end of the vector. */
#define CLASSTYPE_METHOD_VEC(NODE) (TYPE_LANG_SPECIFIC(NODE)->methods)
/* The first type conversion operator in the class (the others can be
@ -3068,7 +3068,7 @@ extern int uses_template_parms PROTO((tree));
extern tree instantiate_class_template PROTO((tree));
extern tree instantiate_template PROTO((tree, tree));
extern void overload_template_name PROTO((tree));
extern int fn_type_unification PROTO((tree, tree, tree, tree, tree, unification_kind_t, tree));
extern int fn_type_unification PROTO((tree, tree, tree, tree, tree, unification_kind_t));
struct tinst_level *tinst_for_decl PROTO((void));
extern void mark_decl_instantiated PROTO((tree, int));
extern int more_specialized PROTO((tree, tree, tree));
@ -3126,6 +3126,7 @@ extern int get_base_distance PROTO((tree, tree, int, tree *));
extern tree compute_access PROTO((tree, tree));
extern tree lookup_field PROTO((tree, tree, int, int));
extern tree lookup_nested_field PROTO((tree, int));
extern int lookup_fnfields_1 PROTO((tree, tree));
extern tree lookup_fnfields PROTO((tree, tree, int));
extern tree lookup_member PROTO((tree, tree, int, int));
extern tree lookup_nested_tag PROTO((tree, tree));

View File

@ -8599,8 +8599,11 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
cp_error ("definition of implicitly-declared `%D'", tmp);
if (tmp)
{
/* Attempt to merge the declarations. This can fail, in
the case of some illegal specialization declarations. */
if (!duplicate_decls (decl, tmp))
my_friendly_abort (892);
cp_error ("no `%#D' member function declared in class `%T'",
decl, ctype);
return tmp;
}
}

View File

@ -1309,8 +1309,21 @@ check_classfn (ctype, function)
tree method_vec = CLASSTYPE_METHOD_VEC (complete_type (ctype));
tree *methods = 0;
tree *end = 0;
tree templates = NULL_TREE;
if (DECL_USE_TEMPLATE (function)
&& is_member_template (DECL_TI_TEMPLATE (function)))
/* Since this is a specialization of a member template,
we're not going to find the declaration in the class.
For example, in:
struct S { template <typename T> void f(T); };
template <> void S::f(int);
we're not going to find `S::f(int)', but there's no
reason we should, either. We let our callers know we didn't
find the method, but we don't complain. */
return NULL_TREE;
if (method_vec != 0)
{
methods = &TREE_VEC_ELT (method_vec, 0);
@ -1375,36 +1388,13 @@ check_classfn (ctype, function)
|| (DECL_TI_TEMPLATE (function)
== DECL_TI_TEMPLATE (fndecl))))
return fndecl;
if (is_member_template (fndecl))
/* This function might be an instantiation
or specialization of fndecl. */
templates =
scratch_tree_cons (NULL_TREE, fndecl, templates);
}
}
break; /* loser */
}
else if (TREE_CODE (OVL_CURRENT (fndecl)) == TEMPLATE_DECL
&& DECL_CONV_FN_P (OVL_CURRENT (fndecl))
&& DECL_CONV_FN_P (function))
/* The method in the class is a member template
conversion operator. We are declaring another
conversion operator. It is possible that even though
the names don't match, there is some specialization
occurring. */
templates =
scratch_tree_cons (NULL_TREE, fndecl, templates);
}
}
if (templates)
/* This function might be an instantiation or a specialization.
We should verify that this is possible. For now, we simply
return NULL_TREE, which lets the caller know that this function
is new, but we don't print an error message. */
return NULL_TREE;
if (methods != end && *methods)
{
tree fndecl = *methods;

View File

@ -906,13 +906,19 @@ print_candidates (fns)
/* Returns the template (one of the functions given by TEMPLATE_ID)
which can be specialized to match the indicated DECL with the
explicit template args given in TEMPLATE_ID. If
NEED_MEMBER_TEMPLATE is true the function is a specialization of a
member template. The template args (those explicitly specified and
those deduced) are output in a newly created vector *TARGS_OUT. If
it is impossible to determine the result, an error message is
issued, unless COMPLAIN is 0. The DECL may be NULL_TREE if none is
available. */
explicit template args given in TEMPLATE_ID. The DECL may be
NULL_TREE if none is available. In that case, the functions in
TEMPLATE_ID are non-members.
If NEED_MEMBER_TEMPLATE is non-zero the function is known to be a
specialization of a member template.
The template args (those explicitly specified and those deduced)
are output in a newly created vector *TARGS_OUT.
If it is impossible to determine the result, an error message is
issued, unless COMPLAIN is 0. In any case, error_mark_node is
returned to indicate failure. */
tree
determine_specialization (template_id, decl, targs_out,
@ -924,9 +930,12 @@ determine_specialization (template_id, decl, targs_out,
int need_member_template;
int complain;
{
tree fns, targs_in;
tree templates = NULL_TREE;
tree fn;
tree fns;
tree targs;
tree explicit_targs;
tree candidates = NULL_TREE;
tree templates = NULL_TREE;
*targs_out = NULL_TREE;
@ -934,7 +943,7 @@ determine_specialization (template_id, decl, targs_out,
return error_mark_node;
fns = TREE_OPERAND (template_id, 0);
targs_in = TREE_OPERAND (template_id, 1);
explicit_targs = TREE_OPERAND (template_id, 1);
if (fns == error_mark_node)
return error_mark_node;
@ -948,25 +957,58 @@ determine_specialization (template_id, decl, targs_out,
tree tmpl;
fn = OVL_CURRENT (fns);
if (!need_member_template
&& TREE_CODE (fn) == FUNCTION_DECL
&& DECL_FUNCTION_MEMBER_P (fn)
&& DECL_USE_TEMPLATE (fn)
&& DECL_TI_TEMPLATE (fn))
/* We can get here when processing something like:
template <class T> class X { void f(); }
template <> void X<int>::f() {}
We're specializing a member function, but not a member
template. */
tmpl = DECL_TI_TEMPLATE (fn);
else if (TREE_CODE (fn) != TEMPLATE_DECL
|| (need_member_template && !is_member_template (fn)))
if (TREE_CODE (fn) == TEMPLATE_DECL)
/* DECL might be a specialization of FN. */
tmpl = fn;
else if (need_member_template)
/* FN is an ordinary member function, and we need a
specialization of a member template. */
continue;
else if (TREE_CODE (fn) != FUNCTION_DECL)
/* We can get IDENTIFIER_NODEs here in certain erroneous
cases. */
continue;
else if (!DECL_FUNCTION_MEMBER_P (fn))
/* This is just an ordinary non-member function. Nothing can
be a specialization of that. */
continue;
else if (!decl)
/* When there's no DECL to match, we know we're looking for
non-members. */
continue;
else
tmpl = fn;
{
tree decl_arg_types;
if (list_length (targs_in) > DECL_NTPARMS (tmpl))
continue;
/* This is an ordinary member function. However, since
we're here, we can assume it's enclosing class is a
template class. For example,
template <typename T> struct S { void f(); };
template <> void S<int>::f() {}
Here, S<int>::f is a non-template, but S<int> is a
template class. If FN has the same type as DECL, we
might be in business. */
if (!same_type_p (TREE_TYPE (TREE_TYPE (decl)),
TREE_TYPE (TREE_TYPE (fn))))
/* The return types differ. */
continue;
/* Adjust the type of DECL in case FN is a static member. */
decl_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
if (DECL_STATIC_FUNCTION_P (fn)
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
decl_arg_types = TREE_CHAIN (decl_arg_types);
if (compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)),
decl_arg_types))
/* They match! */
candidates = tree_cons (NULL_TREE, fn, candidates);
continue;
}
if (decl == NULL_TREE)
{
@ -974,70 +1016,107 @@ determine_specialization (template_id, decl, targs_out,
make sense and there aren't any undeducible parms. It's OK if
not all the parms are specified; they might be deduced
later. */
tree targs = get_bindings_overload (tmpl, DECL_RESULT (tmpl),
targs_in);
if (targs)
/* Unification was successful. */
templates = scratch_tree_cons (targs, tmpl, templates);
targs = get_bindings_overload (tmpl, DECL_RESULT (tmpl),
explicit_targs);
if (uses_template_parms (targs))
/* We couldn't deduce all the arguments. */
continue;
}
else
templates = scratch_tree_cons (NULL_TREE, tmpl, templates);
}
if (decl != NULL_TREE)
{
tree tmpl = most_specialized (templates, decl, targs_in);
tree inner_args;
tree tmpl_args;
/* See whether this function might be a specialization of this
template. */
targs = get_bindings (tmpl, decl, explicit_targs);
if (tmpl == error_mark_node)
goto ambiguous;
else if (tmpl == NULL_TREE)
goto no_match;
if (!targs)
/* Wwe cannot deduce template arguments that when used to
specialize TMPL will produce DECL. */
continue;
inner_args = get_bindings (tmpl, decl, targs_in);
tmpl_args = DECL_TI_ARGS (DECL_RESULT (tmpl));
if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (tmpl_args))
{
*targs_out = copy_node (tmpl_args);
SET_TMPL_ARGS_LEVEL (*targs_out,
TMPL_ARGS_DEPTH (*targs_out),
inner_args);
}
else
*targs_out = inner_args;
return tmpl;
/* Save this template, and the arguments deduced. */
templates = scratch_tree_cons (targs, tmpl, templates);
}
if (templates == NULL_TREE)
if (decl && templates && TREE_CHAIN (templates))
{
/* We have:
[temp.expl.spec]
It is possible for a specialization with a given function
signature to be instantiated from more than one function
template. In such cases, explicit specification of the
template arguments must be used to uniquely identify the
function template specialization being specialized.
Note that here, there's no suggestion that we're supposed to
determine which of the candidate templates is most
specialized. However, we, also have:
[temp.func.order]
Partial ordering of overloaded function template
declarations is used in the following contexts to select
the function template to which a function template
specialization refers:
-- when an explicit specialization refers to a function
template.
So, we do use the partial ordering rules, at least for now.
This extension can only serve to make illegal programs legal,
so it's safe. And, there is strong anecdotal evidence that
the committee intended the partial ordering rules to apply;
the EDG front-end has that behavior, and John Spicer claims
that the committee simply forgot to delete the wording in
[temp.expl.spec]. */
tree tmpl = most_specialized (templates, decl, explicit_targs);
if (tmpl && tmpl != error_mark_node)
{
targs = get_bindings (tmpl, decl, explicit_targs);
templates = scratch_tree_cons (targs, tmpl, NULL_TREE);
}
}
if (templates == NULL_TREE && candidates == NULL_TREE)
{
no_match:
if (complain)
{
cp_error_at ("template-id `%D' for `%+D' does not match any template declaration",
template_id, decl);
return error_mark_node;
}
return NULL_TREE;
cp_error_at ("template-id `%D' for `%+D' does not match any template declaration",
template_id, decl);
return error_mark_node;
}
else if (TREE_CHAIN (templates) != NULL_TREE
|| uses_template_parms (TREE_PURPOSE (templates)))
else if ((templates && TREE_CHAIN (templates))
|| (candidates && TREE_CHAIN (candidates)))
{
ambiguous:
if (complain)
{
cp_error_at ("ambiguous template specialization `%D' for `%+D'",
template_id, decl);
print_candidates (templates);
return error_mark_node;
chainon (candidates, templates);
print_candidates (candidates);
}
return NULL_TREE;
return error_mark_node;
}
/* We have one, and exactly one, match. */
*targs_out = TREE_PURPOSE (templates);
if (candidates)
{
/* It was a specialization of an ordinary member function in a
template class. */
*targs_out = copy_node (DECL_TI_ARGS (TREE_VALUE (candidates)));
return DECL_TI_TEMPLATE (TREE_VALUE (candidates));
}
/* It was a specialization of a template. */
targs = DECL_TI_ARGS (DECL_RESULT (TREE_VALUE (templates)));
if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (targs))
{
*targs_out = copy_node (targs);
SET_TMPL_ARGS_LEVEL (*targs_out,
TMPL_ARGS_DEPTH (*targs_out),
TREE_PURPOSE (templates));
}
else
*targs_out = TREE_PURPOSE (templates);
return TREE_VALUE (templates);
}
@ -1047,7 +1126,9 @@ determine_specialization (template_id, decl, targs_out,
instantiation at this point.
Returns DECL, or an equivalent declaration that should be used
instead.
instead if all goes well. Issues an error message if something is
amiss. Returns error_mark_node if the error is not easily
recoverable.
FLAGS is a bitmask consisting of the following flags:
@ -1101,10 +1182,9 @@ check_explicit_specialization (declarator, decl, template_count, flags)
/* There were more template headers than qualifying template
classes. */
if (template_header_count - template_count > 1)
/* There shouldn't be that many template parameter
lists. There can be at most one parameter list for
every qualifying class, plus one for the function
itself. */
/* There shouldn't be that many template parameter lists.
There can be at most one parameter list for every
qualifying class, plus one for the function itself. */
cp_error ("too many template parameter lists in declaration of `%D'", decl);
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
@ -1284,8 +1364,9 @@ check_explicit_specialization (declarator, decl, template_count, flags)
/* Find the list of functions in ctype that have the same
name as the declared function. */
tree name = TREE_OPERAND (declarator, 0);
tree fns;
tree fns = NULL_TREE;
int idx;
if (name == constructor_name (ctype)
|| name == constructor_name_full (ctype))
{
@ -1303,21 +1384,52 @@ check_explicit_specialization (declarator, decl, template_count, flags)
Similar language is found in [temp.explicit]. */
cp_error ("specialization of implicitly-declared special member function");
return decl;
return error_mark_node;
}
name = is_constructor ? ctor_identifier : dtor_identifier;
}
fns = lookup_fnfields (TYPE_BINFO (ctype), name, 1);
if (!IDENTIFIER_TYPENAME_P (name))
{
idx = lookup_fnfields_1 (ctype, name);
if (idx >= 0)
fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (ctype), idx);
}
else
{
tree methods;
/* For a type-conversion operator, we cannot do a
name-based lookup. We might be looking for `operator
int' which will be a specialization of `operator T'.
So, we find *all* the conversion operators, and then
select from them. */
fns = NULL_TREE;
methods = CLASSTYPE_METHOD_VEC (ctype);
if (methods)
for (idx = 2; idx < TREE_VEC_LENGTH (methods); ++idx)
{
tree ovl = TREE_VEC_ELT (methods, idx);
if (!ovl || !DECL_CONV_FN_P (OVL_CURRENT (ovl)))
/* There are no more conversion functions. */
break;
/* Glue all these conversion functions together
with those we already have. */
for (; ovl; ovl = OVL_NEXT (ovl))
fns = ovl_cons (OVL_CURRENT (ovl), fns);
}
}
if (fns == NULL_TREE)
{
cp_error ("no member function `%s' declared in `%T'",
IDENTIFIER_POINTER (name),
ctype);
return decl;
return error_mark_node;
}
else
TREE_OPERAND (declarator, 0) = fns;
@ -1336,7 +1448,11 @@ check_explicit_specialization (declarator, decl, template_count, flags)
member_specialization,
1);
if (tmpl && tmpl != error_mark_node)
if (!tmpl || tmpl == error_mark_node)
/* We couldn't figure out what this declaration was
specializing. */
return error_mark_node;
else
{
gen_tmpl = most_general_template (tmpl);
@ -1390,8 +1506,6 @@ check_explicit_specialization (declarator, decl, template_count, flags)
/* Register this specialization so that we can find it
again. */
decl = register_specialization (decl, gen_tmpl, targs);
return decl;
}
}
@ -7123,17 +7237,13 @@ overload_template_name (type)
[temp.expl.spec], or when taking the address of a function
template, as in [temp.deduct.funcaddr].
The EXTRA_FN_ARG, if any, is the type of an additional
parameter to be added to the beginning of FN's parameter list.
The other arguments are as for type_unification. */
int
fn_type_unification (fn, explicit_targs, targs, args, return_type,
strict, extra_fn_arg)
strict)
tree fn, explicit_targs, targs, args, return_type;
unification_kind_t strict;
tree extra_fn_arg;
{
tree parms;
tree fntype;
@ -7174,11 +7284,6 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type,
if (fntype == error_mark_node)
return 1;
extra_fn_arg = tsubst (extra_fn_arg, converted_args,
/*complain=*/0, NULL_TREE);
if (extra_fn_arg == error_mark_node)
return 1;
/* Place the explicitly specified arguments in TARGS. */
for (i = 0; i < TREE_VEC_LENGTH (targs); i++)
TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (converted_args, i);
@ -7195,9 +7300,6 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type,
args = scratch_tree_cons (NULL_TREE, return_type, args);
}
if (extra_fn_arg != NULL_TREE)
parms = scratch_tree_cons (NULL_TREE, extra_fn_arg, parms);
/* We allow incomplete unification without an error message here
because the standard doesn't seem to explicitly prohibit it. Our
callers must be ready to deal with unification failures in any
@ -8355,9 +8457,8 @@ get_bindings_real (fn, decl, explicit_args, check_rettype)
{
int ntparms = DECL_NTPARMS (fn);
tree targs = make_scratch_vec (ntparms);
tree decl_arg_types;
tree extra_fn_arg = NULL_TREE;
tree decl_type;
tree decl_arg_types;
int i;
/* Substitute the explicit template arguments into the type of DECL.
@ -8389,32 +8490,17 @@ get_bindings_real (fn, decl, explicit_args, check_rettype)
return NULL_TREE;
}
/* If FN is a static member function, adjust the type of DECL
appropriately. */
decl_arg_types = TYPE_ARG_TYPES (decl_type);
if (DECL_STATIC_FUNCTION_P (fn)
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
{
/* Sometimes we are trying to figure out what's being
specialized by a declaration that looks like a method, and it
turns out to be a static member function. */
if (CLASSTYPE_TEMPLATE_INFO (DECL_REAL_CONTEXT (fn))
&& !is_member_template (fn))
/* The natural thing to do here seems to be to remove the
spurious `this' parameter from the DECL, but that prevents
unification from making use of the class type. So,
instead, we have fn_type_unification add to the parameters
for FN. */
extra_fn_arg = build_pointer_type (DECL_REAL_CONTEXT (fn));
else
/* In this case, though, adding the extra_fn_arg can confuse
things, so we remove from decl_arg_types instead. */
decl_arg_types = TREE_CHAIN (decl_arg_types);
}
decl_arg_types = TREE_CHAIN (decl_arg_types);
i = fn_type_unification (fn, explicit_args, targs,
decl_arg_types, TREE_TYPE (decl_type),
DEDUCE_EXACT,
extra_fn_arg);
decl_arg_types,
TREE_TYPE (decl_type),
DEDUCE_EXACT);
if (i != 0)
return NULL_TREE;

View File

@ -81,7 +81,6 @@ static tree get_vbase_1 PROTO((tree, tree, unsigned int *));
static tree convert_pointer_to_vbase PROTO((tree, tree));
static tree lookup_field_1 PROTO((tree, tree));
static tree convert_pointer_to_single_level PROTO((tree, tree));
static int lookup_fnfields_1 PROTO((tree, tree));
static int lookup_fnfields_here PROTO((tree, tree));
static int is_subobject_of_p PROTO((tree, tree));
static int hides PROTO((tree, tree));
@ -1284,7 +1283,7 @@ lookup_nested_field (name, complain)
/* TYPE is a class type. Return the index of the fields within
the method vector with name NAME, or -1 is no such field exists. */
static int
int
lookup_fnfields_1 (type, name)
tree type, name;
{

View File

@ -1185,15 +1185,12 @@ common_base_type (tt1, tt2)
/* Subroutines of `comptypes'. */
/* Return 1 if two parameter type lists PARMS1 and PARMS2
are equivalent in the sense that functions with those parameter types
can have equivalent types.
If either list is empty, we win.
Otherwise, the two lists must be equivalent, element by element.
/* Return 1 if two parameter type lists PARMS1 and PARMS2 are
equivalent in the sense that functions with those parameter types
can have equivalent types. The two lists must be equivalent,
element by element.
C++: See comment above about TYPE1, TYPE2.
STRICT is no longer used. */
C++: See comment above about TYPE1, TYPE2. */
int
compparms (parms1, parms2)
@ -4559,30 +4556,7 @@ build_unary_op (code, xarg, noconvert)
return build1 (ADDR_EXPR, unknown_type_node, arg);
}
if (TREE_CODE (arg) == TEMPLATE_ID_EXPR)
{
tree targs;
tree fn;
/* We don't require a match here; it's possible that the
context (like a cast to a particular type) will resolve
the particular choice of template. */
fn = determine_specialization (arg,
NULL_TREE,
&targs,
0,
0);
if (fn)
{
fn = instantiate_template (fn, targs);
mark_addressable (fn);
return build_unary_op (ADDR_EXPR, fn, 0);
}
return build1 (ADDR_EXPR, unknown_type_node, arg);
}
else if (type_unknown_p (arg))
if (type_unknown_p (arg))
return build1 (ADDR_EXPR, unknown_type_node, arg);
/* Handle complex lvalues (when permitted)

View File

@ -0,0 +1,9 @@
// Build don't link:
struct S {
S(int);
S(int); // ERROR - already declared
~S();
~S(); // ERROR - already declared
};

View File

@ -5,5 +5,5 @@ void foo(T t) {}
void bar()
{
&foo<double>;
(void (*)(double)) &foo<double>;
}

View File

@ -5,5 +5,5 @@ void foo(T t) {}
void bar()
{
(void (*)(int)) &foo<double>;
(void (*)(int)) (void (*)(double)) &foo<double>;
}

View File

@ -8,5 +8,5 @@ int foo(int i) { return 0; }
int main()
{
&foo<int>;
(int (*)(int)) &foo<int>;
}

View File

@ -8,5 +8,5 @@ void foo(int i) {}
int main()
{
&foo<int>;
(void (*)(int)) &foo<int>;
}

View File

@ -8,5 +8,5 @@ int foo(int i) { return 0; }
int main()
{
return (*&foo<int>)(3);
return (*((int (*)(int)) &foo<int>))(3);
}

View File

@ -7,5 +7,5 @@ void foo(T, T*);
void bar()
{
double d;
(*((void (*)(int, double*)) &foo<int>))(3, &d);
(*((void (*)(int, double*)) (void (*)(int, int*)) &foo<int>))(3, &d);
}

View File

@ -0,0 +1,31 @@
char c;
struct S {
template <typename T>
operator T*();
template <typename T>
operator T();
};
template <>
S::operator int()
{
return 2;
}
template <>
S::operator char*()
{
return &c;
}
int main()
{
S s;
int i = s;
char* cp = s;
if (i != 2 || cp != &c)
return 1;
}

View File

@ -0,0 +1,41 @@
#include <cstddef>
template <class T>
struct S {
void *operator new (size_t);
void *operator new (size_t, int);
void operator delete (void*);
};
static void* s[2];
template <>
void* S<int>::operator new (size_t b)
{
s[0] = ::operator new(b);
return s[0];
}
template <>
void* S<int>::operator new (size_t b, int)
{
s[1] = ::operator new(b);
return s[1];
}
template <>
void S<int>::operator delete (void*)
{
}
int main()
{
S<int>* s1 = new S<int>;
S<int>* s2 = new(3) S<int>;
if (s1 != s[0] || s2 != s[1])
return 1;
delete s1;
delete s2;
}