<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </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 - enable_if "requirement not satisfied" diagnostics could be more robust and general"
   href="https://bugs.llvm.org/show_bug.cgi?id=51696">51696</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>enable_if "requirement not satisfied" diagnostics could be more robust and general
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

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

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

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

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

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

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

        <tr>
          <th>Component</th>
          <td>-New Bugs
          </td>
        </tr>

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

        <tr>
          <th>Reporter</th>
          <td>arthur.j.odwyer@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>htmldeveloper@gmail.com, llvm-bugs@lists.llvm.org, neeilans@live.com, richard-llvm@metafoo.co.uk
          </td>
        </tr></table>
      <p>
        <div>
        <pre>// <a href="https://godbolt.org/z/E5d63q77E">https://godbolt.org/z/E5d63q77E</a>

cat >test.cpp <<EOF
template<bool B, class T = void> struct enable_if { using type = T; };
template<class T> struct enable_if<false, T> {};

// LIES AND DECEPTION
template<bool Dummy, bool B> using enable_if_t = typename enable_if<B>::type;

template<class T> auto f() -> enable_if_t<true, sizeof(T) != 1> {}

void test() {
    f<char>();
}
EOF
clang++ -c test.cpp

test.cpp:10:5: error: no matching function for call to 'f'
    f<char>();
    ^~~~~~~
test.cpp:7:24: note: candidate template ignored: requirement 'true' was not
satisfied [with T = char]
template<class T> auto f() -> enable_if_t<true, sizeof(T) != 1> {}
                       ^


The problem is that the diagnostic is looking for the specific names
`enable_if` and `enable_if_t`, and then *assuming* that if the templates have
those names (regardless of namespace), their parameters must follow the
expected pattern.

It would be nicer if Clang could follow the outline I sketched in
<a href="https://reviews.llvm.org/D108216">https://reviews.llvm.org/D108216</a> :

<span class="quote">> Well, remember that our _EnableIf has a different shape from the standard
> enable_if_t. Ours is _MetaBase<B>::_EnableIfImpl<R>, whereas enable_if_t
> is enable_if<B, R>::type. So I think the criterion would be something
> like "We failed to find a member in a class template of the form
> template<[...], bool, [...]>, where that bool parameter is false,
> and where, if the bool parameter had been true, we would have found
> such a member." If that's too backtracky (Clang sucks at
> backtracking/hypotheticals), we could say "We failed to find a member
> in a class template of the form template<[...], bool, [...]>,
> where that bool parameter is false, and where the class template
> has at least one partial or explicit specialization." I would not
> look at the name of the member, nor the name of the class, nor
> the reason-we're-looking-for-that-member (e.g. the name of the
> alias template).</span >

If Clang could do this, then not only would it not get tricked by stupid
contrived examples like mine above, but also it would be able to detect
"requirements" even when they were implemented in SCARY-template ways such as
the above-mentioned _MetaBase<B>::_EnableIfImpl<R>. As long as there's *a* bool
argument, that is false, and where if it were true we would have found a
member, that should be good enough to trigger Clang's special-case diagnostics
about "requirement was not satisfied".

Even though this bug report is phrased in terms of a "bad diagnostic on
contrived input," *really* what I'm hoping to get out of it is "good
diagnostics on realistic input" (and specifically, on libc++'s _EnableIf). My
contrived example merely demonstrates that the existing code in Clang cannot be
defended on the grounds of "being safely conservative," in case anyone was
going to try that.</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>