If we don’t end a source file with a new line character but just a }
after main(), then the clang compiler (in strict mode
-std=c17 -pedantic-errors
) infamously complains:
error: no newline at end of file [-Werror,-Wnewline-eof]
So where did they get this from? It would seem taken from C17 5.1.1.2 Translation phases, emphasis mine:
Each instance of a backslash character (
) immediately followed by a new-line character is
deleted, splicing physical source lines to form logical source lines. Only the last backslash on
any physical source line shall be eligible for being part of such a splice. A source file that is
not empty shall end in a new-line character, which shall not be immediately preceded by a
backslash character before any such splicing takes place.
This first describes how the preprocessor merges lines in the presence of a . If would seem that the intention of this whole translation phase is to decribe line splicing specifically and not source files in general.
There seems to be some confusion about the last sentence. If I end my file with (new line)
then now clang suddenly lets the code through in direct violation of the above quoted normative part in the standard. gcc however complains about the non-conformance:
error: backslash-newline at end of file
Sure, the translation phases are not part of a constraint so the compiler doesn’t have to generate a diagnostic. But why is clang behaving all backwards?
I checked the C99 rationale and it says that the intention of allowing backslash + new line as a general way to splice lines, string literals etc was added as per C89 for maximum portability: “the C89 Committee generalized this mechanism to permit any token to be continued by interposing a backslash/newline sequence”. This would be why backslash + new line with no trailing tokens after doesn’t make any sense.
9
The main question is if a C file should end with a new line or not and if so where in the C standard does it say so. The translation phase part was the only relevant part I could find.
Yes, that’s the part that says a source file must end with a (non-escaped) newline. You expressed doubt about the applicability of that requirement based on it being bundled with the specifications for line splicing, but I don’t see how that would matter. The spec requires a non-escaped newline at the end of the file, with the result that the source file overall, if non-empty, must have the form of a sequence of one or more newline-terminated lines (at the end of phase 2, but that requires the same at the beginning of phase 2).
If the spec merely wanted to forbid an escaped newline at the end of a source file then it would have said that, and the relevant language would have been simpler than what it actually does say. Something like this, for example: “Prior to such line splicing, a non-empty source file shall not end in a new-line character immediately preceded by a backslash character.”
I see no reason to interpret the requirement for a non-escaped newline at the end of a source file as meaning anything other than what it says on its face.
The bonus question is why clang is seemingly non-conforming when it comes to ending a source file with backslash + newline
Clang does not, for this reason, fail to conform. It accepts non-conforming source without emitting a diagnostic, but conforming implementations are permitted to do that as long as the non-conformance does not involve a constraint violation. I am inclined to guess that this particular omission is contrary to the intent of Clang’s authors, such that it constitutes a program flaw, but you would have to ask them. Possibly by submitting a bug report.
In any case, Clang’s behavior is not well characterized as “backwards”. It does diagnose one bona fide source-conformance issue, but fails to diagnose a different, related one. That may be flawed, but it doesn’t seem backwards to me.
2