From Fedora Project Wiki

Porting Fedora to Modern C

Summary

Back in 1999, a new revision of the C standard removed several backwards compatibility features. However, GCC still accepts these obsolete constructs by default. Support for these constructs is confusing to programmers and potentially affect GCC's ability to implement features from future C standards. It is expected that a future GCC version (likely GCC 14) will disable support for these legacy language constructs by default. The goal of this change is to prepare Fedora for this transition.

Owner


Current status

Detailed Description

Individual language changes are listed in this section. The most important ones are the first too. GCC 14 may also make other changes by default, as described below. All these changes will also require extensive testing, and some adoption of configure checks.

Clang 16 will also benefit from these porting efforts. However, Clang 16 may land in Fedora before this work concludes, so the LLVM team is investigating other approaches.

Removal of implicit function declarations

Status Mostly complete. 54 impacted packages as of 2023-11-29. Enforced via -Werror=implicit-function-declaration.

An implicit function declaration is a legacy compatibility feature that causes the compiler to automatically supply a declaration of type int function() if function is undeclared, but called as a function. However, the implicit return type of int is incompatible with pointer-returning functions, which can lead to difficult debugging sessions if the compiler warning is missed, as described here:

On x86-64, functions returning _Bool called with an implicit declaration will also not work correctly because the return register value for _Bool functions is partially undefined (not all 32 bits in the implicitly declared int are defined).

Implicit function declarations were part of C89 and have been removed from C99. With current GCC versions, the removal can be emulated by building with -Werror=implicit-function-declaration.

Removal of implicit int

Status Mostly complete. 5 packages are impacted as of 2023-11-29. Enforced via -Werror=implicit-int.

Another change for C99 is the removal of implicit int type in declarations. For example, in the following fragment, both i and j are defined as int variables:

static i = 1.0;
auto j = 2.0;

Support for this obsolete construct is incompatible with adoption of type inference for auto definitions (which are part of C++ and planned for C as well.).

Neither change is trivial to implement because introducing errors for these constructs (as required by C99) alters the result of autoconf configure checks. Quite a few such checks use an implicitly declared exit function, for instance. These failures are not really related to the feature under test. If the build system is well written, the build still succeeds, the relevant features are automatically disabled in the test suite and removed from reference ABI lists, and it's not immediately apparent that feature is gone. Therefore, some care is needed that no such alterations happen, and packages need to be ported to C99. Various tools for this porting activity are being developed to support this proposal. Cross-distribution collaboration will help as well, sharing patches and insights.

With current GCC, this change can be emulated using -Werror=implicit-int.

Missing parameter types in function declarations

Status Conversion is complete. No impacted packages.

Current GCC merely warns about spelling mistakes like this one:

void print_int(int32t);

Here, GCC treats int32t as an untyped parameter (not even as an int), and the declaration is treated as not containing a function prototype. This means that a call like

print_int(1, 2);

is silently accepted without a further warning. GCC 14 will error on the declaration with the missing parameter type.

In current GCC, the warning about missing types does not have an option to control it, so it is only possible to turn it into an error with -Werror or -pedantic-errors.

Rejecting implicit conversions between integers and pointers as errors

Status Work partially completed. Approximately 100 impacted packages as of 2023-11-29.

Currently, GCC does not treat conversion between integers at pointers as errors, so this compiles:

int ptr = "string";

However, this is very unlikely to work on 64-bit architectures (it may work by accident without PIE/PIC).

This change can be previewed by compiling with -Werror=int-conversion.

Rejecting missing and extra expressions in return statements

Status Work partially completed. Approximately 13 impacted packages of 2023-11-29.

GCC 14 adds a new warning, -Wreturn-mismatch. The plan is to turn it into an error for the GCC 14 release. This covers the following scenarios:

int f(void) { return; } // Missing expression for return value.
void g(int i) { return i; } // Extra return value expression.

The missing expression case is clearly undefined (if the function return value is used by the caller) and very likely to result in bugs.

In GCC 13, this warning is part of -Wreturn-types, among other things, so -Werror=return-types is an approximation of the GCC 14 default behavior, but will reject some valid programs as well.

Use of incompatible pointer types without a cast

Status Work barely begun. Approximately 381 impacted packages as of 2023-11-29.

GCC currently only warns about incorrect pointer types in initializers, assignments, and function arguments. For example, by default, GCC will produce an object file given this source code:

int *a = "b";

These mismatches are not valid C, and usually indicate problems in the code. Given the large impact of this change, it is still unclear whether GCC 14 will go through with this change, but it seems likely that GCC 14 will treat this as an error by default.

In current GCC, the error behavior can be emulated using -Werror=incompatible-pointer-types.

Removal of old-style function definitions

Status Not currently in scope.

An old style function definition looks like this:

int
sum (a, b)
  char *a;
  int b;
{
  return atoi (a) + b;
}

It is equivalent to this definition with a prototype:

int
sum (char *a, int b)
{
  return atoi (a) + b;
}

This legacy feature is very close to being incompatible with the C2X standard, which introduces unnamed function arguments. But due to a quirk in GCC's implementation, it should be possible to support both at the same time.

This change can be tested using -std=gnu2x -Werror=old-style-definition. The -std=gnu2x option is needed to accept a definition of the form void empty () { }; future C versions will treat () as (void) (see below).

New keywords bool, true, false

Status Currently not in scope.

Packages which supply their own definitions instead of including <stdbool.h> (which remains available) might fail to build.

This change currently cannot be previewed using compiler flags.

Change of meaning of () in function declarators

In earlier C versions, a declaration int function() declares function as accepting an unspecified number of arguments of unknown type. This means that both function(1) and function("one") compile, even though they might not work correctly. In a future C standard, int function() will mean that function does not accept any parameters (like in C++, or as if written as int function(void) in current C). Calls that specify parameters will therefore result in compilation errors.

We believe that this change is ABI-compatible, even on ppc64le (with its parameter save area), although it comes very close to an implicit ABI break.

This change currently cannot be previewed using compiler flags.

Feedback

The transition plan has been discussed at various GNU Tools Cauldrons. Feedback has been generally positive, except a general worry about the work required.

Without a deliberate porting effort, a lot of breakage occurs, as seen in 2016 in Fedora with an uncoordinated change, and more recently with an uncoordinated Clang update.

Benefit to Fedora

Programmers will no longer waste time tracking down things that look eerily like compiler or ABI bugs because in several cases, builds will fail with a clear error message, instead of producing a warning that is easily missed. Potential blockers to adoption of further C language changes are removed.

Scope

  • Proposal owners: Identifier packages that need fixing (using the Mass Prebuild tool). Update rawhide over time to be compatible with strict C99 compilers.
  • Other developers: Help out with non-obvious porting issues, and with upstreaming patches in case active upstreams cannot be easily identified. Tolerate early backports of upstream-submitted fixes in Fedora dist-git.
  • Policies and guidelines: Fedora compiler policy will likely change due to the adoption of GCC 14 in Fedora 40.
  • Trademark approval: N/A (not needed for this Change)
  • Alignment with Objectives: N/A

Upgrade/compatibility impact

The change is expected to be transparent to those users who do not use C compilers. No features are supposed to be added or removed as a result. In fact, most of the porting effort focuses on avoiding configuration changes.

How To Test

General regression testing is sufficient.

User Experience

User experience does not change. Developers may have to adopt their sources or switch to building with -std=gnu89. Details will be provided through upstream release notes referenced from a separate toolchain upgrade Fedora Change proposal.

Dependencies

To avoid regressing the porting effort, GCC as the system compiler needs to reject obsolete constructs by default. This is expected for GCC 14, to be released as part of Fedora 40 in the first half of 2024.

Contingency Plan

  • Contingency mechanism: Upstream GCC will probably accept obsolete constructs longer in case distributions like Fedora cannot port to modern C in time. Worst case, we can patch GCC or try to revert the change to wrapper scripts.
  • Contingency deadline: not provided
  • Blocks release? No if GCC doesn't switch. If GCC switches, we have to complete the port or wait for GCC being patched/wrapped.

Documentation

Information for Fedora developers and other contributors is contained in the Toolchain/PortingToModernC page.

Once the changes become available in an upstream GCC release, its release notes will provide porting instructions to developers.

Release Notes

Probably not needed because no user visible impact is intended. Developer-impacting changes will be documented through a separate Fedora Change proposal for the toolchain upgrade that brings the compiler change, likely by referencing upstream release notes.