* Fix 19203, implement DR 214
@ 2005-03-31 17:51 Nathan Sidwell
2005-03-31 18:49 ` Mark Mitchell
0 siblings, 1 reply; 2+ messages in thread
From: Nathan Sidwell @ 2005-03-31 17:51 UTC (permalink / raw)
To: GCC Patches; +Cc: Mark Mitchell
[-- Attachment #1: Type: text/plain, Size: 1450 bytes --]
Hi,
I've installed this patch on mainline to fix PR 19203 (by implementing
DR214). I have not installed on 4.0 - that will be an RM decision. I've
tested the patch there and it is ok from that POV.
One thing I changed in implementing DR214 was to keep the behaviour
I originally implemented when attempting to fix the underspecified nature
of function partial ordering. DR 214 does not consider
template <typename T> int Foo (T const *) {return 1;} //#1
template <unsigned I> int Foo (char const (&)[I]) {return 2;} //#2
int main ()
{
return Foo ("a") != 2;
}
(this is g++.old-deja/g++.pt/spec40.C). IMHO the fact that array->pointer
decay allowed #1 to deduce should be considered when determining whether
#1 or #2 are ordered. G++ had code to do a similar decay during partial
ordering, and I have preserved that in implementing DR214. Unfortunately
the timing was such that I was unable to persuade the committee to amend
214 to address this issue -- the feeling was DR214 should be resolved and
the above issue was a separate problem, which should be dealt with a new
DR. We should champion such a DR :)
I think this patch allows a further cleanup by removing the LEN argument
from type_unification_real and its callers.
booted & tested on i686-pc-linux-gnu.
nathan
--
Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery LLC
nathan@codesourcery.com :: http://www.planetfall.pwp.blueyonder.co.uk
[-- Attachment #2: 19203.patch --]
[-- Type: text/plain, Size: 15737 bytes --]
? cp/19203.diff
? cp/all.diff
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.531
diff -c -3 -p -r1.531 call.c
*** cp/call.c 24 Feb 2005 21:55:10 -0000 1.531
--- cp/call.c 31 Mar 2005 10:20:54 -0000
*************** joust (struct z_candidate *cand1, struct
*** 6098,6107 ****
if (cand1->template_decl && cand2->template_decl)
{
! winner = more_specialized
(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
--- 6098,6106 ----
if (cand1->template_decl && cand2->template_decl)
{
! winner = more_specialized_fn
(TI_TEMPLATE (cand1->template_decl),
TI_TEMPLATE (cand2->template_decl),
/* 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
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.1106.2.1
diff -c -3 -p -r1.1106.2.1 cp-tree.h
*** cp/cp-tree.h 1 Mar 2005 10:00:30 -0000 1.1106.2.1
--- cp/cp-tree.h 31 Mar 2005 10:21:06 -0000
*************** extern int function_depth;
*** 3112,3119 ****
typedef enum unification_kind_t {
DEDUCE_CALL,
DEDUCE_CONV,
! DEDUCE_EXACT,
! DEDUCE_ORDER
} unification_kind_t;
/* Macros for operating on a template instantiation level node. */
--- 3112,3118 ----
typedef enum unification_kind_t {
DEDUCE_CALL,
DEDUCE_CONV,
! DEDUCE_EXACT
} unification_kind_t;
/* Macros for operating on a template instantiation level node. */
*************** extern tree instantiate_class_template
*** 3997,4003 ****
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 void mark_class_instantiated (tree, int);
extern void do_decl_instantiation (tree, tree);
extern void do_type_instantiation (tree, tree, tsubst_flags_t);
--- 3996,4002 ----
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_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);
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.978.2.5
diff -c -3 -p -r1.978.2.5 pt.c
*** cp/pt.c 17 Mar 2005 13:30:49 -0000 1.978.2.5
--- cp/pt.c 31 Mar 2005 10:21:31 -0000
*************** instantiate_template (tree tmpl, tree ta
*** 9032,9042 ****
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
--- 9032,9037 ----
*************** maybe_adjust_types_for_deduction (unific
*** 9184,9211 ****
/* 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 ();
}
--- 9179,9184 ----
*************** type_unification_real (tree tparms,
*** 9301,9310 ****
sub_strict = UNIFY_ALLOW_NONE;
break;
- case DEDUCE_ORDER:
- sub_strict = UNIFY_ALLOW_NONE;
- break;
-
default:
gcc_unreachable ();
}
--- 9274,9279 ----
*************** type_unification_real (tree tparms,
*** 9347,9353 ****
else
type = arg;
! if (strict == DEDUCE_EXACT || strict == DEDUCE_ORDER)
{
if (same_type_p (parm, type))
continue;
--- 9316,9322 ----
else
type = arg;
! if (strict == DEDUCE_EXACT)
{
if (same_type_p (parm, type))
continue;
*************** mark_decl_instantiated (tree result, int
*** 10394,10429 ****
/* 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. */
int
! more_specialized (tree pat1, tree pat2, int deduce, int len)
{
! tree targs;
! int winner = 0;
! /* 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;
! targs = get_bindings_real (pat2, DECL_TEMPLATE_RESULT (pat1),
! NULL_TREE, 0, deduce, len);
! if (targs)
! ++winner;
! --processing_template_decl;
! return winner;
}
/* Given two class template specialization list nodes PAT1 and PAT2, return:
--- 10363,10520 ----
/* Given two function templates PAT1 and PAT2, return:
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 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_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);
! /* 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:
*************** tree
*** 10587,10623 ****
most_specialized_instantiation (tree instantiations)
{
tree fn, champ;
- int fate;
if (!instantiations)
return NULL_TREE;
!
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
{
! if (fate == 0)
! {
! fn = TREE_CHAIN (fn);
! if (! fn)
! return error_mark_node;
! }
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;
! }
return TREE_PURPOSE (champ) ? TREE_PURPOSE (champ) : TREE_VALUE (champ);
}
--- 10678,10733 ----
most_specialized_instantiation (tree instantiations)
{
tree fn, champ;
if (!instantiations)
return NULL_TREE;
!
! ++processing_template_decl;
!
champ = instantiations;
for (fn = TREE_CHAIN (instantiations); fn; fn = TREE_CHAIN (fn))
{
! 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)
! /* Equally specialized, move to next function. If there
! is no next function, nothing's most specialized. */
! fn = TREE_CHAIN (fn);
champ = 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))
! {
! champ = NULL_TREE;
! break;
! }
!
! processing_template_decl--;
!
! if (!champ)
! return error_mark_node;
return TREE_PURPOSE (champ) ? TREE_PURPOSE (champ) : TREE_VALUE (champ);
}
Index: testsuite/g++.dg/parse/ambig3.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/parse/ambig3.C,v
retrieving revision 1.1
diff -c -3 -p -r1.1 ambig3.C
*** testsuite/g++.dg/parse/ambig3.C 22 Jul 2003 10:54:14 -0000 1.1
--- testsuite/g++.dg/parse/ambig3.C 31 Mar 2005 10:21:36 -0000
***************
*** 5,12 ****
template <int> struct A { static const int i = 1; };
template <int> struct B {};
! template <typename> void foo(B<0>) {} // { dg-error "" }
! template <typename, int j> B<A<j>::i-1> foo(B<j>) { return B<0>(); } // { dg-error "" }
! void bar() { foo<int>(B<0>()); } // { dg-error "ambiguous" }
--- 5,21 ----
template <int> struct A { static const int i = 1; };
template <int> struct B {};
! template <typename> int foo(B<0>)
! {
! return 0;
! }
! template <typename, int j> B<A<j>::i-1> foo(B<j>)
! {
! return B<0>();
! }
! int main()
! {
! return foo<int>(B<0>());
! }
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: Fix 19203, implement DR 214
2005-03-31 17:51 Fix 19203, implement DR 214 Nathan Sidwell
@ 2005-03-31 18:49 ` Mark Mitchell
0 siblings, 0 replies; 2+ messages in thread
From: Mark Mitchell @ 2005-03-31 18:49 UTC (permalink / raw)
To: Nathan Sidwell; +Cc: GCC Patches
Nathan Sidwell wrote:
> Hi,
> I've installed this patch on mainline to fix PR 19203 (by implementing
> DR214). I have not installed on 4.0 - that will be an RM decision. I've
> tested the patch there and it is ok from that POV.
I think it's just a touch on the dicey side for 4.0; I've targeted it
for 4.0.1 in bugzilla. Thanks for taking care of this!
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
(916) 791-8304
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2005-03-31 18:05 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-03-31 17:51 Fix 19203, implement DR 214 Nathan Sidwell
2005-03-31 18:49 ` Mark Mitchell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).