c++: Include the constraint parameter mapping in diagnostic constraint contexts
authorPatrick Palka <ppalka@redhat.com>
Wed, 18 Mar 2020 17:57:24 +0000 (13:57 -0400)
committerPatrick Palka <ppalka@redhat.com>
Fri, 20 Mar 2020 14:19:54 +0000 (10:19 -0400)
commit828878c35c8585978e3ac22deddbf10f33c0a576
tree96205f9de2a52109d19f6c3b85990ff00953daf3
parent261014a1be433a27af75fb7eecc77231261d84f7
c++: Include the constraint parameter mapping in diagnostic constraint contexts

When diagnosing a constraint error, we currently try to print the constraint
inside a diagnostic constraint context with its template arguments substituted
in.  If substitution fails, then we instead just print the dependent form, as in
the test case below:

  .../diagnostic6.C:14:15: error: static assertion failed
     14 | static_assert(E<int>); // { dg-error "static assertion failed|not a class" }
        |               ^~~~~~
  .../diagnostic6.C:14:15: note: constraints not satisfied
  .../diagnostic6.C:4:11:   required for the satisfaction of ‘C<T>’
  .../diagnostic6.C:8:11:   required for the satisfaction of ‘D<typename T::type>’
  .../diagnostic6.C:14:15: error: ‘int’ is not a class, struct, or union type

But printing just the dependent form sometimes makes it difficult to understand
the underlying failure.  In the above example, for instance, there's no
indication of how the template argument 'int' relates to either of the 'T's.

This patch improves the situation by changing these diagnostics to always print
the dependent form of the constraint, and alongside it the (preferably
substituted) constraint parameter mapping.  So with the same test case below we
now get:

  .../diagnostic6.C:14:15: error: static assertion failed
     14 | static_assert(E<int>); // { dg-error "static assertion failed|not a class" }
        |               ^~~~~~
  .../diagnostic6.C:14:15: note: constraints not satisfied
  .../diagnostic6.C:4:11:   required for the satisfaction of ‘C<T>’ [with T = typename T::type]
  .../diagnostic6.C:8:11:   required for the satisfaction of ‘D<typename T::type>’ [with T = int]
  .../diagnostic6.C:14:15: error: ‘int’ is not a class, struct, or union type

This change arguably makes it easier to figure out what's going on whenever a
constraint fails due to substitution creating an invalid type rather than
failing due to the constraint evaluating to false.

gcc/cp/ChangeLog:

* cxx-pretty-print.c (pp_cxx_parameter_mapping): Make extern.  Move
the "[with ]" bits to here from ...
(pp_cxx_atomic_constraint): ... here.
* cxx-pretty-print.h (pp_cxx_parameter_mapping): Declare.
* error.c (rebuild_concept_check): Delete.
(print_concept_check_info): Print the dependent form of the constraint and the
preferably substituted parameter mapping alongside it.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/diagnostic6.C: New test.
gcc/cp/ChangeLog
gcc/cp/cxx-pretty-print.c
gcc/cp/cxx-pretty-print.h
gcc/cp/error.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/concepts/diagnostic6.C [new file with mode: 0644]