Skip to main content
Redhat Developers  Logo
  • AI

    Get started with AI

    • Red Hat AI
      Accelerate the development and deployment of enterprise AI solutions.
    • AI learning hub
      Explore learning materials and tools, organized by task.
    • AI interactive demos
      Click through scenarios with Red Hat AI, including training LLMs and more.
    • AI/ML learning paths
      Expand your OpenShift AI knowledge using these learning resources.
    • AI quickstarts
      Focused AI use cases designed for fast deployment on Red Hat AI platforms.
    • No-cost AI training
      Foundational Red Hat AI training.

    Featured resources

    • OpenShift AI learning
    • Open source AI for developers
    • AI product application development
    • Open source-powered AI/ML for hybrid cloud
    • AI and Node.js cheat sheet

    Red Hat AI Factory with NVIDIA

    • Red Hat AI Factory with NVIDIA is a co-engineered, enterprise-grade AI solution for building, deploying, and managing AI at scale across hybrid cloud environments.
    • Explore the solution
  • Learn

    Self-guided

    • Documentation
      Find answers, get step-by-step guidance, and learn how to use Red Hat products.
    • Learning paths
      Explore curated walkthroughs for common development tasks.
    • Guided learning
      Receive custom learning paths powered by our AI assistant.
    • See all learning

    Hands-on

    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.
    • Interactive labs
      Learn by doing in these hands-on, browser-based experiences.
    • Interactive demos
      Click through product features in these guided tours.

    Browse by topic

    • AI/ML
    • Automation
    • Java
    • Kubernetes
    • Linux
    • See all topics

    Training & certifications

    • Courses and exams
    • Certifications
    • Skills assessments
    • Red Hat Academy
    • Learning subscription
    • Explore training
  • Build

    Get started

    • Red Hat build of Podman Desktop
      A downloadable, local development hub to experiment with our products and builds.
    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.

    Download products

    • Access product downloads to start building and testing right away.
    • Red Hat Enterprise Linux
    • Red Hat AI
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat Developer Toolset

    References

    • E-books
    • Documentation
    • Cheat sheets
    • Architecture center
  • Community

    Get involved

    • Events
    • Live AI events
    • Red Hat Summit
    • Red Hat Accelerators
    • Community discussions

    Follow along

    • Articles & blogs
    • Developer newsletter
    • Videos
    • Github

    Get help

    • Customer service
    • Customer support
    • Regional contacts
    • Find a partner

    Join the Red Hat Developer program

    • Download Red Hat products and project builds, access support documentation, learning content, and more.
    • Explore the benefits

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

    • SQL Server HA on RHEL: Meet Pacemaker HA Agent v2 (tech preview)

    • Deploy with confidence: Continuous integration and continuous delivery for agentic AI

    • Every layer counts: Defense in depth for AI agents with Red Hat AI

    • Fun in the RUN instruction: Why container builds with distroless images can surprise you

    • Trusted software factory: Building trust in the agentic AI era

    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

    Chat Support

    Please log in with your Red Hat account to access chat support.