Porting to GCC 16

The GCC 16 release series differs from previous GCC releases in a number of ways. Some of these are a result of bug fixing, and some old behaviors have been intentionally changed to support new standards, or relaxed in standards-conforming ways to facilitate compilation or run-time performance.

Some of these changes are user visible and can cause grief when porting to GCC 16. This document is an effort to identify common issues and provide solutions. Let us know if you have suggestions for improvements!

Common C and C++ language issues

Changes to -Wunused-but-set-* warnings

Since GCC 16, -Wunused-but-set-* warning options have been extended to have multiple levels controlling what kinds of uses disable the warnings for variables which are otherwise unused. Older versions of GCC only implemented what has become -Wunused-but-set-variable=1 or -Wunused-but-set-parameter=1, while the new default for -Wunused-but-set-variable or -Wunused-but-set-parameter is =3 (the new defaults are also used when these warnings are enabled by -Wall or -Wextra, respectively). =2 ignores pre/post inc/decrements on the variable, =3 also ignores compound assignments if the LHS variable is not also used on the RHS.


void foo (void) {
  int a = 1; // -Wunused-variable warning
  int b = 0; // Warning for -Wunused-but-set-variable=n n >= 1
  b = 1; b = 2;
  int c = 0; // Warning for -Wunused-but-set-variable=n n >= 2
  ++c; c--; --c; c++;
  int d = 0; // Warning for -Wunused-but-set-variable=n n >= 3
  d += 4;
  int e = 0; // No warning, cast to void
  (void) e;
  int f = 0; // No warning, f used
  int g = f = 5;
  (void) g;
  int h = 0; // No warning, preincrement result used
  int i = ++h;
  (void) i;
  int j = 0; // No warning, postdecrement result used
  int k = j--;
  (void) k;
  int l = 0; // No warning, l used
  int m = l |= 2;
  (void) m;
}

In order to avoid the warnings, one can either remove newly diagnosed variables or parameters which aren't used except in pre/post inc/decrements or compound assignments, make them used in some way, e.g. just casting to (void), or lowering the level of the warning. But note that an unused variable may indicate a coding error, where some other object was mistakenly used in its place, or a larger change was begun but left incomplete. See -Wunused-but-set-* documentation for more details.

C++ language issues

All GCC releases make improvements to conformance which may reject non-conforming, legacy codebases. Other issues arise from C++20 becoming the default choice of published Standard to follow (as might have been overridden with, e.g., -std=c++20), and changes in C++20 from previous Standards.

Deprecated features removed in C++20

In the transition from C++17 to C++20, several features that had been deprecated have been removed from the Standard. These are summarized at the top of Changes between C++17 and C++20 DIS ["Draft International Standard"]. Note that names removed from C++20 may still appear in headers when building under -std=c++20, and only provoke 'deprecated' warnings.

C++ build failures

Ambiguous overload for operator!=

In C++20, a type that defines operator== gets an operator!= provided implicitly by the compiler. This can cause ambiguities if the type also defines its own operator!= with an unconventional signature, such as only supporting comparisons of non-const types (often a mistake, because comparison typically does not require altering its arguments). This provokes errors like:

 error: ambiguous overload for 'operator!=' (operand types are 'daeStringRef' and 'long int')

Fixing argument-type signatures is often the simplest fix, but more complicated cases may require adding or removing overloads.

No match for operator>>

In C++20, the operator>> overload for reading from an istream into a char* was removed because it offers no way to prevent buffer overrun when reading into a buffer of unspecified size. This results in errors like:

 error: no match for 'operator>>' (operand types are 'std::istream' {aka 'std::basic_istream<char>'} and 'char*')

A fix is to read into a native array, which uses the bound to prevent overrun and leaves any extra characters unread, or to read into an std::string, which grows as needed.

Program uses features from a newer Standard

Many failures are caused by a spurious build option -std=gnu++11:

 error: 'make_unique' is not a member of 'std'

This is usually a consequence of a bug in Autoconf prior to release 2.73 that adds this option to Makefiles when, acting on a directive AC_PROG_CXX, it tries but fails to verify that GCC 16's compiler supports C++11 language features by default. To work around that, remove the AC_PROG_CXX directive from the program's configure.ac file and regenerate the makefiles.

Expected identifier before

C++20 defines new keywords such as concept and requires, which can no longer be used as identifiers:

 error: expected identifier before 'concept'

The only solutions are to change the name of the identifier, or build to an older standard with (e.g.) -std=c++17.

Implicit lambda capture of 'this'

C++20 deprecates implicitly capturing the value of the meta-variable this in saved lambda state, provoking warnings if member names from the surrounding context are used in the lambda body:

 warning: implicit capture of 'this' via '[=]' is deprecated in C++20

These can be resolved by adding this or *this, as appropriate, to the capture list, such as by [=,this].

Changes to character literals

In C++20, u8"str" and u8'c' literals changed from type char to type char8_t, leading to errors like:

 error: invalid conversion from 'const char8_t*' to 'const char*' [-fpermissive]

The fix is most commonly a cast from the u8 literal to plain char or char const*.

Missing header includes

Programs sometimes use names without having properly #included the header that declares them, relying instead on the name having being declared incidentally via some other header; until it no longer does, resulting in errors like:

 error: 'uint64_t' was not declared in this scope

These are fixed by identifying which header declares the name, and including that. The compiler may suggest the header to include.

Has no member named destroy

In C++20, many deprecated member functions and member typedefs of std::allocator were removed because std::allocator_traits has since C++11 provided better defaults for those members that should be used instead. This applies to former members pointer, const_pointer, reference, const_reference, construct, destroy, rebind, is_always_equal, and max_size.

The solution is to use (e.g.) std::allocator_traits<A>::destroy in place of A::destroy.

Operating Systems

Solaris

Changes affecting plugin authors

GCC's diagnostic machinery has been substantially cleaned up in GCC 16. Most of the implementation has been moved to a new gcc/diagnostics/ subdirectory and diagnostics:: namespace, with many fields becoming private. This should not affect plugins that use just the diagnostic-core.h API, but plugins making more sophisticated uses of diagnostics may need updating. The following tables list the types that have been renamed in GCC 16 and the header files that have been moved.

Renamed types
GCC 15 type GCC 16 type Notes
class diagnostic_buffer class diagnostics::buffer
class diagnostic_client_data_hooks class diagnostics::client_data_hooks
class diagnostic_client_plugin_info class diagnostics::client_plugin_info
class diagnostic_column_policy class diagnostics::column_policy
class diagnostic_context class diagnostics::context
struct diagnostic_counters struct diagnostics::counters New header: diagnostics/counters.h
class diagnostic_diagram class diagnostics::diagram
class diagnostic_event class diagnostics::paths::event
class diagnostic_event_id_t class diagnostics::paths::event_id_t
struct diagnostic_info struct diagnostics::diagnostic_info Fields have gained m_ prefixes
class diagnostic_location_print_policy class diagnostics::location_print_policy
class diagnostic_metadata class diagnostics::metadata
class diagnostic_option_classifier class diagnostics::option_classifier
struct diagnostic_option_id struct diagnostics::option_id New header: diagnostics/option-id.h
class diagnostic_option_manager class diagnostics::option_manager
class diagnostic_output_file class diagnostics::output_file
class diagnostic_output_format class diagnostics::sink
class diagnostic_per_format_buffer class diagnostics::per_sink_buffer
struct diagnostic_source_printing_options struct diagnostics::source_printing_options
class diagnostic_source_print_policy class diagnostics::source_print_policy
enum diagnostic_t enum class diagnostics::kind
class diagnostic_text_output_format class diagnostics::text_sink
class diagnostic_thread class diagnostics::paths::thread
typedef diagnostic_thread_id_t typedef diagnostics::paths::thread_id_t
class diagnostic_path class diagnostics::paths::path
class edit_context class diagnostics::changes::change_set
class logical_location class diagnostics::logical_locations::key
enum logical_location_kind enum diagnostics::logical_locations::kind
class logical_location_manager class diagnostics::logical_locations::manager
class sarif_output_format class diagnostics::sarif_sink
class diagnostic_sarif_format_buffer class diagnostics::sarif_sink_buffer
class option_manager class diagnostics::option_id_manager New header: diagnostics/option-id-manager.h
Header file changes
GCC 15 header GCC 16 header
diagnostic-buffer.h diagnostics/buffering.h
diagnostic-client-data-hooks.h diagnostics/client-data-hooks.h
diagnostic-color.h diagnostics/color.h
diagnostic.def diagnostics/kind.def
diagnostic-diagram.h diagnostics/diagram.h
diagnostic-format-html.h diagnostics/html-sink.h
diagnostic-format-sarif.h diagnostics/sarif-sink.h
diagnostic-format-text.h diagnostics/text-sink.h
diagnostic-label-effects.h diagnostics/source-printing-effects.h
diagnostic-macro-unwinding.h diagnostics/macro-unwinding.h
diagnostic-metadata.h diagnostics/metadata.h
diagnostic-output-file.h diagnostics/output-file.h
diagnostic-path.h diagnostics/paths.h
diagnostic-url.h diagnostics/url.h
edit-context.h diagnostics/changes.h
File cache types of input.h diagnostics/file-cache.h
logical-locations.h diagnostics/logical-locations.h