Bug 43559

Summary: [4.5 Regression] Overloaded template functions became ambiguous
Product: gcc Reporter: Philipp <carlphilippreh>
Component: c++Assignee: Jason Merrill <jason>
Status: RESOLVED FIXED    
Severity: normal CC: gcc-bugs, jason
Priority: P3 Keywords: rejects-valid
Version: 4.5.0   
Target Milestone: 4.5.0   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2010-03-30 16:46:47

Description Philipp 2010-03-28 19:04:35 UTC
The following code used to work with gcc-4.4.3.
The Comeau online compiler also accepts it.
But with the gcc-4.5 trunk, it is rejected as ambiguous.


template<typename T, typename U> void f(U&) { }
template<typename T, typename U> void f(T const&) { }

int main()
{
        int a;
        f<int, int const>(a);
}

This is a reduced test case from boost.phoenix.
I'm not completely sure if gcc-4.5 is now right or wrong. Please investigate.
Comment 1 Paolo Carlini 2010-03-28 19:27:54 UTC
Jason, what do you think?
Comment 2 Johannes Schaub 2010-03-28 19:33:32 UTC
I've done some analysis for this using the argument-deduction during partial ordering rules as clarified by http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#214:

template<typename T, typename U>
void f(U&) { } // #1

template<typename T, typename U>
void f(T const&) { } // #2


4 Each type from the parameter template and the corresponding type from the argument template are used as the types of P and A.

Round 1, #1 -> #2:

  As: (X&)        // #1
  Ps: (T const&)  // #2

Round 2, #2 -> #1:

  As: (X const&)  // #2
  Ps: (T&)        // #1

— 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.

=> 

Round 1, #1 -> #2:

  As: (X)          // #1
  Ps: (T const)    // #2

Round 2, #2 -> #1:

  As: (X const)   // #2
  Ps: (T)         // #1

If both P and A were reference types (before being replaced with the type referred to above), determine which of the two types (if any) is more cv-quali&#64257;ed than the other; otherwise the types are considered to be equally cv-quali&#64257;ed for partial ordering purposes. The result of this determination will be used below.

=> ************* #2 more cv-qualified than #1

— If P is a cv-quali&#64257;ed type, P is replaced by the cv-unquali&#64257;ed version of P.
— If A is a cv-quali&#64257;ed type, A is replaced by the cv-unquali&#64257;ed version of A.

Round 1, #1 -> #2:

  As: (X)     // #1
  Ps: (T)     // #2

Round 2, #2 -> #1:

  As: (X)     // #2
  Ps: (T)     // #1

Using the resulting types P and A the deduction is then done as described in 14.9.2.5. If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template.

Round 1, T <- X                                       
Round 2, T <- X

#1.param1 at least as specialized as #2.param1 and vice-versa. 

If, for a given type, deduction succeeds in both directions (i.e., the types are identical after the transformations above) and if the type from the argument template is more cv-quali&#64257;ed than the type from the parameter template (as described above) that type is considered to be more specialized than the other.

  Deduction succeeded in both rounds ("types" as in P/A pairs), but #2.param1 was more cv-qualified 
    => #2.param1 more specialized than #1.param1

If for each type being considered a given template is at least as specialized for all types and more specialized for some set of types and the other template is not more specialized for any types or is not at least as specialized for any types, then the given template is more specialized than the other template.

#2 is at least as specialized for all types and more specialized for #1.param1 and #1 is not more specialized for any types, so #2 is more specialized than #1. 

So, i think GCC should choose the one with the f(T const&) because that template is more specialized. Notice that the rules also say

In most cases, all template parameters must have values in order for deduction to succeed, but for partial ordering purposes a template parameter may remain without a value provided it is not used in the types being used for partial ordering. 
Comment 3 Richard Biener 2010-03-30 13:47:43 UTC
Still unconfirmed, leaving at P3.
Comment 4 Jason Merrill 2010-03-30 16:46:47 UTC
Yes, this is a bug.  The call to same_type_p in more_specialized_fn is wrong because the two template parms have different indices.
Comment 5 Jason Merrill 2010-03-30 19:40:01 UTC
Subject: Bug 43559

Author: jason
Date: Tue Mar 30 19:39:48 2010
New Revision: 157831

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=157831
Log:
	PR c++/43559
	* pt.c (more_specialized_fn): Don't control cv-qualifier check
	with same_type_p.

Added:
    trunk/gcc/testsuite/g++.dg/template/partial7.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/pt.c
    trunk/gcc/testsuite/ChangeLog

Comment 6 Jason Merrill 2010-03-30 19:47:10 UTC
Fixed.