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 <nat...@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

Reply via email to