Porting to GCC 4.7

The GCC 4.7 release series differs from previous GCC releases in more than the usual list of changes. Some of these are a result of bug fixing, and some old behaviors have been intentionally changed in order to support new standards, or relaxed in standards-conforming ways to facilitate compilation or runtime performance. Some of these changes are not visible to the naked eye and will not cause problems when updating from older versions.

However, some of these changes are visible, and can cause grief to users porting to GCC 4.7. This document is an effort to identify major issues and provide clear solutions in a quick and easily searched manner. Additions and suggestions for improvement are welcome.

General issues

Use of invalid flags when linking

Earlier releases did not warn or error about completely invalid options on gcc/g++/gfortran etc. command lines, if nothing was compiled, but only linking was performed. This is no longer the case. For example,

gcc -Wl -o foo foo.o -mflat_namespace

Now produces the following error

error: unrecognized command line option ‘-Wl’
error: unrecognized command line option ‘-mflat_namespace’

Invalid options need to be removed from the command line or replaced by something that is valid.

C++ language issues

Header dependency changes

Many of the standard C++ library include files have been edited to no longer include <unistd.h> to remove namespace pollution.

As such, C++ programs that used functions including truncate, sleep or pipe without first including <unistd.h> will no longer compile. The diagnostic produced is similar to:

error: ‘truncate’ was not declared in this scope
error: ‘sleep’ was not declared in this scope
error: ‘pipe’ was not declared in this scope
error: there are no arguments to 'offsetof' that depend on a template
parameter, so a declaration of 'offsetof' must be available

Fixing this issue is easy: just include <unistd.h>.

Note on proper checking for thread support

At no time should user-level code use private GCC-implementation-space macros such as _GLIBCXX_HAS_GTHREADS to determine concurrency support at compile-time Instead, use the POSIX macro _REENTRANT.

Name lookup changes

The C++ compiler no longer performs some extra unqualified lookups it had performed in the past, namely dependent base class scope lookups and unqualified template function lookups.

C++ programs that depended on the compiler's previous behavior may no longer compile. For example, code such as

template<typename T>
int t(T i)
{ return f(i); }

int
f(int i)
{ return i; }

int
main()
{
  return t(1);
}

Will result in the following diagnostic:

In instantiation of ‘int t(T) [with T = int]’
  required from here
  error: ‘f’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
  note: ‘int f(int)’ declared here, later in the translation unit

To fix, make sure the function f in the code above is declared before first use in function t. Like so:

int
f(int i)
{ return i; }

template<typename T>
int t(T i)
{ return f(i); }

int
main()
{
  return t(1);
}

This can be temporarily worked around by using -fpermissive.

Detection of redeclared variable names in nested scopes

The C++ compiler no longer allows identical identifiers in some nested scopes. Namely:

void f(int);

int main()
{
    for (int i=0;;++i)
    {
      int i=5;
      f(i);
    }
    return 0;
 }

Now results in the error:

error: redeclaration of ‘int i’
error: ‘int i’ previously declared here

To fix this, rename one of the two variables from i to a distinct identifier.

User-defined literals and whitespace

The C++ compiler in ISO C++11 mode std={c++11,c++0x,gnu++11,gnu++0x} supports user defined literals, which are incompatible with some valid ISO C++03 code.

In particular, whitespace is now needed after a string literal and before something that could be a valid user defined literal. Take the valid ISO C++03 code

const char *p = "foobar"__TIME__;

In C++03, the __TIME__ macro expands to some string literal and is concatenated with the other one. In C++11 __TIME__ isn't expanded, instead operator "" __TIME__ is being looked up, resulting in the following diagnostic:

 error: unable to find string literal operator
 ‘operator"" __TIME__’

This applies to any string literal followed without whitespace by some macro. To fix, just add some whitespace between the string literal and the macro name.

Visibility of template instantiations

The ELF symbol visibility of a template instantiation is now properly constrained by the visibility of its template arguments. As a result, users that compile with -fvisibility=hidden should be aware of the visibility of types #included from library headers; if the header does not explicitly control symbol visibility (as the standard C++ library does) types from those headers will be hidden, and so instantiations that use those types as template arguments will also be hidden. For instance,

#include <vector>               // template std::vector has default visibility
#include <ctime>                // struct tm has hidden visibility
template class std::vector<tm>; // instantiation has hidden visibility

Most likely only code that uses extern explicit template instantiation in headers will notice this change. One approach to adjusting the visibility of a library header foo.h is to create a forwarding header on the -I include path consisting of

#pragma GCC visibility push(default)
#include_next <foo.h>
#pragma GCC visibility push

Links

Jakub Jelinek, GCC 4.7 related common package rebuild failures (was Re: mass rebuild status)