Skip to main content
Redhat Developers  Logo
  • Products

    Featured

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat OpenShift AI
      Red Hat OpenShift AI
    • Red Hat Enterprise Linux AI
      Linux icon inside of a brain
    • Image mode for Red Hat Enterprise Linux
      RHEL image mode
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • Red Hat Developer Hub
      Developer Hub
    • View All Red Hat Products
    • Linux

      • Red Hat Enterprise Linux
      • Image mode for Red Hat Enterprise Linux
      • Red Hat Universal Base Images (UBI)
    • Java runtimes & frameworks

      • JBoss Enterprise Application Platform
      • Red Hat build of OpenJDK
    • Kubernetes

      • Red Hat OpenShift
      • Microsoft Azure Red Hat OpenShift
      • Red Hat OpenShift Virtualization
      • Red Hat OpenShift Lightspeed
    • Integration & App Connectivity

      • Red Hat Build of Apache Camel
      • Red Hat Service Interconnect
      • Red Hat Connectivity Link
    • AI/ML

      • Red Hat OpenShift AI
      • Red Hat Enterprise Linux AI
    • Automation

      • Red Hat Ansible Automation Platform
      • Red Hat Ansible Lightspeed
    • Developer tools

      • Red Hat Trusted Software Supply Chain
      • Podman Desktop
      • Red Hat OpenShift Dev Spaces
    • Developer Sandbox

      Developer Sandbox
      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared 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
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

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

      • Developer productivity
      • Developer Tools
      • GitOps
    • Secure Development & Architectures

      • Security
      • Secure coding
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
      • View All Technologies
    • Start exploring in the Developer Sandbox for free

      sandbox graphic
      Try Red Hat's products and technologies without setup or configuration.
    • Try at no cost
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • Java
      Java icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • API Catalog
    • Product Documentation
    • Legacy Documentation
    • Red Hat Learning

      Learning image
      Boost your technical skills to expert-level with the help of interactive lessons offered by various Red Hat Learning programs.
    • Explore Red Hat Learning
  • 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 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 C++ features in GCC 13

June 21, 2023
Marek Polacek
Related topics:
Linux
Related products:
Red Hat Enterprise Linux

Share:

    The latest major version of the GNU Compiler Collection (GCC), 13.1, was released in April 2023. Like every major GCC release, this version brings many additions, improvements, bug fixes, and new features. GCC 13 is already the system compiler in Fedora 38. Red Hat Enterprise Linux (RHEL) users will get GCC 13 in the Red Hat GCC Toolset (RHEL 8 and RHEL 9). It's also possible to try GCC 13 on godbolt.org and similar web pages.

    Like the article I wrote about GCC 10 and GCC 12, this article describes only new features implemented in the C++ front end; it does not discuss developments in the C++ language itself. Interesting changes in the standard C++ library that comes with GCC 13 are described in a separate blog post: New C features in GCC 13

    The default dialect in GCC 13 is -std=gnu++17.  You can use the -std=c++23 or -std=gnu++23 command-line options to enable C++23 features, and similarly for C++20 and others. Note that C++20 and C++23 features are still experimental in GCC 13.

    C++23 features

    This section describes the following new C++23 features:

    • static_assert (false) in templates
    • De-deprecating volatile compound operations
    • Relaxing constexpr restrictions
    • Static operators
    • Extended floating-point types
    • Simpler implicit move
    • Equality operator fix
    • Portable assumptions
    • char8_t compatibility fix
    • Labels at the end of compound statements
    • Traits to detect reference binding to temporary
    • C++ Contracts

    static_assert (false) in templates

    GCC 13 resolves P2593R0 / CWG 2518. The consequence is that a failing static_assert is only ill-formed at instantiation time. In other words, this program compiles without errors in all C++ modes with GCC 13:

    template<typename> void f()
    {
      static_assert (false, "");
    }
    

    because static_assert (false) in uninstantiated templates is now accepted. (GCC 12 rejected the example above.)

    De-deprecating volatile compound operations

    P2327R1 partially reverts C++20 P1152R4, which deprecated many uses of volatile. As a consequence, bit-wise operations on volatile operands no longer warn:

    volatile int vi;
    int i;
    
    void g()
    {
      vi ^= i; // no -Wvolatile warning
      vi |= i; // no -Wvolatile warning
      vi &= i; // no -Wvolatile warning
    }

    The change was backported to GCC 12 and 11 as well, so those versions also don’t warn for the test case above. A related defect report, CWG 2654, was recently approved, meaning that the rest of the compound assignment operators were un-deprecated as well. GCC 13 already implements this defect report, so the warning doesn’t trigger for other compound operations such as +=.

    Relaxing constexpr restrictions

    It’s become customary to relax restrictions about the usage of the constexpr keyword since its introduction in C++11. C++23 doesn’t break this habit. In C++23 (but not earlier modes), P2647R1 allows using static constexpr variables in constexpr functions:

    constexpr char
    test ()
    {
      static constexpr char c[] = "Hello World"; // OK in C++23
      return c[1];
    }
    
    static_assert (test () == 'e');
    

    In a similar vein, P2448R2 brings further constexpr relaxation: in C++23, a constexpr function’s return type or the type of its parameter does not have to be a literal type anymore, and, perhaps more importantly, a constexpr function does not necessarily need to satisfy the requirement of a core constant expression (but actually calling such a function will result in a compile-time error). The intent is to allow functions to be marked constexpr that will later become usable in a constant expression, once other functions that they call become constexpr.

    GCC offers a new option, -Winvalid-constexpr, to get a diagnostic when a function could not be invoked in a constexpr context yet even in C++23 mode.

    void f (int& i);
    constexpr void
    g (int& i)
    {
      f(i); // warns by default in C++20, in C++23 only with -Winvalid-constexpr
    }

    Static operators

    GCC 13 implements both P1169R4 - static operator() and P2589R1 - static operator[]. As the names suggest, these proposals allow the programmer to create a static function call operator and a static subscript operator. Every non-static member function needs to pass the invisible this pointer, which causes additional overhead when such a function is invoked. A static member function avoids the overhead because it doesn’t get the implicit object parameter.

    struct S {
      static constexpr bool operator() (int x, int y) { return x < y; }
    };
    constexpr S s;
    static_assert (s (1, 2));
    
    void g()
    {
      S::operator()(1, 2);  // OK in C++23
    }
    

    Similarly, operator[] can be marked static as well:

    struct S {
      S() {}
      static int& operator[]() { return mem[0]; }
      static int mem[64];
    };
    
    void g()
    {
      S s;
      s[]++;
    }

    Interested readers can read more about the motivation for this change here.

    Extended floating-point types

    Since GCC 13 implements P1467R9, users can now use types such as std::float16_t and similar:

    #include <stdfloat>
    
    int main ()
    {
      std::float16_t f16 = 1.0f16;
      std::float32_t f32 = 2.0f32;
      std::float64_t f64 = 3.0f64;
      std::float128_t f128 = 4.0f128;
    }

    These types are becoming popular in fields like machine learning, computer graphics, weather modelers and similar, where it’s typically required to perform a huge amount of computations, but what precision is important depends on the particular use case. std::float32_t and std::float64_t are available on almost every architecture; std::float16_t is currently available on x86_64, aarch64, and a few other architectures; and std::float128_t is available on architectures that support the __float128/_Float128 types.

    On x86_64 and aarch64, std::bfloat16 is supported as well (the support comes with software emulation as well):

      std::bfloat16_t x = 1.0bf16;

    Simpler implicit move

    The rules mandating implicit move unfortunately keep changing; over the years we have had at least P0527R1, P1155R3, and P1825R0. C++23 brought P2266R3, attempting to simplify the rules. For example, the cumbersome maybe-double overload resolution rule was removed. Additionally, P2266 enabled the implicit move even for functions that return references, e.g.:

    struct X { };
    
    X&& foo (X&& x) {
      return x;
    }
    

    As a consequence, previously valid code may not compile anymore in C++23:

    int& g(int&& x)
    {
      return x; 
    }
    

    Because x is treated as an rvalue in C++23, and it’s not allowed to bind a non-const lvalue reference to an rvalue. For more information, please see the Porting To documentation.

    Equality operator fix

    As a previous blog explained, the implicit reversing of operator== made some valid C++17 code ill-formed in C++20, for instance when a class defines comparison operators that are accidentally asymmetric:

    struct S {
      bool operator==(const S&) { return true; } // mistakenly non-const
      bool operator!=(const S&) { return false; } // mistakenly non-const
    };
    
    bool b = S{} != S{}; // well-formed in C++17, ambiguous in C++20
    

    The problem was that the asymmetric operator== was compared to itself in reverse. GCC implemented a tiebreaker to make the test case above work even in C++20, but the C++ committee resolved the issue in a different way: P2468R2 says that if there is an operator!= with the same parameter types as the operator==, the reversed form of the operator== is ignored. GCC 13 implements the standardized approach.

    Portable assumptions

    GCC 13 gained support for P1774R8, a paper describing how a programmer can use the construct [[assume(expr)]] to allow the compiler to assume that expr is true and optimize the code accordingly. Most compilers already provide a non-standard way to achieve this. For example, GCC supports the __builtin_unreachable built-in function. When used correctly, the resulting code may be both smaller and faster than a version without the [[assume]].

    Consider the following (silly) function:

    int
    foo (int x, int y)
    {
      [[assume (x >= y)]];
      if (x == y)
        return 0;
      else if (x > y)
        return 1;
      else
        return -1;
    }
    

    And the difference in the (x86) output assembly without/with the assume attribute:

    @@ -8,11 +8,7 @@ _Z3fooii:
    .cfi_startproc
    xorl    %eax, %eax
    cmpl    %esi, %edi
    -    je    .L1
    -    setg    %al
    -    movzbl    %al, %eax
    -    leal    -1(%rax,%rax), %eax
    -.L1:
    +    setne    %al
    ret
    .cfi_endproc
     .LFE0:
    

    With the attribute, in this case, all the compiler needs to do is to check if x and y are equal, because it knows it can assume that x cannot be less than y; this results in better output code. Such an optimization is typically the result of the Value Range Propagation optimization taking place.

    Note, however, that if the assumption is violated, the code triggers undefined behavior and the compiler is then free to do absolutely anything, so the attribute should be used sparingly and with great care. Also note that the compiler is free to ignore the attribute altogether.

    char8_t compatibility fix

    P0482R6, which added the char8_t type, didn’t permit

    const char arr[] = u8"hi";

    But that caused problems in practice, so the example above is allowed under P2513R4, which GCC 13 implements.

    Labels at the end of compound statements

    GCC 13 implements proposal P2324R2. C2X (the next major C language standard revision) has started allowing labels at the end of a compound statement (which is, for example, before a function’s final }) without a following ;. The C2X proposal was implemented in GCC 11. To minimize differences between C and C++ in this regard, C++ followed suit:

    void
    p2324 ()
    {
    first:
      int x;
    second:
      x = 1;
    last: // no error in C++23
    }

    Traits to detect reference binding to temporary

    GCC 13 supports P2255R2, which adds two new type traits to detect reference binding to a temporary. They can be used to detect code like

       std::pair<const std::string&, int> p("meow", 1);

    which is incorrect because it always creates a dangling reference, because the std::string temporary is created inside the selected constructor of std::pair, and not outside it. These traits are called std::reference_constructs_from_temporary and std::reference_converts_from_temporary.

    We have made use of these new traits in the standard C++ library to detect buggy code. For example, certain wrong uses of std::function, std::pair, and std::make_from_tuple are now caught and an error is issued.

    Contracts

    Even though C++ Contracts are not in the C++ standard yet (although they briefly were in N4820—see Contract Attributes), GCC 13 implements a draft of C++ Contracts. This feature is highly experimental and has to be enabled by the -fcontracts option. (It also requires that the program is linked with -lstdc++exp.) Here’s an example of the pre feature:

    void f (int x)
      [[ pre: x >= 0 ]]  // line 3
    {
    }
    
    int main ()
    {
      f (1);  // OK
      f (0);  // OK
      f (-1); // oops
    }
    

    This program, when compiled with -fcontracts -std=c++20 and run, will output the following:

    $ ./contracts_demo
    contract violation in function f at g.C:3: x >= 0
    terminate called without an active exception
    Aborted (core dumped)

    Defect report resolutions

    A number of defect reports were resolved in GCC 13. A few examples follow.

    operator[] and default arguments

    P2128R6, which added support for the multidimensional subscript operator, meant to allow default arguments, but accidentally did not. This was fixed in CWG 2507, and the following example compiles in C++23 mode:

    struct A {
      void operator[](int, int = 42);
    };

    attributes on concepts

    Since CWG 2428, it’s permitted to have attributes on concepts:

    template<typename T>
    concept C [[deprecated]] = true;

    consteval in default arguments

    Spurred by problems revolving around the usage of source_location::current, CWG 2631 clarifies that immediate function calls in default arguments are not evaluated until the default argument is used (rather than being evaluated where they are defined, as part of the semantic constraints checking).

    Additional updates

    This section describes other enhancements in GCC 13

    Concepts fixes

    The C++ Concepts code has gotten a lot of bug fixes and a number of loose ends were tied up.

    If you had issues with GCC 12 on concepts-heavy code, chances are GCC 13 will do a much better job.

    Mixing of GNU and standard attributes

    GCC 13 allows mixing GNU and standard (of the [[ ]] form) attributes. Not allowing it caused problems with code, like:

      struct __attribute__ ((may_alias)) alignas (2) struct S { };

    or:

       #define EXPORT __attribute__((visibility("default")))
       struct [[nodiscard]] EXPORT F { };

    Reduced memory usage and compile time

    In GCC 13, we implemented various optimizations that reduce memory usage of the compiler. For example, specialization of nested templated classes has been optimized by reducing the number of unnecessary substitutions. Details can be found here.  Another optimization was to reduce compile time by improving hashing of typenames.

    To improve compile times, the compiler in GCC 13 provides new built-ins which the standard C++ library can use. It is generally faster to use a compiler built-in rather than instantiating a (potentially large) number of class templates and similar. For instance, GCC 13 added __is_convertible and __is_nothrow_convertible, as well as __remove_cv, __remove_reference and __remove_cvref built-ins.

    Another optimization was to reduce the number of temporaries when initializing an array of std::string.

    -nostdlib++

    The C++ front end now understands the new option -nostdlib++, which enables linking without implicitly linking in the C++ standard library.

    -fconcepts option cleaned up

    Previously, -fconcepts in C++17 meant the same thing as -fconcepts-ts (enabling Concepts Technical Specification which allows constructs not allowed by the standard) in C++20. This oddity was cleaned up and now -fconcepts no longer implies -fconcepts-ts prior to C++20. (We recommend using -std=c++20 if your code uses C++ Concepts.)

    New and improved warnings

    GCC's set of warning options have been enhanced in GCC 13.

    -Wparentheses and operator=

    -Wparentheses in GCC 13 warns when an operator= is used as a truth condition:

    struct A {
      A& operator=(int);
      operator bool();
    };
    
    
    void
    f (A a)
    {
      if (a = 0); // warn
    }

    Various std::move warnings improved

    GCC 12 already had a warning which warns about pessimizing uses of std::move in a return statement. (See a related blog post for more on this.) However, the warning didn’t warn about returning a class prvalues, where a std::move also prevents the Return Value Optimization. This has been fixed, and the warning now warns about the std::move in:

    T fn()
    {
      T t;
      return std::move (T{});
    }
    

    as well. Moreover, -Wpessimizing-move warns in more contexts. For example:

       T t = std::move(T());
       T t(std::move(T()));
       T t{std::move(T())};
       T t = {std::move(T())};
       void foo (T);
       foo (std::move(T()));

    A related warning, -Wredundant-move, was extended to warn when the user is moving a const object as in:

    struct T { };
    
    T f(const T& t)
    {
      return std::move(t);
    }
    

    where the std::move is redundant, because T does not have a T(const T&&) constructor (which is very unlikely). Even with the std::move, T(T&&) would not be used because it would mean losing the const qualifier. Instead, T(const T&) will be called.

    New warning: -Wself-move

    Relatedly to the previous paragraph, GCC 13 gained a new warning, which warns about useless “self” moves as in the example below.

       int x = 42;
       x = std::move (x);

    New warning: -Wdangling-reference

    GCC 13 implements a fairly bold new warning to detect bugs in the source code when a reference is bound to a temporary whose lifetime has ended, which is undefined behavior. The canonical example is

     int n = 1;
     const int& r = std::max(n-1, n+1); // r is dangling
    

    where both temporaries (that had been created for n-1 and n+1) were destroyed at the end of the full expression. This warning (enabled by -Wall) detects this problem. It works by employing a heuristic which checks if a reference is initialized by a function call that returns a reference and at least one parameter of the called function is a reference that is bound to a temporary.

    Because the compiler does not check the definition of the called function (and often the definition isn’t even visible), the warning can be fooled, although in practice it doesn’t happen very often. However, there are functions like std::use_facet that take and return a reference but don’t return one of its arguments. In such cases, we suggest suppressing the warning by using a #pragma:

    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wdangling-reference"
    const T& foo (const T&) { ... }
    #pragma GCC diagnostic pop

    Subsequently, the warning was extended to also warn about a common “footgun” concerning std::minmax:

    auto v = std::minmax(1, 2);

    which, perhaps not obviously, also contains a dangling reference: the selected std::minmax overload returns std::pair<const int&, const int&> where the two const int references are bound to temporaries. Since its inception, the warning has been tweaked a number of times. For instance, we adjusted it to ignore reference-like classes, because those tended to provoke false positives.

    New warning: -Wxor-used-as-pow

    This warning warns about suspicious uses of the exclusive OR operator ^. For instance, when the user writes 2^8, it’s likely that they actually meant 1 << 8. To reduce the number of false positives and make the warning useful in practice, it only warns when the first operand is the decimal constant 2 or 10.

    New option: -Wchanges-meaning

    In C++, a name in a class must have the same meaning in the complete scope of the class.  To that effect, GCC 12 emits an -fpermissive error for

    struct A {};
    struct B { A a; struct A { }; }; // error, A changes meaning
    

    In GCC 13, it is possible to disable this particular diagnostic by using the new command-line option -Wchanges-meaning. Having a dedicated option to control this diagnostic is useful because other compilers aren’t as consistent in detecting this invalid code.

    Color function names in diagnostic

    This change can be best demonstrated with a screenshot (Figure 1).

    Function names appear in color in GCC 13.
    Figure 1: C function names formatted in color.

    Acknowledgments

    As usual, I'd like to thank my coworkers at Red Hat who made the GNU C++ compiler so much better, notably Jason Merrill, Jakub Jelinek, Patrick Palka, and Jonathan Wakely.

    Last updated: April 4, 2024

    Related Posts

    • New C features in GCC 13

    • A leaner <iostream> in libstdc++ for GCC 13

    • Improvements to static analysis in the GCC 13 compiler

    • Why you should use io_uring for network I/O

    • Some more C# 11

    • Improvements to static analysis in the GCC 14 compiler

    Recent Posts

    • Assessing AI for OpenShift operations: Advanced configurations

    • OpenShift Lightspeed: Assessing AI for OpenShift operations

    • OpenShift Data Foundation and HashiCorp Vault securing data

    • Axolotl meets LLM Compressor: Fast, sparse, open

    • What’s new for developers in Red Hat OpenShift 4.19

    What’s up next?

    Advanced Linux Commands tile card - updated

    Download the Advanced Linux Commands Cheat Sheet, which  presents a collection of Linux commands and executables for developers who are using the Linux operating system in advanced programming scenarios.

    Get the cheat sheet
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    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

    Red Hat legal and privacy links

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

    Report a website issue