New features in GCC 16: Improved error messages and SARIF output | Red Hat Developer
Skip to main content
Search
Search
All Red Hat
New features in GCC 16: Improved error messages and SARIF output
April 28, 2026
David Malcolm
Related topics:<br>C, C#, C++CompilersDeveloper toolsLinuxSecure coding
Related products:<br>Red Hat Enterprise Linux
Table of contents:
I work at Red Hat on the GNU Compiler Collection (GCC). GCC 16 is about to be released, so I'm sharing some of the new features I worked on this year. Some changes are visible to users, while others improve the system more subtly.<br>New C++ error improvements<br>A well-known challenge for C++ developers is the readability of template-related error messages. C++ compilers tend to either provide too little information or spew screenfuls of text at you. Either way, the errors can be difficult to decipher.<br>GCC error messages have a hierarchical structure to them. In GCC 15, I added an experimental option that shows this structure as a collection of nested bullet points.<br>In GCC 16, this behavior is now the default. You can return to the previous behavior using -fno-diagnostics-show-nesting or -fdiagnostics-plain-output. I fixed several bugs and made use of the hierarchical structure in more places. For example, it is easy to get declarations and definitions out of sync when manually adding const to a parameter:<br>class foo<br>public:<br>void test(int i, int j, void *ptr, int k);<br>};
// Wrong "const"-ness of param 3.<br>void foo::test(int i, int j, const void *ptr, int k)<br>}In GCC 15, we emitted the following output:<br>:8:6: error: no declaration matches 'void foo::test(int, int, const void*, int)'<br>8 | void foo::test(int i, int j, const void *ptr, int k)<br>| ^~~<br>:4:10: note: candidate is: 'void foo::test(int, int, void*, int)'<br>4 | void test(int i, int j, void *ptr, int k);<br>| ^~~~<br>:1:7: note: 'class foo' defined here<br>1 | class foo<br>| ^~~In GCC 16, we now emit this:<br>:8:6: error: no declaration matches 'void foo::test(int, int, const void*, int)'<br>8 | void foo::test(int i, int j, const void *ptr, int k)<br>| ^~~<br>• there is 1 candidate<br>• candidate is: 'void foo::test(int, int, void*, int)'<br>:4:10:<br>4 | void test(int i, int j, void *ptr, int k);<br>| ^~~~<br>• parameter 3 of candidate has type 'void*'...<br>:4:35:<br>4 | void test(int i, int j, void *ptr, int k);<br>| ~~~~~~^~~<br>• ...which does not match type 'const void*'<br>:8:42:<br>8 | void foo::test(int i, int j, const void *ptr, int k)<br>| ~~~~~~~~~~~~^~~<br>:1:7: note: 'class foo' defined here<br>1 | class foo<br>| ^~~This pinpoints the exact location of the problem. Use this Compiler Explorer link to see how color highlights and contrasts mismatched types in both the messages and the quoted source code.<br>Updated SARIF machine-readable output<br>By default, GCC writes its diagnostics (errors and warnings) as text to stderr. Parsing this output with regular expressions has become difficult as the compiler's capabilities have grown. In GCC 13, I added the ability to write diagnostics in machine-readable form using the Static Analysis Results Interchange Format (SARIF). This JSON-based format allows us to separate the data of the diagnostic from the way the diagnostic is presented.<br>GCC 16 includes several improvements to the generated SARIF output. For example, when reporting a missing return *this in an assignment operator:<br>namespace foo {<br>namespace bar {<br>class foo {<br>foo&<br>operator= (const foo &other)<br>m_val = other.m_val;<br>int m_val;<br>};<br>} // namespace bar<br>} // namespace foo The SARIF output now captures the nested structure of logical locations. This allows a SARIF viewer to filter for diagnostics within the foo::bar namespace:<br>"logicalLocations": [{"name": "foo",<br>"fullyQualifiedName": "foo",<br>"kind": "namespace",<br>"index": 0},<br>{"name": "bar",<br>"fullyQualifiedName": "foo::bar",<br>"kind": "namespace",<br>"parentIndex": 0,<br>"index": 1},<br>{"name": "baz",<br>"kind": "type",<br>"parentIndex": 1,<br>"index": 2},<br>{"name": "operator=",<br>"fullyQualifiedName": "foo::bar::baz::operator=",<br>"decoratedName": "_ZN3foo3bar3bazaSERKS1_",<br>"kind": "function",<br>"parentIndex": 2,<br>"index": 3}]GCC 16 also adds data to SARIF output to better express non-standard control flow (such as exception-handling and longjmp) within code paths. This data is included in the upcoming SARIF 2.2 standard.<br>New HTML output option<br>In GCC 15, I added -fdiagnostics-add-output= to allow for multiple kinds of diagnostic output simultaneously. Plain text output has limitations, so GCC 16 includes a new experimental-html option.<br>Figure 1 shows the first example using -fdiagnostics-add-output=experimental-html.
Figure 1: An experimental HTML diagnostic in GCC 16 showing a "no declaration matches" error with highlighted code snippets and callouts.
You can see the full generated page here.<br>As the name suggests, this feature is experimental, but I've already found it helpful for debugging the GCC built-in static analyzer. When you enable the tool with the -fanalyzer option, it explores interprocedural paths through...