https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106256

            Bug ID: 106256
           Summary: Custom diagnostics for unsatisified standard concepts
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Keywords: diagnostic
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: redi at gcc dot gnu.org
  Target Milestone: ---

Sy Brand's https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2429r0.pdf
"Concepts Error Messages for Humans" suggests that we should not expand the
definitions of standard concepts. For example, given:


#include <concepts>

template <std::integral N>
void f(N n);

int main() {
  f(nullptr);
}


Compiling with -std=c++20 gives:

<source>: In function 'int main()':
<source>:7:6: error: no matching function for call to 'f(std::nullptr_t)'
    7 |     f(nullptr);
      |     ~^~~~~~~~~
<source>:4:6: note: candidate: 'template<class N>  requires  integral<N> void
f(N)'
    4 | void f(N n);
      |      ^
<source>:4:6: note:   template argument deduction/substitution failed:
<source>:4:6: note: constraints not satisfied
In file included from <source>:1:
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/concepts: In substitution
of 'template<class N>  requires  integral<N> void f(N) [with N =
std::nullptr_t]':
<source>:7:6:   required from here
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/concepts:100:13:  
required for the satisfaction of 'integral<N>' [with N = std::nullptr_t]
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/concepts:100:24: note: the
expression 'is_integral_v<_Tp> [with _Tp = std::nullptr_t]' evaluated to
'false'
  100 |     concept integral = is_integral_v<_Tp>;
      |                        ^~~~~~~~~~~~~~~~~~


Sy suggested that showing the definition of std::integral is not helpful.
Saying that std::is_integral_v<T> is false is no more helpful than saying that
std::integral<T> is unsatisified. I agree.

We could skip showing the definition if it's a concept defined in the std::lib,
and could provide custom diagnostics for specific standard concepts e.g. Sy
suggests

Hint: 'integral<T>' is only satisfied if 'T' is an integral type, see
<https://en.cppreference.com/w/cpp/types/is_integral>

I'm not sure about showing the third-party URL (maybe a URL to a doc on
gcc.gnu.org instead) but I like the idea as the default behaviour. We could add
a switch to show all the gory details of the std::lib concept implementation,
but that shouldn't be the default. 



Other problems with this diagnostic:

<source>:4:6: note: candidate: 'template<class N>  requires  integral<N> void
f(N)'

This should say std::integral<N> not integral<N>. This becomes even more
important if we do decide to elide the details of standard concepts, we really
need to be clear it's std::integral.


<source>:4:6: note:   template argument deduction/substitution failed:
<source>:4:6: note: constraints not satisfied

1. Why is the second note indented less than the first?

2. Do we need both lines? Could we customize the first line when substitution
failed because of unsatisfied constraints? Maybe change that first line to say
whether deduction failed, or substitution failed, and in the latter case
combine it with "contraints not satisfied" if that was the reason for
substitution failure. It might be nice to be less succinct e.g. "this candidate
cannot be used because its template arguments could not be deduced", "this
candidate cannot be used because substituting the template arguments failed",
"this candidate cannot be used because its constraints are not satisfied".

Continuing ...

In file included from <source>:1:
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/concepts: In substitution
of 'template<class N>  requires  integral<N> void f(N) [with N =
std::nullptr_t]':
<source>:7:6:   required from here
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/concepts:100:13:  
required for the satisfaction of 'integral<N>' [with N = std::nullptr_t]
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/concepts:100:24: note: the
expression 'is_integral_v<_Tp> [with _Tp = std::nullptr_t]' evaluated to
'false'
  100 |     concept integral = is_integral_v<_Tp>;
      |                        ^~~~~~~~~~~~~~~~~~

1. The second line should say std::integral as well.

2. Why is its location the std::lib <concepts> header? That line refers to the
function template specialization f<std::nullptr_t> which is defined in the user
code, not in the <concepts> header. Why do we have "In file included from ..."
when we're referring to something not defined in a header?

3. Why are we even naming that candidate again? We've already said the
candidate didn't match and we're now printing the reasons it wasn't viable. I
don't think we need to repeat which candidate we're talking about.


Taken together, these suggestions would give us:

<source>: In function 'int main()':
<source>:7:6: error: no matching function for call to 'f(std::nullptr_t)'
    7 |     f(nullptr);
      |     ~^~~~~~~~~
<source>:4:6: note: candidate: 'template<class N>  requires  std::integral<N>
void f(N)'
    4 | void f(N n);
      |      ^
<source>:4:6: note:   this candidate cannot be used because its constraints are
not satisfied
<source>:4:6: note:   'std::integral<N>' is only satisfied if 'N' is an
integral type, see
<https://gcc.gnu.org/onlinedocs/libstdc++/concepts/is_integral>

Reply via email to