diff options
-rw-r--r-- | gcc/cp/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/cp/call.c | 3 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 5 | ||||
-rw-r--r-- | gcc/cp/pt.c | 261 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/parse/ambig3.C | 15 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/spec20.C | 19 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/spec21.C | 28 |
8 files changed, 269 insertions, 83 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b63906c..93c7170 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +2005-03-31 Nathan Sidwell <nathan@codesourcery.com> + + PR c++/19203, implement DR 214 + * call.c (joust): Use more_specialized_fn. + * cp-tree.h (DEDUCE_ORDER): Remove. + (more_specialized): Replace with ... + (more_specialized_fn): ... this. + * pt.c (maybe_adjust_types_for_deduction): Remove DEDUCE_ORDER + case. + (type_unification_real): Remove DEDUCE_ORDER case. + (more_specialized): Replace with ... + (more_specialized_fn): ... this. Implement DR 214. + (most_specialized_instantiation): Use get_bindings_real directly. + 2005-03-31 Gabriel Dos Reis <gdr@integrable-solutions.net> PR c++/18644 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 131e175..9d76276c 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -6084,10 +6084,9 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn) if (cand1->template_decl && cand2->template_decl) { - winner = more_specialized + winner = more_specialized_fn (TI_TEMPLATE (cand1->template_decl), TI_TEMPLATE (cand2->template_decl), - DEDUCE_ORDER, /* Tell the deduction code how many real function arguments we saw, not counting the implicit 'this' argument. But, add_function_candidate() suppresses the "this" argument diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ac025d6..7f4efc3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3112,8 +3112,7 @@ extern int function_depth; typedef enum unification_kind_t { DEDUCE_CALL, DEDUCE_CONV, - DEDUCE_EXACT, - DEDUCE_ORDER + DEDUCE_EXACT } unification_kind_t; /* Macros for operating on a template instantiation level node. */ @@ -3998,7 +3997,7 @@ extern tree instantiate_class_template (tree); extern tree instantiate_template (tree, tree, tsubst_flags_t); extern int fn_type_unification (tree, tree, tree, tree, tree, unification_kind_t, int); extern void mark_decl_instantiated (tree, int); -extern int more_specialized (tree, tree, int, int); +extern int more_specialized_fn (tree, tree, int); extern void mark_class_instantiated (tree, int); extern void do_decl_instantiation (tree, tree); extern void do_type_instantiation (tree, tree, tsubst_flags_t); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d5514f3..b80faae 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -9064,11 +9064,6 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain) as in [temp.expl.spec], or when taking the address of a function template, as in [temp.deduct.funcaddr]. - DEDUCE_ORDER: - We are deducing arguments when calculating the partial - ordering between specializations of function or class - templates, as in [temp.func.order] and [temp.class.order]. - LEN is the number of parms to consider before returning success, or -1 for all. This is used in partial ordering to avoid comparing parms for which no actual argument was passed, since they are not considered in @@ -9216,28 +9211,6 @@ maybe_adjust_types_for_deduction (unification_kind_t strict, /* There is nothing to do in this case. */ return 0; - case DEDUCE_ORDER: - /* DR 214. [temp.func.order] is underspecified, and leads to no - ordering between things like `T *' and `T const &' for `U *'. - The former has T=U and the latter T=U*. The former looks more - specialized and John Spicer considers it well-formed (the EDG - compiler accepts it). - - John also confirms that deduction should proceed as in a function - call. Which implies the usual ARG and PARM conversions as DEDUCE_CALL. - However, in ordering, ARG can have REFERENCE_TYPE, but no argument - to an actual call can have such a type. - - If both ARG and PARM are REFERENCE_TYPE, we change neither. - If only ARG is a REFERENCE_TYPE, we look through that and then - proceed as with DEDUCE_CALL (which could further convert it). */ - if (TREE_CODE (*arg) == REFERENCE_TYPE) - { - if (TREE_CODE (*parm) == REFERENCE_TYPE) - return 0; - *arg = TREE_TYPE (*arg); - } - break; default: gcc_unreachable (); } @@ -9333,10 +9306,6 @@ type_unification_real (tree tparms, sub_strict = UNIFY_ALLOW_NONE; break; - case DEDUCE_ORDER: - sub_strict = UNIFY_ALLOW_NONE; - break; - default: gcc_unreachable (); } @@ -9379,7 +9348,7 @@ type_unification_real (tree tparms, else type = arg; - if (strict == DEDUCE_EXACT || strict == DEDUCE_ORDER) + if (strict == DEDUCE_EXACT) { if (same_type_p (parm, type)) continue; @@ -10426,36 +10395,158 @@ mark_decl_instantiated (tree result, int extern_p) /* Given two function templates PAT1 and PAT2, return: - DEDUCE should be DEDUCE_EXACT or DEDUCE_ORDER. - 1 if PAT1 is more specialized than PAT2 as described in [temp.func.order]. -1 if PAT2 is more specialized than PAT1. 0 if neither is more specialized. - LEN is passed through to fn_type_unification. */ + LEN indicates the number of parameters we should consider + (defaulted parameters should not be considered). + + The 1998 std underspecified function template partial ordering, and + DR214 addresses the issue. We take pairs of arguments, one from + each of the templates, and deduce them against eachother. One of + the templates will be more specialized if all the *other* + template's arguments deduce against its arguments and at least one + of its arguments *does* *not* deduce against the other template's + corresponding argument. Deduction is done as for class templates. + The arguments used in deduction have reference and top level cv + qualifiers removed. Iff both arguments were originally reference + types *and* deduction succeeds in both directions, the template + with the more cv-qualified argument wins for that pairing (if + neither is more cv-qualified, they both are equal). Unlike regular + deduction, after all the arguments have been deduced in this way, + we do *not* verify the deduced template argument values can be + substituted into non-deduced contexts, nor do we have to verify + that all template arguments have been deduced. */ int -more_specialized (tree pat1, tree pat2, int deduce, int len) -{ - tree targs; - int winner = 0; +more_specialized_fn (tree pat1, tree pat2, int len) +{ + tree decl1 = DECL_TEMPLATE_RESULT (pat1); + tree decl2 = DECL_TEMPLATE_RESULT (pat2); + tree targs1 = make_tree_vec (DECL_NTPARMS (pat1)); + tree targs2 = make_tree_vec (DECL_NTPARMS (pat2)); + tree tparms1 = DECL_INNERMOST_TEMPLATE_PARMS (pat1); + tree tparms2 = DECL_INNERMOST_TEMPLATE_PARMS (pat2); + tree args1 = TYPE_ARG_TYPES (TREE_TYPE (decl1)); + tree args2 = TYPE_ARG_TYPES (TREE_TYPE (decl2)); + int better1 = 0; + int better2 = 0; + + /* Don't consider 'this' parameter. */ + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1)) + args1 = TREE_CHAIN (args1); + + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2)) + args2 = TREE_CHAIN (args2); - /* If template argument deduction succeeds, we substitute the - resulting arguments into non-deduced contexts. While doing that, - we must be aware that we may encounter dependent types. */ - ++processing_template_decl; - targs = get_bindings_real (pat1, DECL_TEMPLATE_RESULT (pat2), - NULL_TREE, 0, deduce, len); - if (targs) - --winner; + /* Consider the return type for a conversion function */ + if (DECL_CONV_FN_P (decl1)) + { + gcc_assert (DECL_CONV_FN_P (decl2)); + args1 = tree_cons (NULL_TREE, TREE_TYPE (TREE_TYPE (decl1)), args1); + args2 = tree_cons (NULL_TREE, TREE_TYPE (TREE_TYPE (decl2)), args2); + len++; + } + + processing_template_decl++; + + while (len--) + { + tree arg1 = TREE_VALUE (args1); + tree arg2 = TREE_VALUE (args2); + int deduce1, deduce2; + int quals1 = -1; + int quals2 = -1; - targs = get_bindings_real (pat2, DECL_TEMPLATE_RESULT (pat1), - NULL_TREE, 0, deduce, len); - if (targs) - ++winner; - --processing_template_decl; + if (TREE_CODE (arg1) == REFERENCE_TYPE) + { + arg1 = TREE_TYPE (arg1); + quals1 = cp_type_quals (arg1); + } + + if (TREE_CODE (arg2) == REFERENCE_TYPE) + { + arg2 = TREE_TYPE (arg2); + quals2 = cp_type_quals (arg2); + } - return winner; + if ((quals1 < 0) != (quals2 < 0)) + { + /* Only of the args is a reference, see if we should apply + array/function pointer decay to it. This is not part of + DR214, but is, IMHO, consistent with the deduction rules + for the function call itself, and with our earlier + implementation of the underspecified partial ordering + rules. (nathan). */ + if (quals1 >= 0) + { + switch (TREE_CODE (arg1)) + { + case ARRAY_TYPE: + arg1 = TREE_TYPE (arg1); + /* FALLTHROUGH. */ + case FUNCTION_TYPE: + arg1 = build_pointer_type (arg1); + break; + + default: + break; + } + } + else + { + switch (TREE_CODE (arg2)) + { + case ARRAY_TYPE: + arg2 = TREE_TYPE (arg2); + /* FALLTHROUGH. */ + case FUNCTION_TYPE: + arg2 = build_pointer_type (arg2); + break; + + default: + break; + } + } + } + + arg1 = TYPE_MAIN_VARIANT (arg1); + arg2 = TYPE_MAIN_VARIANT (arg2); + + deduce1 = !unify (tparms1, targs1, arg1, arg2, UNIFY_ALLOW_NONE); + deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE); + + if (!deduce1) + better2 = -1; + if (!deduce2) + better1 = -1; + if (better1 < 0 && better2 < 0) + /* We've failed to deduce something in either direction. + These must be unordered. */ + break; + + if (deduce1 && deduce2 && quals1 >= 0 && quals2 >= 0) + { + /* Deduces in both directions, see if quals can + disambiguate. Pretend the worse one failed to deduce. */ + if ((quals1 & quals2) == quals2) + deduce1 = 0; + if ((quals1 & quals2) == quals1) + deduce2 = 0; + } + if (deduce1 && !deduce2 && !better2) + better2 = 1; + if (deduce2 && !deduce1 && !better1) + better1 = 1; + + args1 = TREE_CHAIN (args1); + args2 = TREE_CHAIN (args2); + } + + processing_template_decl--; + + return (better1 > 0) - (better2 > 0); } /* Given two class template specialization list nodes PAT1 and PAT2, return: @@ -10619,37 +10710,56 @@ tree most_specialized_instantiation (tree instantiations) { tree fn, champ; - int fate; if (!instantiations) return NULL_TREE; - + + ++processing_template_decl; + champ = instantiations; for (fn = TREE_CHAIN (instantiations); fn; fn = TREE_CHAIN (fn)) { - fate = more_specialized (TREE_VALUE (champ), TREE_VALUE (fn), - DEDUCE_EXACT, -1); - if (fate == 1) - ; - else + int fate = 0; + + if (get_bindings_real (TREE_VALUE (champ), + DECL_TEMPLATE_RESULT (TREE_VALUE (fn)), + NULL_TREE, 0, DEDUCE_EXACT, -1)) + fate--; + + if (get_bindings_real (TREE_VALUE (fn), + DECL_TEMPLATE_RESULT (TREE_VALUE (champ)), + NULL_TREE, 0, DEDUCE_EXACT, -1)) + fate++; + + if (fate != 1) { - if (fate == 0) - { - fn = TREE_CHAIN (fn); - if (! fn) - return error_mark_node; - } + if (!fate) + /* Equally specialized, move to next function. If there + is no next function, nothing's most specialized. */ + fn = TREE_CHAIN (fn); champ = fn; } } - - for (fn = instantiations; fn && fn != champ; fn = TREE_CHAIN (fn)) - { - fate = more_specialized (TREE_VALUE (champ), TREE_VALUE (fn), - DEDUCE_EXACT, -1); - if (fate != 1) - return error_mark_node; - } + + if (champ) + /* Now verify that champ is better than everything earlier in the + instantiation list. */ + for (fn = instantiations; fn != champ; fn = TREE_CHAIN (fn)) + if (get_bindings_real (TREE_VALUE (champ), + DECL_TEMPLATE_RESULT (TREE_VALUE (fn)), + NULL_TREE, 0, DEDUCE_EXACT, -1) + || !get_bindings_real (TREE_VALUE (fn), + DECL_TEMPLATE_RESULT (TREE_VALUE (champ)), + NULL_TREE, 0, DEDUCE_EXACT, -1)) + { + champ = NULL_TREE; + break; + } + + processing_template_decl--; + + if (!champ) + return error_mark_node; return TREE_PURPOSE (champ) ? TREE_PURPOSE (champ) : TREE_VALUE (champ); } @@ -12333,7 +12443,8 @@ dependent_template_id_p (tree tmpl, tree args) TYPENAME_TYPE corresponds. Returns ERROR_MARK_NODE if no such TYPE can be found. Note that this function peers inside uninstantiated templates and therefore should be used only in extremely limited - situations. */ + situations. ONLY_CURRENT_P restricts this peering to the currently + open classes heirarchy (which is required when comparing types). */ tree resolve_typename_type (tree type, bool only_current_p) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 66d1b01..afa03d5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2005-03-31 Nathan Sidwell <nathan@codesourcery.com> + + PR c++/19203, DR 214 + * g++.dg/parse/ambig3.C: Not ambiguous. + * g++.dg/template/spec20.C: New. + * g++.dg/template/spec21.C: New. + 2005-03-31 Steve Ellcey <sje@cup.hp.com> PR target/20045 diff --git a/gcc/testsuite/g++.dg/parse/ambig3.C b/gcc/testsuite/g++.dg/parse/ambig3.C index 72ee960..4139071 100644 --- a/gcc/testsuite/g++.dg/parse/ambig3.C +++ b/gcc/testsuite/g++.dg/parse/ambig3.C @@ -5,8 +5,17 @@ template <int> struct A { static const int i = 1; }; template <int> struct B {}; -template <typename> void foo(B<0>) {} // { dg-error "" } +template <typename> int foo(B<0>) +{ + return 0; +} -template <typename, int j> B<A<j>::i-1> foo(B<j>) { return B<0>(); } // { dg-error "" } +template <typename, int j> B<A<j>::i-1> foo(B<j>) +{ + return B<0>(); +} -void bar() { foo<int>(B<0>()); } // { dg-error "ambiguous" } +int main() +{ + return foo<int>(B<0>()); +} diff --git a/gcc/testsuite/g++.dg/template/spec20.C b/gcc/testsuite/g++.dg/template/spec20.C new file mode 100644 index 0000000..71548e4 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/spec20.C @@ -0,0 +1,19 @@ +// Copyright (C) 2005 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 31 Mar 2005 <nathan@codesourcery.com> + +// Origin: Giovanni Bajo <giovannibajo@libero.it> +// Bug 19203: Failure to implement DR 214 + +template <class A> +void foo(const A& a); + +template <class RET, class ARG1> +int foo(RET (&)(ARG1)); // this one + + +float decl(int); + +int bar(void) +{ + return foo(decl); +} diff --git a/gcc/testsuite/g++.dg/template/spec21.C b/gcc/testsuite/g++.dg/template/spec21.C new file mode 100644 index 0000000..e04ac5a --- /dev/null +++ b/gcc/testsuite/g++.dg/template/spec21.C @@ -0,0 +1,28 @@ +// Copyright (C) 2005 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 31 Mar 2005 <nathan@codesourcery.com> + +// { dg-do run } +// DR214 + +template <class T> T f(int) {return 0;} +template <class T, class U> T f(U){return 1;} + +template <typename T, typename R> T checked_cast (R const &) {return 0;} +template <typename T, typename R> T checked_cast (R *) {return 1;} + + +int main () +{ + int i = 0; + + if (f<int>(1)) + return 1; + + if (checked_cast<int>(i) != 0) + return 2; + + if (checked_cast<int>(&i) != 1) + return 3; + + return 0; +} |