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>