Patchwork PR c++/40942 - Failure of template specialization partial ordering

login
register
mail settings
Submitter Dodji Seketeli
Date March 31, 2012, 4:37 p.m.
Message ID <m3k420n2v7.fsf@redhat.com>
Download mbox | patch
Permalink /patch/149859/
State New
Headers show

Comments

Dodji Seketeli - March 31, 2012, 4:37 p.m.
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(-)
Jason Merrill - April 2, 2012, 5:02 a.m.
OK.

Jason

Patch

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" }
 }