master 5d128bf3559: compile.el: Handle GCC 16 nested notes
Sean Whitton <[email protected]>
| Newsgroups | gmane.emacs.diffs |
|---|---|
| Message-ID | <[email protected]> |
branch: master commit 5d128bf35599c012ddc0c5cb9d168f62f621a5ee Author: Arsen Arsenović <[email protected]> Commit: Sean Whitton <[email protected]> compile.el: Handle GCC 16 nested notes * lisp/progmodes/compile.el (compilation-error-regexp-alist-alist): New gcc-nested-notes entry (bug#81308). * etc/compilation.txt (GCC nested notes): New section. --- etc/compilation.txt | 245 ++++++++++++++++++++++++++++++++++++++++++++++ lisp/progmodes/compile.el | 48 +++++++++ 2 files changed, 293 insertions(+) diff --git a/etc/compilation.txt b/etc/compilation.txt index 323ef8cf3c0..e05abc3fa9e 100644 --- a/etc/compilation.txt +++ b/etc/compilation.txt @@ -322,6 +322,251 @@ In file included from /usr/include/c++/3.3/backward/warn.h:4, from /usr/include/c++/3.3/backward/iostream.h:31:0, from test_clt.cc:1: +* GCC nested notes + +symbol: gcc-nested-notes + +Example from https://developers.redhat.com/articles/2026/04/28/gcc-16-improved-error-messages-sarif-output#new_c___error_improvements with and without Unicode + +test.cc:8:6: error: no declaration matches 'void foo::test(int, int, const void*, int)' + 8 | void foo::test(int i, int j, const void *ptr, int k) + | ^~~ + * there is 1 candidate + * candidate is: 'void foo::test(int, int, void*, int)' + test.cc:4:10: + 4 | void test(int i, int j, void *ptr, int k); + | ^~~~ + * parameter 3 of candidate has type 'void*'... + test.cc:4:35: + 4 | void test(int i, int j, void *ptr, int k); + | ~~~~~~^~~ + * ...which does not match type 'const void*' + test.cc:8:42: + 8 | void foo::test(int i, int j, const void *ptr, int k) + | ~~~~~~~~~~~~^~~ +test.cc:1:7: note: 'class foo' defined here + 1 | class foo + | ^~~ + +test.cc:8:6: error: no declaration matches ‘void foo::test(int, int, const void*, int)’ + 8 | void foo::test(int i, int j, const void *ptr, int k) + | ^~~ + • there is 1 candidate + • candidate is: ‘void foo::test(int, int, void*, int)’ + test.cc:4:10: + 4 | void test(int i, int j, void *ptr, int k); + | ^~~~ + • parameter 3 of candidate has type ‘void*’... + test.cc:4:35: + 4 | void test(int i, int j, void *ptr, int k); + | ~~~~~~^~~ + • ...which does not match type ‘const void*’ + test.cc:8:42: + 8 | void foo::test(int i, int j, const void *ptr, int k) + | ~~~~~~~~~~~~^~~ +test.cc:1:7: note: ‘class foo’ defined here + 1 | class foo + | ^~~ + +../../gcc/gcc/cp/module.cc: In member function ‘void {anonymous}::trees_out::type_node(tree)’: +../../gcc/gcc/cp/module.cc:9628:40: error: cannot convert ‘qualifier_set’ to ‘int’ in initialization + 9628 | int quals = type_memfn_quals (type); + | ~~~~~~~~~~~~~~~~~^~~~~~ + | | + | qualifier_set +../../gcc/gcc/cp/module.cc:9635:24: error: no match for ‘operator!=’ (operand types are ‘int’ and ‘qualifier_set’) + 9635 | || quals != type_memfn_quals (root) + | ~~~~~ ^~ ~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | int qualifier_set + • there are 3 candidates + ../../gcc/gcc/cp/module.cc:9635:24: + 9635 | || quals != type_memfn_quals (root) + | ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ +In file included from ../../gcc/gcc/cp/module.cc:215: + • candidate 1: ‘bool operator==(const cp_expr&, tree)’ (reversed) + ../../gcc/gcc/cp/cp-tree.h:126:1: + 126 | operator == (const cp_expr &lhs, tree rhs) + | ^~~~~~~~ + • no known conversion for argument 1 from ‘qualifier_set’ to ‘const cp_expr&’ + ../../gcc/gcc/cp/cp-tree.h:126:29: + 126 | operator == (const cp_expr &lhs, tree rhs) + | ~~~~~~~~~~~~~~~^~~ +In file included from ../../gcc/gcc/coretypes.h:479, + from ../../gcc/gcc/cp/module.cc:214: + • candidate 2: ‘template<class T1, class T2> typename wi::binary_traits<T1, T2>::predicate_result operator!=(const T1&, const T2&)’ + ../../gcc/gcc/wide-int.h:3853:19: + 3853 | BINARY_PREDICATE (operator !=, ne_p) + | ^~~~~~~~ + • in definition of macro ‘BINARY_PREDICATE’ + 3829 | OP (const T1 &x, const T2 &y) \ + | ^~ + • template argument deduction/substitution failed: + • in definition of macro ‘BINARY_PREDICATE’ + 3829 | OP (const T1 &x, const T2 &y) \ + | ^~ + • ../../gcc/gcc/wide-int.h: In substitution of ‘template<class T1, class T2> typename wi::binary_traits<T1, T2>::predicate_result operator!=(const T1&, const T2&) [with T1 = int; T2 = qualifier_set]’: + • required from here + ../../gcc/gcc/cp/module.cc:9635:42: + 9635 | || quals != type_memfn_quals (root) + | ^ + • error: incomplete type ‘wi::int_traits<qualifier_set>’ used in nested name specifier + ../../gcc/gcc/wide-int.h:3853:19: + 3853 | BINARY_PREDICATE (operator !=, ne_p) + | ^~~~~~~~ + • in definition of macro ‘BINARY_PREDICATE’ + 3829 | OP (const T1 &x, const T2 &y) \ + | ^~ +In file included from ../../gcc/gcc/input.h:24, + from ../../gcc/gcc/coretypes.h:507: + • candidate 3: ‘bool operator!=(const expanded_location&, const expanded_location&)’ + ../../gcc/gcc/../libcpp/include/line-map.h:1313:1: + 1313 | operator!= (const expanded_location &a, + | ^~~~~~~~ + • no known conversion for argument 1 from ‘int’ to ‘const expanded_location&’ + ../../gcc/gcc/../libcpp/include/line-map.h:1313:38: + 1313 | operator!= (const expanded_location &a, + | ~~~~~~~~~~~~~~~~~~~~~~~~~^ +../../gcc/gcc/c/c-typeck.cc:8719:38: error: no match for ‘operator|’ (operand types are ‘qualifier_set’ and ‘qualifier_set’) + 8719 | : ((lquals | rquals) == lquals))) + | ~~~~~~ ^ ~~~~~~ + | | | + | | qualifier_set + | qualifier_set + • there are 6 candidates + ../../gcc/gcc/c/c-typeck.cc:8719:38: + 8719 | : ((lquals | rquals) == lquals))) + | ~~~~~~~^~~~~~~~ + • candidate 1: ‘template<class T1, class T2> typename wi::binary_traits<T1, T2>::operator_result operator|(const T1&, const T2&)’ + ../../gcc/gcc/wide-int.h:3855:18: + 3855 | BINARY_OPERATOR (operator |, bit_or) + | ^~~~~~~~ + • in definition of macro ‘BINARY_OPERATOR’ + 3837 | OP (const T1 &x, const T2 &y) \ + | ^~ + • template argument deduction/substitution failed: + • in definition of macro ‘BINARY_OPERATOR’ + 3837 | OP (const T1 &x, const T2 &y) \ + | ^~ + • ../../gcc/gcc/wide-int.h: In substitution of ‘template<class T1, class T2> typename wi::binary_traits<T1, T2>::operator_result operator|(const T1&, const T2&) [with T1 = qualifier_set; T2 = qualifier_set]’: + • required from here + ../../gcc/gcc/c/c-typeck.cc:8719:19: + 8719 | : ((lquals | rquals) == lquals))) + | ^~~~~~ + • error: incomplete type ‘wi::int_traits<qualifier_set>’ used in nested name specifier + ../../gcc/gcc/wide-int.h:3855:18: + 3855 | BINARY_OPERATOR (operator |, bit_or) + | ^~~~~~~~ + • in definition of macro ‘BINARY_OPERATOR’ + 3837 | OP (const T1 &x, const T2 &y) \ + | ^~ + • candidate 2: ‘dump_flags_t operator|(dump_flags_t, dump_flags_t)’ + ../../gcc/gcc/dumpfile.h:212:1: + 212 | operator| (dump_flags_t lhs, dump_flags_t rhs) + | ^~~~~~~~ + • no known conversion for argument 1 from ‘qualifier_set’ to ‘dump_flags_t’ {aka ‘dump_flag’} + ../../gcc/gcc/dumpfile.h:212:25: + 212 | operator| (dump_flags_t lhs, dump_flags_t rhs) + | ~~~~~~~~~~~~~^~~ + • candidate 3: ‘optgroup_flags_t operator|(optgroup_flags_t, optgroup_flags_t)’ + ../../gcc/gcc/dumpfile.h:280:1: + 280 | operator| (optgroup_flags_t lhs, optgroup_flags_t rhs) + | ^~~~~~~~ + • no known conversion for argument 1 from ‘qualifier_set’ to ‘optgroup_flags_t’ {aka ‘optgroup_flag’} + ../../gcc/gcc/dumpfile.h:280:29: + 280 | operator| (optgroup_flags_t lhs, optgroup_flags_t rhs) + | ~~~~~~~~~~~~~~~~~^~~ + • candidate 4: ‘constexpr cv_qualifier operator|(cv_qualifier, cv_qualifier)’ + ../../gcc/gcc/tree-core.h:716:1: + 716 | operator| (cv_qualifier l, cv_qualifier r) + | ^~~~~~~~ + • no known conversion for argument 1 from ‘qualifier_set’ to ‘cv_qualifier’ + ../../gcc/gcc/tree-core.h:716:25: + 716 | operator| (cv_qualifier l, cv_qualifier r) + | ~~~~~~~~~~~~~^ + • candidate 5: ‘constexpr qualifier_set operator|(qualifier_set, cv_qualifier)’ + ../../gcc/gcc/tree.h:2816:1: + 2816 | operator| (qualifier_set qs, cv_qualifier cvs) + | ^~~~~~~~ + • no known conversion for argument 2 from ‘qualifier_set’ to ‘cv_qualifier’ + ../../gcc/gcc/tree.h:2816:43: + 2816 | operator| (qualifier_set qs, cv_qualifier cvs) + | ~~~~~~~~~~~~~^~~ + • candidate 6: ‘constexpr qualifier_set operator|(cv_qualifier, qualifier_set)’ + ../../gcc/gcc/tree.h:2822:1: + 2822 | operator| (cv_qualifier cvs, qualifier_set qs) + | ^~~~~~~~ + • no known conversion for argument 1 from ‘qualifier_set’ to ‘cv_qualifier’ + ../../gcc/gcc/tree.h:2822:25: + 2822 | operator| (cv_qualifier cvs, qualifier_set qs) + | ~~~~~~~~~~~~~^~~ + +The g++.dg/diagnostic/pr100716.C example has some more complex cases: + +pr100716.C: In function ‘int main()’: +pr100716.C:34:13: error: no matching function for call to ‘A<int>::f(int)’ + 34 | A<int>().f(0); // { dg-error "no matching function for call to 'A<int>::f\\(int\\)'" } + | ~~~~~~~~~~^~~ + • there is 1 candidate + • candidate 1: ‘template<class U> void A<T>::f() [with T = int]’ + pr100716.C:7:12: + 7 | void f() {} // { dg-line Af } + | ^ + • candidate expects 0 arguments, 1 provided +pr100716.C:37:13: error: no matching function for call to ‘A<int>::g()’ + 37 | A<int>().g(); // { dg-error "no matching function for call to 'A<int>::g\\(\\)'" } + | ~~~~~~~~~~^~ + • there is 1 candidate + • candidate 1: ‘template<class U> void A<T>::g(U) [with T = int]’ + pr100716.C:10:12: + 10 | void g(U) {} // { dg-line Ag } + | ^ + • candidate expects 1 argument, 0 provided +pr100716.C:40:13: error: no matching function for call to ‘B<int>::f()’ + 40 | B<int>().f(); // { dg-error "no matching function for call to 'B<int>::f\\(\\)'" } + | ~~~~~~~~~~^~ + • there is 1 candidate + • candidate 1: ‘template<class U> void B<T>::f(U) [with T = int]’ + pr100716.C:17:12: + 17 | void f(U) {} // { dg-line Bf } + | ^ + • candidate expects 1 argument, 0 provided +pr100716.C:43:13: error: no matching function for call to ‘B<int>::g()’ + 43 | B<int>().g(); // { dg-error "no matching function for call to 'B<int>::g\\(\\)'" } + | ~~~~~~~~~~^~ + • there is 1 candidate + • candidate 1: ‘template<class U> void B<T>::g(U, T) [with T = int]’ + pr100716.C:20:12: + 20 | void g(U, T) {} // { dg-line Bg } + | ^ + • candidate expects 2 arguments, 0 provided +pr100716.C:46:15: error: no matching function for call to ‘B<float>::g(int)’ + 46 | B<float>().g(0); // { dg-error "no matching function for call to 'B<float>::g\\(int\\)'" } + | ~~~~~~~~~~~~^~~ + • there is 1 candidate + • candidate 1: ‘template<class U> void B<T>::g(U, T) [with T = float]’ + pr100716.C:20:12: + 20 | void g(U, T) {} // { dg-line Bg } + | ^ + • candidate expects 2 arguments, 1 provided +pr100716.C:49:8: error: no matching function for call to ‘C::f()’ + 49 | C().f(); // { dg-error "no matching function for call to 'C::f\\(\\)'" } + | ~~~~~^~ + • there is 1 candidate + • candidate 1: ‘template<class U> void C::f(U)’ + pr100716.C:26:10: + 26 | void f(U) {} // { dg-line Cf } + | ^ + • candidate expects 1 argument, 0 provided +pr100716.C:52:8: error: no matching function for call to ‘C::g(int)’ + 52 | C().g(0); // { dg-error "no matching function for call to 'C::g\\(int\\)'" } + | ~~~~~^~~ + • there is 1 candidate + • candidate 1: ‘template<class U> void C::g()’ + pr100716.C:29:10: + 29 | void g() {} // { dg-line Cg } + | ^ + • candidate expects 0 arguments, 1 provided * GNU style diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el index df6a3a4250b..8d5a5df766a 100644 --- a/lisp/progmodes/compile.el +++ b/lisp/progmodes/compile.el @@ -476,6 +476,54 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1)) ;; so don't try to match it. ": \\*\\*\\* \\[\\(\\(.+?\\):\\([0-9]+\\): .+\\)\\]" 2 3 nil 0 1) + (gcc-nested-notes + ;; GCC 16 and onwards can produce messages that have structured and + ;; elaborate nested notes. These messages are, in fact, + ;; informative, and not errors unto themselves. + ;; + ;; The issue is that these messages can include locations (and + ;; indeed do include a location by default), which Emacs may + ;; misconstrue as a new diagnostic. So, catch it early, to + ;; consider it an informative message. + ,(rx + bol + ;; The structure of these messages is something like: + ;; INDENT BULLET MESSAGE \n + ;; INDENT LOCATION + ;; ... where INDENT are spaces, BULLET is either an ASCII star or + ;; a Unicode bullet (U+2022), MESSAGE is informative text and + ;; LOCATION is the usual FILE:LINE:COL coordinate. + ;; + ;; Sample: + ;; • candidate is: ‘void foo::test(int, int, void*, int)’ + ;; test.cc:4:10: + ;; 4 | void test(int i, int j, void *ptr, int k); + + ;; Match first line. + (group-n 9 (+ " ")) (| ?* ?\N{BULLET}) space (* nonl) (+ (any "\r\n")) + + ;; Match second line. + (backref 9) " " + ;; File name group, from `gnu' rule. + (group-n 1 + ;; Avoid matching the file name as a program in the pattern + ;; above by disallowing file names entirely composed of digits. + ;; Do not allow file names beginning with a space. + (| (not (in "0-9" "\n\t ")) + (: (+ (in "0-9")) + (not (in "0-9" "\n")))) + ;; A file name can be composed of any non-newline char, but + ;; rule out some valid but unlikely cases, such as a trailing + ;; space or a space followed by a -, or a colon followed by a + ;; space. + (*? (| (not (in "\n :")) + (: " " (not (in ?- "/\n"))) + (: ":" (not (in " \n")))))) + ?: (group-n 2 (+ (in "0-9"))) ; Line + ?: (group-n 3 (+ (in "0-9"))) ; Column + ?:) + 1 2 3 0) + (gnu ;; The `gnu' message syntax is ;; [PROGRAM:]FILE:LINE[-ENDLINE]:[COL[-ENDCOL]:] MESSAGE