This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] PR c++/40942 - Failure of template specialization partial ordering
- From: Dodji Seketeli <dodji at redhat dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Cc: Jason Merrill <jason at redhat dot com>, Nathan Sidwell <nathan at codesourcery dot com>
- Date: Sat, 31 Mar 2012 18:37:16 +0200
- Subject: [PATCH] PR c++/40942 - Failure of template specialization partial ordering
Hello,
G++ compiles the example below without error:
struct S
{
template <typename T>
S (T const *) //#0
{ }
template <int N>
S (char const (&)[N]) //#1
{ }
};
int
main()
{
S s1 ("test"); // #3 This should error out because the
// call to S constructor is ambiguous.
}
But the call to the constructor at #3 should be considered ambiguous.
G++ considers this call non-ambiguous and chooses #1 because during
overload resolution, the partial ordering of the two constructors ends
up considering that the second S constructor template is more
specialized than the first one.
It does so because it wrongly applies an array-to-pointer decay
conversion to the "array of const char" parameter type of S in #1 (after
the reference-removing conversion that is allowed in that context),
converting it into a "pointer to const char".
That decay conversion is not allowed in the context of partial ordering
of template instantiations ([temp.deduct.partial]/5 lists the
conversions allowed in that context and doesn't mention any decay
conversion). It is only allowed in the context of a function call.
I believe this behaviour dates back from 2001 when the commit r39604
[1] was added, and the commit r97336 [2] that implemented DR 214
worked hard to keep it.
Here are the change logs of the two commits in question.
[1]:
commit a1d01fd0e4b8bf97295885cfbbf8fe6f382efa4c
Author: nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Mon Feb 12 14:38:25 2001 +0000
cp:
* pt.c (maybe_adjust_types_for_deduction, DEDUCE_ORDER case):
Remove spurious information in comment. Allow further
adjustments of REFERENCE_TYPE args.
testsuite:
* g++.old-deja/g++.pt/spec40.C: New test.
[2]:
commit 517ee39a43d80fd91cc7c91c244ca0fc6e1d008e
Author: nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Thu Mar 31 17:36:17 2005 +0000
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.
Fixed thus by removing the decay conversion in the context of partial
ordering of template instantiations.
Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.
gcc/cp/
* pt.c (more_specialized_fn): Don't apply decay conversion to
types of function parameters.
gcc/testsuite/
* g++.old-deja/g++.pt/spec40.C: Adjust to take the resolution of
DR 214 in account.
---
gcc/cp/pt.c | 40 ----------------------------
gcc/testsuite/g++.old-deja/g++.pt/spec40.C | 27 ++++++++++++++++---
2 files changed, 23 insertions(+), 44 deletions(-)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9b410a7..04ba37d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -17132,46 +17132,6 @@ more_specialized_fn (tree pat1, tree pat2, int len)
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);
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec40.C b/gcc/testsuite/g++.old-deja/g++.pt/spec40.C
index 70abb6f..fc37f41 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/spec40.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/spec40.C
@@ -1,14 +1,33 @@
-// { dg-do run }
+// { dg-do compile }
// Copyright (C) 2000 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 12 Feb 2001 <nathan@codesourcery.com>
-// More from bug 1617. We didn't resolve partial ordering properly. The
-// std is rather vague about it anyway, DR 214 talks about this.
+// More from bug 1617. The resolution of DR 214 implies that the below
+// call to Foo is ambiguous.
+//
+// The type transformation (on the function parameter of Foo) allowed
+// in the context of partial ordering of the Foo template overloads is
+// the following ([temp.deduct.partial]/5):
+//
+// Before the partial ordering is done, certain transformations
+// are performed on the types used for partial ordering:
+//
+// - If P is a reference type, P is replaced by the type
+// referred to.
+//
+// - If A is a reference type, A is replaced by the type
+// referred to.
+//
+// It follows that we are not allowed to apply array-to-pointer
+// decay conversion to the type of the function parameter
+// 'char const (&)[I]'. So the two Foo specializations should
+// be considered unrelated. Thus the partial ordering of the two
+// Foo specializations should fail.
template <typename T> int Foo (T const *) {return 1;}
template <unsigned I> int Foo (char const (&)[I]) {return 2;}
int main ()
{
- return Foo ("a") != 2;
+ return Foo ("a") != 2; // { dg-error "call of overloaded \[^\n\r\]* is ambiguous" }
}
--
1.7.6.5
--
Dodji