Porting to GCC 4.9

The GCC 4.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 in order to support new standards, or relaxed in standards-conforming ways to facilitate compilation or run-time 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.9. 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.

C/C++ language issues

Invalid OpenMP #pragma omp end directive now diagnosed

GCC no longer accepts invalid OpenMP like:


  #pragma omp critical
    foo ();
  #pragma omp end critical

This example now gives the following diagnostic:

t.c:6:19: error: expected ‘declare’ before ‘critical’
   #pragma omp end critical
                   ^

There is no #pragma omp end critical directive for C/C++ (whereas for Fortran there is !$omp end critical) but before OpenMP 4.0 support was added, this would be diagnosed only with -Wunknown-pragmas. As OpenMP 4.0 includes the #pragma omp end declare target directive, this is now a parsing error.

Null pointer checks may be optimized away more aggressively

GCC might now optimize away the null pointer check in code like:


  int copy (int* dest, int* src, size_t nbytes) {
    memmove (dest, src, nbytes);
    if (src != NULL)
      return *src;
    return 0;
  }

The pointers passed to memmove (and similar functions in <string.h>) must be non-null even when nbytes==0, so GCC can use that information to remove the check after the memmove call. Calling copy(p, NULL, 0) can therefore deference a null pointer and crash.

The example above needs to be fixed to avoid the invalid memmove call, for example:


    if (nbytes != 0)
      memmove (dest, src, nbytes);

This optimization can also affect implicit null pointer checks such as the one done by the C++ runtime for the delete[] operator.

C language issues

Right operand of comma operator without effect

GCC now warns about unused right-hand side of a comma expression that contains no side effects:


  int i = 42; 
  bar (), i;

This example now gives the following diagnostic:

w.c:5:9: warning: right-hand operand of comma expression has no effect [-Wunused-value]
   bar (), i;
         ^

To suppress this warning cast the right-hand operand to void:


  int i = 42; 
  bar (), (void) i;

C++ language issues

Shadowing name of exception in catch handler now rejected

GCC by default no longer accepts code such as:


  try {
    // ...
  } catch (const E& e) {
    int e = 0;
  }

This example now gives the following diagnostic:

e.cc:8:9: error: redeclaration of ‘int e’ [-fpermissive]
     int e = 0;                                                                       
         ^
e.cc:7:21: note:const E& e’ previously declared here
   } catch (const E& e) {                                                             
                     ^

The standard says the example is ill-formed, so GCC was changed to reject it for PR31952. To fix the error either rename one of the variables or use an additional nested scope for the second one.

Default arguments on redeclaration of member function of class template now rejected

GCC by default no longer accepts code such as:


  template<class T>
  struct A
  {
    void f(int);
  };

  template<class T>
  void A<T>::f(int i=0) { }

This example now gives the following diagnostic:

r.cc:8:21: error: redeclaration of ‘void A<T>::f(int)’ may not have default arguments [-fpermissive]

The standard says the example is ill-formed, so GCC was changed to reject it for PR54485. To fix the error the default argument must appear when the member function is first declared.

Header <memory> changes

The contents of the <memory> header were reorganized to allow easier reuse within libstdc++. As a result, some code which directly includes headers such as <bits/shared_ptr.h> will no longer compile and may produce a diagnostic like:

/usr/include/c++/4.9.0/bits/shared_ptr_base.h: In member function ‘virtual void* std::_Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp>::_M_get_deleter(const std::type_info&)’:
/usr/include/c++/4.9.0/bits/shared_ptr_base.h:479:39: error: must #include <typeinfo> before using typeid
         return __ti == typeid(_Deleter) ? &_M_impl._M_del() : nullptr;
                                       ^

All <bits/xxx.h> headers are internal library headers and including them directly is not supported and may be made into a hard error in a future GCC release.

Header <cstddef> changes

The <cstddef> header was updated for C++11 support and this breaks some libraries which misuse macros meant for internal use by GCC only. For instance with GMP versions up to 5.1.3, you may see:

/usr/include/c++/4.9.0/cstddef:51:11: error:::max_align_t’ has not been declared
   using ::max_align_t;
           ^

Another possible error is:

someheader.h:99:13: error:ptrdiff_t’ does not name a type

A workaround until libraries get updated is to include <cstddef> or <stddef.h> before any headers from that library.

Functions returning abstract class types

GCC now checks return types more strictly and will reject declarations of functions which return abstract types, including in uninstantiated templates and in typedefs to function pointers. Returning an abstract type is not possible so the code must be fixed.

Links

Matthias Klose, Debian test rebuild on x86_64-linux-gnu with trunk 20140118