Commit dda04398 by Nathan Sidwell Committed by Nathan Sidwell

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
parent 27954bdb
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> 2005-03-31 Gabriel Dos Reis <gdr@integrable-solutions.net>
PR c++/18644 PR c++/18644
......
...@@ -6084,10 +6084,9 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn) ...@@ -6084,10 +6084,9 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn)
if (cand1->template_decl && cand2->template_decl) if (cand1->template_decl && cand2->template_decl)
{ {
winner = more_specialized winner = more_specialized_fn
(TI_TEMPLATE (cand1->template_decl), (TI_TEMPLATE (cand1->template_decl),
TI_TEMPLATE (cand2->template_decl), TI_TEMPLATE (cand2->template_decl),
DEDUCE_ORDER,
/* Tell the deduction code how many real function arguments /* Tell the deduction code how many real function arguments
we saw, not counting the implicit 'this' argument. But, we saw, not counting the implicit 'this' argument. But,
add_function_candidate() suppresses the "this" argument add_function_candidate() suppresses the "this" argument
......
...@@ -3112,8 +3112,7 @@ extern int function_depth; ...@@ -3112,8 +3112,7 @@ extern int function_depth;
typedef enum unification_kind_t { typedef enum unification_kind_t {
DEDUCE_CALL, DEDUCE_CALL,
DEDUCE_CONV, DEDUCE_CONV,
DEDUCE_EXACT, DEDUCE_EXACT
DEDUCE_ORDER
} unification_kind_t; } unification_kind_t;
/* Macros for operating on a template instantiation level node. */ /* Macros for operating on a template instantiation level node. */
...@@ -3998,7 +3997,7 @@ extern tree instantiate_class_template (tree); ...@@ -3998,7 +3997,7 @@ extern tree instantiate_class_template (tree);
extern tree instantiate_template (tree, tree, tsubst_flags_t); extern tree instantiate_template (tree, tree, tsubst_flags_t);
extern int fn_type_unification (tree, tree, tree, tree, tree, unification_kind_t, int); extern int fn_type_unification (tree, tree, tree, tree, tree, unification_kind_t, int);
extern void mark_decl_instantiated (tree, 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 mark_class_instantiated (tree, int);
extern void do_decl_instantiation (tree, tree); extern void do_decl_instantiation (tree, tree);
extern void do_type_instantiation (tree, tree, tsubst_flags_t); extern void do_type_instantiation (tree, tree, tsubst_flags_t);
......
...@@ -9064,11 +9064,6 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain) ...@@ -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 as in [temp.expl.spec], or when taking the address of a function
template, as in [temp.deduct.funcaddr]. 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 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 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 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, ...@@ -9216,28 +9211,6 @@ maybe_adjust_types_for_deduction (unification_kind_t strict,
/* There is nothing to do in this case. */ /* There is nothing to do in this case. */
return 0; 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: default:
gcc_unreachable (); gcc_unreachable ();
} }
...@@ -9333,10 +9306,6 @@ type_unification_real (tree tparms, ...@@ -9333,10 +9306,6 @@ type_unification_real (tree tparms,
sub_strict = UNIFY_ALLOW_NONE; sub_strict = UNIFY_ALLOW_NONE;
break; break;
case DEDUCE_ORDER:
sub_strict = UNIFY_ALLOW_NONE;
break;
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
...@@ -9379,7 +9348,7 @@ type_unification_real (tree tparms, ...@@ -9379,7 +9348,7 @@ type_unification_real (tree tparms,
else else
type = arg; type = arg;
if (strict == DEDUCE_EXACT || strict == DEDUCE_ORDER) if (strict == DEDUCE_EXACT)
{ {
if (same_type_p (parm, type)) if (same_type_p (parm, type))
continue; continue;
...@@ -10426,36 +10395,158 @@ mark_decl_instantiated (tree result, int extern_p) ...@@ -10426,36 +10395,158 @@ mark_decl_instantiated (tree result, int extern_p)
/* Given two function templates PAT1 and PAT2, return: /* 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 PAT1 is more specialized than PAT2 as described in [temp.func.order].
-1 if PAT2 is more specialized than PAT1. -1 if PAT2 is more specialized than PAT1.
0 if neither is more specialized. 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 int
more_specialized (tree pat1, tree pat2, int deduce, int len) more_specialized_fn (tree pat1, tree pat2, int len)
{ {
tree targs; tree decl1 = DECL_TEMPLATE_RESULT (pat1);
int winner = 0; 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;
/* If template argument deduction succeeds, we substitute the /* Don't consider 'this' parameter. */
resulting arguments into non-deduced contexts. While doing that, if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1))
we must be aware that we may encounter dependent types. */ args1 = TREE_CHAIN (args1);
++processing_template_decl;
targs = get_bindings_real (pat1, DECL_TEMPLATE_RESULT (pat2),
NULL_TREE, 0, deduce, len);
if (targs)
--winner;
targs = get_bindings_real (pat2, DECL_TEMPLATE_RESULT (pat1), if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2))
NULL_TREE, 0, deduce, len); args2 = TREE_CHAIN (args2);
if (targs)
++winner;
--processing_template_decl;
return 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;
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);
}
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: /* Given two class template specialization list nodes PAT1 and PAT2, return:
...@@ -10619,38 +10710,57 @@ tree ...@@ -10619,38 +10710,57 @@ tree
most_specialized_instantiation (tree instantiations) most_specialized_instantiation (tree instantiations)
{ {
tree fn, champ; tree fn, champ;
int fate;
if (!instantiations) if (!instantiations)
return NULL_TREE; return NULL_TREE;
++processing_template_decl;
champ = instantiations; champ = instantiations;
for (fn = TREE_CHAIN (instantiations); fn; fn = TREE_CHAIN (fn)) for (fn = TREE_CHAIN (instantiations); fn; fn = TREE_CHAIN (fn))
{ {
fate = more_specialized (TREE_VALUE (champ), TREE_VALUE (fn), int fate = 0;
DEDUCE_EXACT, -1);
if (fate == 1) if (get_bindings_real (TREE_VALUE (champ),
; DECL_TEMPLATE_RESULT (TREE_VALUE (fn)),
else NULL_TREE, 0, DEDUCE_EXACT, -1))
{ fate--;
if (fate == 0)
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)
/* Equally specialized, move to next function. If there
is no next function, nothing's most specialized. */
fn = TREE_CHAIN (fn); fn = TREE_CHAIN (fn);
if (! fn)
return error_mark_node;
}
champ = fn; champ = fn;
} }
} }
for (fn = instantiations; fn && fn != champ; fn = TREE_CHAIN (fn)) 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))
{ {
fate = more_specialized (TREE_VALUE (champ), TREE_VALUE (fn), champ = NULL_TREE;
DEDUCE_EXACT, -1); break;
if (fate != 1)
return error_mark_node;
} }
processing_template_decl--;
if (!champ)
return error_mark_node;
return TREE_PURPOSE (champ) ? TREE_PURPOSE (champ) : TREE_VALUE (champ); return TREE_PURPOSE (champ) ? TREE_PURPOSE (champ) : TREE_VALUE (champ);
} }
...@@ -12333,7 +12443,8 @@ dependent_template_id_p (tree tmpl, tree args) ...@@ -12333,7 +12443,8 @@ dependent_template_id_p (tree tmpl, tree args)
TYPENAME_TYPE corresponds. Returns ERROR_MARK_NODE if no such TYPE TYPENAME_TYPE corresponds. Returns ERROR_MARK_NODE if no such TYPE
can be found. Note that this function peers inside uninstantiated can be found. Note that this function peers inside uninstantiated
templates and therefore should be used only in extremely limited 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 tree
resolve_typename_type (tree type, bool only_current_p) resolve_typename_type (tree type, bool only_current_p)
......
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> 2005-03-31 Steve Ellcey <sje@cup.hp.com>
PR target/20045 PR target/20045
......
...@@ -5,8 +5,17 @@ ...@@ -5,8 +5,17 @@
template <int> struct A { static const int i = 1; }; template <int> struct A { static const int i = 1; };
template <int> struct B {}; 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>());
}
// 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);
}
// 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment