+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'
tree fn;
i = fn_type_unification (tmpl, explicit_targs, targs, arglist,
- return_type, strict, NULL_TREE);
+ return_type, strict);
if (i != 0)
return candidates;
else
{
int len;
+ int slot;
tree method_vec;
if (!CLASSTYPE_METHOD_VEC (type))
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);
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
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? */
for (fns = overload; fns; fns = OVL_CHAIN (fns))
{
tree fn = OVL_FUNCTION (fns);
- tree fn_arg_types;
tree instantiation;
tree instantiation_type;
tree targs;
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;
#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
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));
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));
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;
}
}
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);
|| (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;
/* 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,
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;
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;
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)
{
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);
}
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:
/* 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);
/* 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))
{
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;
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);
/* Register this specialization so that we can find it
again. */
decl = register_specialization (decl, gen_tmpl, targs);
-
- return decl;
}
}
[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;
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);
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
{
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.
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;
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));
/* 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;
{
\f
/* 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)
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)
--- /dev/null
+// Build don't link:
+
+struct S {
+ S(int);
+ S(int); // ERROR - already declared
+
+ ~S();
+ ~S(); // ERROR - already declared
+};
void bar()
{
- &foo<double>;
+ (void (*)(double)) &foo<double>;
}
void bar()
{
- (void (*)(int)) &foo<double>;
+ (void (*)(int)) (void (*)(double)) &foo<double>;
}
int main()
{
- &foo<int>;
+ (int (*)(int)) &foo<int>;
}
int main()
{
- &foo<int>;
+ (void (*)(int)) &foo<int>;
}
int main()
{
- return (*&foo<int>)(3);
+ return (*((int (*)(int)) &foo<int>))(3);
}
void bar()
{
double d;
- (*((void (*)(int, double*)) &foo<int>))(3, &d);
+ (*((void (*)(int, double*)) (void (*)(int, int*)) &foo<int>))(3, &d);
}
--- /dev/null
+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;
+}
--- /dev/null
+#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;
+}