On 11/12/24 9:02 AM, David Malcolm wrote:
[from 0/3]
The most natural way to present textual output is to use indentation,
so patch 1 does this. However, our existing textual format uses the
source location as a prefix, e.g.
PATH/foo.cc: error: message goes here
and unfortunately this makes the indented hierarchy unreadable
(especially if a tree of diagnostics spans multiple source files).
I've previously tried to do a bit of diagnostic nesting with initial
spaces, which this patch removes. This seems like a small regression in
the default mode, though I'm not too concerned about it.
Maybe there could be a mode that puts the indenting from this framework
at the beginning of the message rather than the beginning of the line?
This patch uses the nested diagnostics capabilities added in the earlier
patch in the C++ frontend.
With this, and enabling the non-standard text formatting via:
-fdiagnostics-set-output=text:experimental-nesting=yes
and using:
-std=c++20 -fconcepts-diagnostics-depth=2
then the output for the example in SG15's P3358R0 ("SARIF for Structured
Diagnostics") is:
P3358R0.C: In function ‘int main()’:
P3358R0.C:26:6: error: no matching function for call to ‘pet(lizard)’
26 | pet(lizard{});
| ~~~^~~~~~~~~~
• note: candidate: ‘template<class auto:1> requires pettable<auto:1> void
pet(auto:1)’
P3358R0.C:21:6:
Putting the source location on a separate line seems like an interesting
approach to the issue of variable-length pathnames vs. nesting.
In a quick test with nested-diagnostics-1-truncated.C, it seems like
emacs compile-mode has trouble with the indented source locations. The
singly indented ones it doesn't recognize at all; the doubly indented
ones it correctly identifies as locations, but thinks the file name is
e.g. "default nested-diagnostics-1-truncated.C:25". And it
misidentifies the line
• nested-diagnostics-1-truncated.C: In substitution of
‘template<class auto:1> requires pettable<auto:1> void \
pet(auto:1) [with auto:1 = lizard]’:
as the last :1 being a line number in a very long and strange filename.
I wonder about an option to put source locations at the start of the
line while nesting the actual diagnostics? Possibly before the quoted
source line, to conserve the actual number of lines of output?
21 | void pet(pettable auto t);
| ^~~
• note: template argument deduction/substitution failed:
• note: constraints not satisfied
• P3358R0.C: In substitution of ‘template<class auto:1> requires
pettable<auto:1> void pet(auto:1) [with auto:1 = lizard]’:
• required from here
P3358R0.C:26:6:
26 | pet(lizard{});
| ~~~^~~~~~~~~~
• required for the satisfaction of ‘pettable<auto:1>’ [with auto:1 =
lizard]
Incidentally, the wording of these two context lines seems a bit weird;
we're checking the satisfaction of pet<lizard>, not pettable<lizard>.
The latter is a constraint on the former.
P3358R0.C:19:9:
19 | concept pettable = has_member_pet<T> or has_default_pet<T>;
| ^~~~~~~~
• note: no operand of the disjunction is satisfied
P3358R0.C:19:38:
19 | concept pettable = has_member_pet<T> or has_default_pet<T>;
| ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
• note: the operand ‘has_member_pet<T>’ is unsatisfied because
P3358R0.C:19:20:
19 | concept pettable = has_member_pet<T> or has_default_pet<T>;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
• required for the satisfaction of ‘has_member_pet<T>’ [with T =
lizard]
P3358R0.C:13:9:
13 | concept has_member_pet = requires(T t) { t.pet(); };
| ^~~~~~~~~~~~~~
It would be nice to avoid two lines about has_member_pet in this case.
• required for the satisfaction of ‘pettable<auto:1>’ [with auto:1
= lizard]
P3358R0.C:19:9:
19 | concept pettable = has_member_pet<T> or
has_default_pet<T>;
| ^~~~~~~~
It would be nice to do away with this redundant context that we already
printed above.
• in requirements with ‘T t’ [with T = lizard]
P3358R0.C:13:26:
13 | concept has_member_pet = requires(T t) { t.pet(); };
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
• note: the required expression ‘t.pet()’ is invalid, because
P3358R0.C:13:47:
13 | concept has_member_pet = requires(T t) { t.pet(); };
| ~~~~~^~
• error: ‘struct lizard’ has no member named ‘pet’
P3358R0.C:13:44:
13 | concept has_member_pet = requires(T t) { t.pet(); };
| ~~^~~
• note: the operand ‘has_default_pet<T>’ is unsatisfied because
P3358R0.C:19:41:
19 | concept pettable = has_member_pet<T> or has_default_pet<T>;
| ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
• required for the satisfaction of ‘has_default_pet<T>’ [with T =
lizard]
P3358R0.C:16:9:
16 | concept has_default_pet = T::is_pettable;
| ^~~~~~~~~~~~~~~
• required for the satisfaction of ‘pettable<auto:1>’ [with auto:1
= lizard]
P3358R0.C:19:9:
19 | concept pettable = has_member_pet<T> or
has_default_pet<T>;
| ^~~~~~~~
There's also the broader issue of weird context ordering in g++, where
sometimes we get context from outside in (as expressed by the nesting)
and sometimes from inside out (the "required for" lines), mixed
together. Maybe we could try to avoid printing inside-out context (i.e.
everything added by cp_diagnostic_text_starter) at all when we're
already printing outside-in context? Or use formatting to distinguish
it more clearly?
+++ b/gcc/testsuite/g++.dg/concepts/nested-diagnostics-1-truncated.C
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++17 } }
+// { dg-options "-fconcepts" }
+// { dg-additional-options
"-fdiagnostics-set-output=text:experimental-nesting=yes,experimental-nesting-show-locations=no"
}
+
+struct dog {};
+struct cat {};
+
+void pet(dog);
+void pet(cat);
+
+template <class T>
+concept has_member_pet = requires(T t) { t.pet(); };
+
+template <class T>
+concept has_default_pet = T::is_pettable;
+
+template <class T>
+concept pettable = has_member_pet<T> or has_default_pet<T>;
+
+void pet(pettable auto t);
+
+struct lizard {};
+
+int main() {
+ pet(lizard{}); // { dg-error "no matching function for call to
'pet\\\(lizard\\\)'" }
+}
+
+/* { dg-begin-multiline-output "" }
+ * note: candidate: 'template<class auto:1> requires pettable<auto:1> void
pet(auto:1)'
+ * note: template argument deduction/substitution failed:
+ * note: constraints not satisfied
+ * In substitution of 'template<class auto:1> requires
pettable<auto:1> void pet(auto:1) [with auto:1 = lizard]':
+ * required from here
"required from here" sure seems pointless with no source location...
Anyway, all these comments aren't requests for changes to this patch so
much as thoughts about future directions.
The patch is OK as is.
Jason