<html>
    <head>
      <base href="http://llvm.org/bugs/" />
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW --- - After r224456, clang++ fails to substitute some non-type template arguments"
   href="http://llvm.org/bugs/show_bug.cgi?id=22738">22738</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>After r224456, clang++ fails to substitute some non-type template arguments
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>new-bugs
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>All
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>All
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>new bugs
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>dimitry@andric.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvmbugs@cs.uiuc.edu
          </td>
        </tr>

        <tr>
          <th>Classification</th>
          <td>Unclassified
          </td>
        </tr></table>
      <p>
        <div>
        <pre>After r224456 [1], clang++ fails to substitute some non-type template
arguments, in particular a construction used by google sparsehash [2].

This resulted in a port build failure during a test run for importing clang
3.6.0 into FreeBSD [3].

The resulting error is of the form:

./src/hash_test_interface.h:772:15: note: candidate template ignored:
substitution failure [with K2 = int, T2 = int]: deduced non-type template
argument does not have the same type as the its corresponding template
parameter ('int' vs 'const int &')
  friend void swap(HashtableInterface_DenseHashMap<K2,T2,Empty2,H2,E2,A2>& a,
              ^

A reduced example is as follows:

========================================================================
template <class K, const K& E>
class NonTypeTest {
public:
  template <class K2, const K2& E2>
  friend void swap(NonTypeTest<K2,E2>& a, NonTypeTest<K2,E2>& b);
};

template <class K2, const K2& E2>
void swap(NonTypeTest<K2,E2>& a, NonTypeTest<K2,E2>& b)
{
}

extern const int N = 42;

typedef NonTypeTest<int, N> TestType;

void test(TestType x, TestType y)
{
  swap(x, y);
}
========================================================================

When clang tries to deduce the non-type template argument for the free swap
function, it fails:

non-type2.cpp:19:3: error: no matching function for call to 'swap'
  swap(x, y);
  ^~~~
non-type2.cpp:9:6: note: candidate template ignored: substitution failure [with
K2 = int]: deduced non-type template argument does not have the same type as
the its corresponding template parameter ('int' vs 'const int &')
void swap(NonTypeTest<K2,E2>& a, NonTypeTest<K2,E2>& b)
     ^
1 error generated.

And strangely, it complains that the non-type template argument has the wrong
type, where it clearly is "const K2&", K2 being "int" in this case.

Note that gcc has no problems compiling this: I tried 4.7 through 5.0.

Even replacing the 'derived' non-type template argument with an explicit int
does not help:

========================================================================
template <class K, const int& E>
class NonTypeTest {
public:
  template <class K2, const int& E2>
  friend void swap(NonTypeTest<K2,E2>& a, NonTypeTest<K2,E2>& b);
};

template <class K2, const int& E2>
void swap(NonTypeTest<K2,E2>& a, NonTypeTest<K2,E2>& b)
{
}

extern const int N = 42;

typedef NonTypeTest<int, N> TestType;

void test(TestType x, TestType y)
{
  swap(x, y);
}
========================================================================

Resulting in:

non-type6.cpp:19:3: error: no matching function for call to 'swap'
  swap(x, y);
  ^~~~
non-type6.cpp:9:6: note: candidate template ignored: substitution failure [with
K2 = int]: deduced non-type template argument does not have the same type as
the its corresponding template parameter ('int' vs 'const int &')
void swap(NonTypeTest<K2,E2>& a, NonTypeTest<K2,E2>& b)
     ^
1 error generated.

Again, the versions of gcc that I tried had no problems compiling it.

Interestingly, when you remove the first template argument, it also begins to
trip up gcc 4.9 and later:

========================================================================
template <const int& E>
class NonTypeTest {
public:
  template <const int& E2>
  friend void swap(NonTypeTest<E2>& a, NonTypeTest<E2>& b);
};

template <const int& E2>
void swap(NonTypeTest<E2>& a, NonTypeTest<E2>& b)
{
}

extern const int N = 42;

typedef NonTypeTest<N> TestType;

void test(TestType x, TestType y)
{
  swap(x, y);
}
========================================================================

Clang produces the by now familiar error:

non-type7.cpp:19:3: error: no matching function for call to 'swap'
  swap(x, y);
  ^~~~
non-type7.cpp:9:6: note: candidate template ignored: substitution failure :
deduced non-type template argument does not have the same type as the its
corresponding template parameter ('int' vs 'const int &')
void swap(NonTypeTest<E2>& a, NonTypeTest<E2>& b)
     ^
1 error generated.

But while gcc 4.7 and 4.8 compile this without error, both gcc 4.9 and 5.0
start complaining:

non-type7.cpp: In function 'void test(TestType, TestType)':
non-type7.cpp:19:12: error: no matching function for call to 'swap(TestType&,
TestType&)'
   swap(x, y);
            ^
non-type7.cpp:9:6: note: candidate: template<const int& E2> void
swap(NonTypeTest<E2>&, NonTypeTest<E2>&)
 void swap(NonTypeTest<E2>& a, NonTypeTest<E2>& b)
      ^
non-type7.cpp:9:6: note:   template argument deduction/substitution failed:
non-type7.cpp:19:12: note:   couldn't deduce template parameter 'E2'
   swap(x, y);
            ^

It is not entirely clear from the error message *why* it could not deduce the
parameter, though.

Summarizing the above: is this a construction that was never really legal in
C++ (or C++11), but is it only recently being flagged as invalid?  Or is this a
bug in non-type template argument deduction, both in clang, and some versions
of gcc?

And if the construction is not legal, what is the correct way of achieving the
goal that google sparsehash tries to achieve? :-)

[1] <a href="http://llvm.org/viewvc/llvm-project?view=revision&revision=224456">http://llvm.org/viewvc/llvm-project?view=revision&revision=224456</a>
[2] <a href="https://code.google.com/p/sparsehash/">https://code.google.com/p/sparsehash/</a>
[3]
<a href="http://package18.nyi.freebsd.org/data/headamd64PR197395-default/2015-02-27_12h37m16s/logs/errors/google-sparsehash-2.0.2_2.log">http://package18.nyi.freebsd.org/data/headamd64PR197395-default/2015-02-27_12h37m16s/logs/errors/google-sparsehash-2.0.2_2.log</a></pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>