Porting to GCC 10

The GCC 10 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 10. This document is an effort to identify common issues and provide solutions. Let us know if you have suggestions for improvements!

C language issues

Default to -fno-common

A common mistake in C is omitting extern when declaring a global variable in a header file. If the header is included by several files it results in multiple definitions of the same variable. In previous GCC versions this error is ignored. GCC 10 defaults to -fno-common, which means a linker error will now be reported. To fix this, use extern in header files when declaring global variables, and ensure each global is defined in exactly one C file. If tentative definitions of particular variables need to be placed in a common block, __attribute__((__common__)) can be used to force that behavior even in code compiled without -fcommon. As a workaround, legacy C code where all tentative definitions should be placed into a common block can be compiled with -fcommon.


      int x;  // tentative definition - avoid in header files

      extern int y;  // correct declaration in a header file
  

C++ language issues

Header dependency changes

Some C++ Standard Library headers have been changed to no longer include the <stdexcept> header. As such, C++ programs that used components defined in <stdexcept> or <string> without explicitly including the right headers will no longer compile.

Previously components such as std::runtime_error, std::string and std::allocator were implicitly defined after including unrelated headers such as <array> and <optional>. Correct code should include the appropriate headers for the classes being used.

Fortran language issues

Argument mismatches

GCC 10 now rejects argument mismatches occurring in the same source file. Those are not permitted by the Fortran standard and in general have the potential to generate invalid code. However, the Fortran standard does permit passing an array element or a scalar string (of default character kind or of c_char kind) as actual argument to an array dummy argument. (For the exact wording, see the Fortran standard on argument association; in particular, Fortran 2018, Sect. 15.5.2.4, Para. 4.)

Depending on their nature, argument mismatches have the potential to cause the generation of invalid code and, hence, should be investigated. The most common reason that code fails due to newly enforced check is the following: instead of using an array element as actual argument, a scalar is used; one solution is to replace the scalar by a size-one array. (This should be passed as a whole as there is no point in passing it as array element.) Additionally, check that the code indeed only accesses this single element. — Other mismatches occur more rarely but usually indicate more serious bugs where a wrong result is likely (at least for some target-platform and optimization combination).

If short-term fixing of those issues is not feasible, the compiler flag -fallow-argument-mismatch (implied by -std=legacy) downgrades the error to a warning.

Example: Assume a subroutine which takes an assumed-size or explicit-size array and the array size as another argument, such as


      subroutine sub_assumed(array, n)
        real array(*)
        integer n
        …
      end

      subroutine another_explicit(array, n)
        integer n
        real array(n)
        …
      end

An invalid but comparably common use is to pass scalar to such procedures:


      real var
      …
      call sub_assumed(var, 1)

This can be fixed in several ways. The simplest and most localized one is the following; the scalar is replaced by an array. In the second subroutine, it is assumed that the argument is both read from and written to. In the third procedure, a single number is passed, which is assumed to be only accessed for reading. (Note: By adding the brackets, a Fortran 66 or 77 compiler can no longer compile it.)


      subroutine caller()
        real var(1)
        …
        call sub_assumed(var, 1)
      end

      subroutine caller_arg(var)
        real var
        real var2(1)var2(1) = var
        call sub_assumed(var2, 1)
        var = var2(1)
      end

      subroutine caller_readonly(var)
        …
! Before: var = func(42.0, 1)
        var = func([42.0], 1)