aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2005-03-31 17:36:17 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2005-03-31 17:36:17 +0000
commitdda0439880fee40a90309ed74446c29a3ca08a05 (patch)
tree5ecfece501acdb1b2be881d9444e863d74730ab4 /gcc/cp
parent27954bdbc3051fbf6adfdc8675fa33f36da7c292 (diff)
downloadgcc-dda0439880fee40a90309ed74446c29a3ca08a05.zip
gcc-dda0439880fee40a90309ed74446c29a3ca08a05.tar.gz
gcc-dda0439880fee40a90309ed74446c29a3ca08a05.tar.bz2
PR c++/19203, implement DR 214
cp: 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. testsuite: PR c++/19203, DR 214 * g++.dg/parse/ambig3.C: Not ambiguous. * g++.dg/template/spec20.C: New. * g++.dg/template/spec21.C: New. From-SVN: r97336
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog14
-rw-r--r--gcc/cp/call.c3
-rw-r--r--gcc/cp/cp-tree.h5
-rw-r--r--gcc/cp/pt.c261
4 files changed, 203 insertions, 80 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)