From 0301787454dd52a66d62d421f8a4015ab62686ae Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Sun, 21 Feb 1999 16:38:23 +0000 Subject: [PATCH] cp-tree.h (CLASSTYPE_METHOD_VEC): Adjust comment. 1999-02-19 Mark Mitchell * 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 --- gcc/cp/ChangeLog | 27 ++ gcc/cp/call.c | 2 +- gcc/cp/class.c | 200 +++++++-------- gcc/cp/cp-tree.h | 11 +- gcc/cp/decl.c | 5 +- gcc/cp/decl2.c | 40 ++- gcc/cp/pt.c | 332 ++++++++++++++++--------- gcc/cp/search.c | 3 +- gcc/cp/typeck.c | 38 +-- gcc/testsuite/g++.old-deja/g++.other/redecl2.C | 9 + gcc/testsuite/g++.old-deja/g++.pt/explicit1.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/explicit2.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/explicit26.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/explicit27.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/explicit28.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/explicit30.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/spec29.C | 31 +++ gcc/testsuite/g++.old-deja/g++.pt/spec30.C | 41 +++ 18 files changed, 451 insertions(+), 300 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.other/redecl2.C create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/spec29.C create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/spec30.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 38b713d..3a8d0db 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,30 @@ +1999-02-19 Mark Mitchell + + * 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 * cp-tree.h (lvalue_or_else): Qualify a char* with the `const' diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 83e1d69..1e43233 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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; diff --git a/gcc/cp/class.c b/gcc/cp/class.c index afcc89a..d2eaa97 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d91149c..861f395 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c5ffd2b..95bd6f9 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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; } } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 2608343..70120de 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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 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; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 49d948c..905bdf6 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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 X { void f(); } - template <> void X::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 struct S { void f(); }; + template <> void S::f() {} + + Here, S::f is a non-template, but S 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; diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 1edfdf8..33842c6 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -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; { diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 58c19a4..83d13f1 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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) diff --git a/gcc/testsuite/g++.old-deja/g++.other/redecl2.C b/gcc/testsuite/g++.old-deja/g++.other/redecl2.C new file mode 100644 index 0000000..7dcdeb4 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/redecl2.C @@ -0,0 +1,9 @@ +// Build don't link: + +struct S { + S(int); + S(int); // ERROR - already declared + + ~S(); + ~S(); // ERROR - already declared +}; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit1.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit1.C index 0daf54f..d218474 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/explicit1.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit1.C @@ -5,5 +5,5 @@ void foo(T t) {} void bar() { - &foo; + (void (*)(double)) &foo; } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit2.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit2.C index 4d88c39..7388031 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/explicit2.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit2.C @@ -5,5 +5,5 @@ void foo(T t) {} void bar() { - (void (*)(int)) &foo; + (void (*)(int)) (void (*)(double)) &foo; } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit26.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit26.C index eba8d79..7d16162 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/explicit26.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit26.C @@ -8,5 +8,5 @@ int foo(int i) { return 0; } int main() { - &foo; + (int (*)(int)) &foo; } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit27.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit27.C index 4a5adb5..a8d8221 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/explicit27.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit27.C @@ -8,5 +8,5 @@ void foo(int i) {} int main() { - &foo; + (void (*)(int)) &foo; } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit28.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit28.C index b842b89..0133f16 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/explicit28.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit28.C @@ -8,5 +8,5 @@ int foo(int i) { return 0; } int main() { - return (*&foo)(3); + return (*((int (*)(int)) &foo))(3); } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit30.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit30.C index 5a69713..468dd79 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/explicit30.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit30.C @@ -7,5 +7,5 @@ void foo(T, T*); void bar() { double d; - (*((void (*)(int, double*)) &foo))(3, &d); + (*((void (*)(int, double*)) (void (*)(int, int*)) &foo))(3, &d); } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec29.C b/gcc/testsuite/g++.old-deja/g++.pt/spec29.C new file mode 100644 index 0000000..9f27a8e --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/spec29.C @@ -0,0 +1,31 @@ +char c; + +struct S { + template + operator T*(); + + template + 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; +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec30.C b/gcc/testsuite/g++.old-deja/g++.pt/spec30.C new file mode 100644 index 0000000..5d36e25 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/spec30.C @@ -0,0 +1,41 @@ +#include + +template +struct S { + void *operator new (size_t); + void *operator new (size_t, int); + void operator delete (void*); +}; + +static void* s[2]; + +template <> +void* S::operator new (size_t b) +{ + s[0] = ::operator new(b); + return s[0]; +} + +template <> +void* S::operator new (size_t b, int) +{ + s[1] = ::operator new(b); + return s[1]; +} + +template <> +void S::operator delete (void*) +{ +} + +int main() +{ + S* s1 = new S; + S* s2 = new(3) S; + + if (s1 != s[0] || s2 != s[1]) + return 1; + + delete s1; + delete s2; +} -- 2.7.4