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>
PR c++/18644
......
......@@ -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
......
......@@ -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);
......
......@@ -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)
......
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
......
......@@ -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>());
}
// 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