Clang 15 rejects implicit C declarations by default
Clang 15 promotes implicit function declarations and implicit int to errors in C99 and later modes. Its prototype diagnostics also distinguish deprecated source from declarations whose meaning changes in C2x.
A C build can succeed while the compiler lacks the declaration needed to check a function call correctly. Clang 15 reduces that tolerance. Its release notes make implicit function declarations and implicit int errors by default in C99 and later modes. The LLVM 15.0.0 release became available on September 6.
The change concerns the compiler's default diagnostic severity for constructs that older modes treated differently. It does not mean C suddenly acquired function declarations. It means a build can no longer depend on these diagnostics remaining warnings under the affected modes. Missing headers and missing type specifiers become immediate compilation failures unless a supported compatibility option changes that policy.
C's usefulness at foreign-function boundaries is one of its strongest practical arguments for me. That usefulness depends on callers and callees agreeing about types. A build failure at an undeclared call is preferable to treating the linker's ability to find a symbol as evidence that the call was correctly specified.
A visible declaration changes what can be checked
Consider a translation unit that calls an application function without including its declaration. This example intentionally lacks the relevant header.
int run_request(void)
{
return request_status();
}
The function name's presence at link time cannot provide the compiler with a source-level prototype during translation. The source should include the header that owns the declaration, or otherwise provide the correct declaration before the call. Guessing a return type to silence a diagnostic is not equivalent to obtaining the interface contract.
Clang 15's default error makes that requirement visible earlier in the build. In modes before C2x, -Wno-error=implicit-function-declaration can downgrade the diagnostic to a warning, and -Wno-implicit-function-declaration can disable it. The release notes explicitly limit those escape routes. In C2x mode, support for implicit declarations is removed and the warning options have no effect.
That is a significant difference between a transition option and an alternative language definition. An older-mode build can temporarily change severity for particular source. A C2x build cannot use the same switch to recover a facility that the frontend has removed from that mode. The selected language version must be part of interpreting a diagnostic-control flag.
Implicit int receives the same treatment
The notes describe a parallel change for -Wimplicit-int. In C99 and later modes, the diagnostic now defaults to an error. Before C2x, the corresponding no-error or disabling option can relax it. C2x removes support and ignores those warning controls for this purpose.
This affects declarations that omit their intended type, including old source that relied on int as an implicit default. The appropriate correction states the intended type explicitly. That correction may be simple, but the actual interface still determines the type. A mechanical insertion of int everywhere would preserve the assumption without establishing that it is correct.
Clang also adjusts how it describes C89. The release removes the ungrouped diagnostic that called defaulting to int an extension in that mode. The notes explain that it was valid C89, so the old explanation was inaccurate. Explicitly enabling -Wimplicit-int in C89 now produces warnings instead of doing nothing.
These changes show a useful diagnostic principle. A compiler should distinguish old language rules from extensions and invalid constructs. The same token sequence can have a different status under a different selected standard. Correct severity and correct wording both matter when a project maintains source across language modes.
Non-prototype declarations have a separate migration problem
Clang 15 also revises -Wstrict-prototypes and adds the related -Wdeprecated-non-prototype diagnostic. These are not simply alternate names for an undeclared-function error. A declaration can exist while failing to specify a prototype that describes the accepted arguments.
The release notes divide those cases by what happens under C2x. -Wstrict-prototypes diagnoses deprecated declarations and definitions without prototypes when their behaviour remains correct in the newer mode. It remains off by default, but -pedantic enables it because it is a deprecation warning.
-Wdeprecated-non-prototype covers cases whose behaviour changes in C2x. It also diagnoses calls that pass arguments to a function without a prototype. That diagnostic is enabled by default and belongs to the strict-prototypes warning group. The notes say its state at the function declaration site determines whether it applies to callers, which gives a header owner control over the affected interface's diagnostic policy.
Neither warning has an effect in C2x or when -fno-knr-functions is enabled. That qualification again ties the warning to the language rules in force. Migration diagnostics are useful while the old construct remains available. Once the selected mode has different function-declaration rules, the compiler applies those rules directly.
Conflicting definitions are now diagnosed correctly
One corrected error concerns a declaration with a prototype followed by an incompatible definition without one. The release gives the form void f(int); void f() {} as a case now diagnosed correctly. The presence of a prior declaration does not make the later definition consistent with it.
That matters for code assembled from several generations of C style. A header may carry an explicit prototype while a source file retains an older-looking definition. The compiler must evaluate their relationship within the selected language mode. Diagnosing the disagreement protects the interface the header expresses.
I value C's small language, but small syntax does not mean every declaration is easy to interpret without context. These diagnostics reduce the amount of missing information a reader must infer. They are especially relevant where a header is the shared description of a function used by multiple translation units.
Pointer conversions also become harder to overlook
The same release makes -Wint-conversion an error by default in every C language mode. The notes identify implicit conversions between integers and pointers as its subject. Unlike the implicit-declaration changes, this default is not restricted to C99 and later.
The documented controls can downgrade or disable this diagnostic. Their existence does not establish that an arbitrary conversion expresses the intended interface. In particular, a cast added at the call site can conceal the symptom while leaving a missing or incorrect declaration unresolved. The function's actual declaration remains the source of the argument and result types.
Clang 15's combined changes therefore affect more than projects that explicitly enable warnings as errors. Existing default builds can stop on omitted types, undeclared calls, or implicit pointer conversions. The release notes supply distinct diagnostic names and language-mode boundaries for each case, so corrections can address the missing contract in the source instead of suppressing all diagnostics together.