The GCC 9 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 9. This document is an effort to identify common issues and provide solutions. Let us know if you have suggestions for improvements!
The C standard says that compound literals which occur inside of the body of a function have automatic storage duration associated with the enclosing block. Older GCC releases were putting such compound literals into the scope of the whole function, so their lifetime actually ended at the end of containing function. This has been fixed in GCC 9. Code that relied on this extended lifetime needs to be fixed, move the compound literals to whatever scope they need to accessible in.
struct S { int a, b; };
int foo(void) {
// The following line no longer compiles
struct S *p = &({ (struct S) { 1, 2 }; });
struct S *q;
{
q = &(struct S) { 3, 4 };
}
// This is invalid use after lifetime of the compound literal
// ended.
return q->b;
}
GCC releases before 9 were implementing an OpenMP 3.1 data sharing rule
that const
qualified variables without mutable
member are predetermined shared, but as an exception may be specified
in the firstprivate
clause. OpenMP 4.0 dropped this rule,
but in the hope that this incompatible change will be reverted GCC kept
the previous behavior. Now that for OpenMP 5.0 it has been
confirmed this is not going to change, GCC 9 started implementing the
OpenMP 4.0 and later behavior. When not using a default
clause or when using default(shared)
, this makes no
difference. When using default(none)
, previously the
choice was not to specify const
qualified variables
on the construct at all, or specify them in the
firstprivate
clause.
In GCC 9 as well as for OpenMP 4.0 compliance those variables need
to be specified on constructs in which they are used, either in a
shared
or in a firstprivate
clause. Specifying
them in a firstprivate
clause is one way to achieve
compatibility with both older GCC versions and GCC 9. Another option
is to drop the default(none)
clause. In C++,
const
variables with constant initializers which are not
odr-used in the region, but replaced with their constant initializer,
are not considered to be referenced in the region for
default(none)
purposes.
int get (void);
void use (int);
void foo (void) {
const int a = get ();
const int b = 1;
#pragma omp parallel for default(none)
for (int i = 0; i < a; i += b)
;
// The above used to compile with GCC 8 and older, but will
// not anymore with GCC 9. A firstprivate(a, b) clause needs
// to be added for C; for C++ it could be just firstprivate(a)
// to make it compatible with all GCC releases.
}
const int huge_array[1024] = { ... };
void bar (void) {
#pragma omp parallel for default(none)
for (int i = 0; i < 1024; i++)
use (huge_array[i]);
// Similarly, this used to compile with GCC 8 and older and
// will not anymore. Adding firstprivate(huge_array) is
// probably undesirable here, so either
// default(none) shared(huge_array) should be used and it will
// only support GCC 9 and later, or default(none) should be
// removed and then it will be compatible with all GCC releases
// and huge_array will be shared.
}
operator new(size_t, nothrow_t)
calls
operator new(size_t)
GCC 9 implements the requirement introduced in the C++ 2011 standard that
the nothrow
version of operator new
calls the
ordinary, throwing version of operator new
(and catches any
exception and instead returns a null pointer).
This was changed by DR 206 to ensure
that the various forms of operator new
do not become decoupled
if a user only replaces the ordinary operator new
.
Code that only replaces one version of operator new
and expects
the other versions to be unaffected might change behaviour when using GCC 9.
If your program uses a replacement operator new(size_t, nothrow_t)
then it must also replace operator new(size_t)
and
operator delete(void*)
, and ensure memory obtained from the
nothrow
version of new
can be freed by the ordinary
version of operator delete
.
The simplest solution is to only replace the ordinary
operator new(size_t)
and
operator delete(void*)
and
operator delete(void*, size_t)
functions, and the replaced versions will be used by all of
operator new(size_t, nothrow_t)
,
operator new[](size_t)
and
operator new[](size_t, nothrow_t)
and the corresponding operator delete
functions.
To support types with extended alignment you may also need to replace
operator new(size_t, align_val_t)
and
operator delete(void*, align_val_t)
and
operator delete(void*, align_val_t)
(which will then be used by the nothrow
and array forms for
extended alignments).
Copyright (C) Free Software Foundation, Inc. Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.
These pages are maintained by the GCC team. Last modified 2023-10-15.