Skip to main content
Redhat Developers  Logo
  • Products

    Platforms

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat AI
      Red Hat AI
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • See all Red Hat products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat Developer Hub
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat OpenShift Local
    • Red Hat Developer Sandbox

      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Red Hat OpenShift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • See all technologies
    • Programming languages & frameworks

      • Java
      • Python
      • JavaScript
    • System design & architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer experience

      • Productivity
      • Tools
      • GitOps
    • Automated data processing

      • AI/ML
      • Data science
      • Apache Kafka on Kubernetes
    • Platform engineering

      • DevOps
      • DevSecOps
      • Red Hat Ansible Automation Platform for applications and services
    • Secure development & architectures

      • Security
      • Secure coding
  • Learn

    Featured

    • Kubernetes & cloud native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • AI/ML
      AI/ML Icon
    • See all learning resources

    E-books

    • GitOps cookbook
    • Podman in action
    • Kubernetes operators
    • The path to GitOps
    • See all e-books

    Cheat sheets

    • Linux commands
    • Bash commands
    • Git
    • systemd commands
    • See all cheat sheets

    Documentation

    • Product documentation
    • API catalog
    • Legacy documentation
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore the Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

New features in GCC 16: Improved error messages and SARIF output

April 28, 2026
David Malcolm
Related topics:
C, C#, C++CompilersDeveloper toolsLinuxSecure coding
Related products:
Red Hat Enterprise Linux

    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.

    New C++ error improvements

    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.

    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.

    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:

    class foo
    {
      public:
        void test(int i, int j, void *ptr, int k);
    };
        
    // Wrong "const"-ness of param 3.
    void foo::test(int i, int j, const void *ptr, int k)
    {
    }

    In GCC 15, we emitted the following output:

    <source>: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)
          |      ^~~
    <source>:4:10: note: candidate is: 'void foo::test(int, int, void*, int)'
        4 |     void test(int i, int j, void *ptr, int k);
          |          ^~~~
    <source>:1:7: note: 'class foo' defined here
        1 | class foo
          |       ^~~

    In GCC 16, we now emit this:

    <source>: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)'
          <source>:4:10:
              4 |     void test(int i, int j, void *ptr, int k);
                |          ^~~~
          • parameter 3 of candidate has type 'void*'...
            <source>:4:35:
                4 |     void test(int i, int j, void *ptr, int k);
                  |                             ~~~~~~^~~
          • ...which does not match type 'const void*'
            <source>:8:42:
                8 | void foo::test(int i, int j, const void *ptr, int k)
                  |                              ~~~~~~~~~~~~^~~
    <source>:1:7: note: 'class foo' defined here
        1 | class foo
          |       ^~~

    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.

    Updated SARIF machine-readable output

    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.

    GCC 16 includes several improvements to the generated SARIF output. For example, when reporting a missing return *this in an assignment operator:

    namespace foo { 
    namespace bar { 
    class foo { 
      foo&
      operator= (const foo &other)
      {
        m_val = other.m_val;
      }
      int m_val;
    };
    } // namespace bar
    } // 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:

               "logicalLocations": [{"name": "foo",
                                     "fullyQualifiedName": "foo",
                                     "kind": "namespace",
                                     "index": 0},
                                    {"name": "bar",
                                     "fullyQualifiedName": "foo::bar",
                                     "kind": "namespace",
                                     "parentIndex": 0,
                                     "index": 1},
                                    {"name": "baz",
                                     "kind": "type",
                                     "parentIndex": 1,
                                     "index": 2},
                                    {"name": "operator=",
                                     "fullyQualifiedName": "foo::bar::baz::operator=",
                                     "decoratedName": "_ZN3foo3bar3bazaSERKS1_",
                                     "kind": "function",
                                     "parentIndex": 2,
                                     "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.

    New HTML output option

    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.

    Figure 1 shows the first example using -fdiagnostics-add-output=experimental-html.

    Screeenshot of Firefox showing HTML output
    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.

    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 your source code to find bugs at compile time. I often need to debug fiddly issues in this code, and the more visualization the better. The HTML output displays nested stack frames in an execution path, using drop shadows to represent the stack visually (Figure 2).

    Screenshot of Firefox showing visualization of interprocedural control flow
    Figure 2: Experimental HTML output from the GCC static analyzer, illustrating a 26-event execution path with nested frames and visual drop shadows to represent the call stack.

    The full example is here. This version also includes an easter egg (generated via -fdiagnostics-add-output=experimental-html:show-state-diagrams=yes). If you press j and k, you can move forward and backward through the path, with diagrams showing the predicted state of memory at each event, and what pointers are pointing to what buffers (Figure 3).

    Screenshot of Firefox showing state visualization
    Figure 3: An experimental GCC state diagram visualizing the heap and stack memory transitions, illustrating a pointer referencing a freed buffer.

    Static analyzer improvements

    The visualization made it easier to spot and fix problems in the analyzer, leading to several internal improvements in GCC 16. The analyzer's core data structure for tracking code (the "supergraph") had become difficult to work with, with various dark corners for bugs to hide in. I've rewritten it in GCC 16. The new code has much clearer separation of concerns (between places in the user's code versus operations that occur on the transitions between these places), and I'm already finding it makes it easier to add new features.

    I also updated the data structure that tracks simulated memory buffer contents, replacing a rather clunky hashing approach with a simple std::map from bit ranges to contents. The new approach is both easier to understand and faster.

    My colleague Andrew MacLeod has spent several years on a project called Ranger to improve how GCC tracks properties of values in the user's code for use by the optimizer. This covers things such as knowing whether a given integer is in the valid range to be used as an array index, or whether individual bits are known to be true or false. In GCC 16 I've started wiring up -fanalyzer to these data structures. Like the above changes, this is unlikely to be directly visible, but should lead to more accurate analysis and fewer false positives.

    Before GCC 16, -fanalyzer only worked on C code; running it on C++ code often produced irrelevant results. The problem was that my code was ignoring how GCC internally represents (a) exception-handling, leading to it inventing impossible paths through the code, and (b) C++'s Named Return Value Optimization (NRVO), leading to lots of false reports about supposed memory leaks.

    I have good news and bad news here. The good news: In GCC 16, I implemented exception handling and the NRVO, allowing -fanalyzer to work with C++ code. 

    The bad news is that the feature is currently limited to small examples. Running it on complex code might cause scaling issues where the analyzer spends its entire analysis budget on a small fraction of the code and gives up, burning CPU cycles without generating useful results. False positives have been replaced by false negatives, and so I still can't recommend using it on C++ code. It's better to be correct than to be fast, and I'm looking at ways of scaling things up for GCC 17 in the hope of making -fanalyzer be practical for use on production C++.

    Try GCC 16

    These features are just a small sample of the many improvements in GCC 16, which is about to be officially released upstream. You can try the new version now in Compiler Explorer; as I write this, it's listed as GCC trunk. Putting my downstream hat on, you can also try it in Fedora 44. Have fun!

    Related Posts

    • GCC and gcc-toolset versions in RHEL: An explainer

    • 6 usability improvements in GCC 15

    • How to implement C23 #embed in GCC 15

    • Monitor GCC compile time

    • New C++ features in GCC 14

    • Improvements to static analysis in the GCC 14 compiler

    Recent Posts

    • New features in GCC 16: Improved error messages and SARIF output

    • OpenShift AI observability summarizer: Transform metrics into meaning

    • Build .NET container images with Tekton

    • Exploring distroless containers with Project Hummingbird

    • Deploy hosted control planes with OpenShift Virtualization: Split hub

    What’s up next?

    Share graphics_advanced Linux commands

    Advanced Linux commands cheat sheet

    Bob Reselman
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Build

    • Developer Sandbox
    • Developer tools
    • Interactive tutorials
    • API catalog

    Quicklinks

    • Learning resources
    • E-books
    • Cheat sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site status dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2026 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility