Skip to content

[C2y] Implement WG14 N3411 #130180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 7, 2025
Merged

Conversation

AaronBallman
Copy link
Collaborator

This paper (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3411.pdf) allows a source file to end without a newline. Clang has supported this as a conforming extension for a long time, so this suppresses the diagnotic in C2y mode but continues to diagnose as an extension in earlier language modes. It also continues to diagnose if the user passes -Wnewline-eof explicitly.

This paper allows a source file to end without a newline. Clang has
supported this as a conforming extension for a long time, so this
suppresses the diagnotic in C2y mode but continues to diagnose as an
extension in earlier language modes. It also continues to diagnose if
the user passes -Wnewline-eof explicitly.
@AaronBallman AaronBallman added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" c2y labels Mar 6, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 6, 2025

@llvm/pr-subscribers-clang

Author: Aaron Ballman (AaronBallman)

Changes

This paper (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3411.pdf) allows a source file to end without a newline. Clang has supported this as a conforming extension for a long time, so this suppresses the diagnotic in C2y mode but continues to diagnose as an extension in earlier language modes. It also continues to diagnose if the user passes -Wnewline-eof explicitly.


Full diff: https://github.com/llvm/llvm-project/pull/130180.diff

4 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+3)
  • (modified) clang/lib/Lex/Lexer.cpp (+7-8)
  • (added) clang/test/C/C2y/n3411.c (+14)
  • (modified) clang/www/c_status.html (+1-1)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 38b5bdf1dd46b..36aeb6c736627 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -108,6 +108,9 @@ C Language Changes
 
 C2y Feature Support
 ^^^^^^^^^^^^^^^^^^^
+- Implemented N3411 which allows a source file to not end with a newline
+  character. This is still reported as a conforming extension in earlier
+  language modes.
 
 C23 Feature Support
 ^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 087c6f13aea66..c62a9f5041183 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -3192,23 +3192,22 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
   if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r')) {
     DiagnosticsEngine &Diags = PP->getDiagnostics();
     SourceLocation EndLoc = getSourceLocation(BufferEnd);
-    unsigned DiagID;
+    unsigned DiagID = diag::warn_no_newline_eof;
 
     if (LangOpts.CPlusPlus11) {
       // C++11 [lex.phases] 2.2 p2
       // Prefer the C++98 pedantic compatibility warning over the generic,
       // non-extension, user-requested "missing newline at EOF" warning.
-      if (!Diags.isIgnored(diag::warn_cxx98_compat_no_newline_eof, EndLoc)) {
+      if (!Diags.isIgnored(diag::warn_cxx98_compat_no_newline_eof, EndLoc))
         DiagID = diag::warn_cxx98_compat_no_newline_eof;
-      } else {
-        DiagID = diag::warn_no_newline_eof;
-      }
     } else {
-      DiagID = diag::ext_no_newline_eof;
+      // This is conforming in C2y, but is an extension in earlier language
+      // modes.
+      if (!LangOpts.C2y)
+        DiagID = diag::ext_no_newline_eof;
     }
 
-    Diag(BufferEnd, DiagID)
-      << FixItHint::CreateInsertion(EndLoc, "\n");
+    Diag(BufferEnd, DiagID) << FixItHint::CreateInsertion(EndLoc, "\n");
   }
 
   BufferPtr = CurPtr;
diff --git a/clang/test/C/C2y/n3411.c b/clang/test/C/C2y/n3411.c
new file mode 100644
index 0000000000000..edfc1c16fe365
--- /dev/null
+++ b/clang/test/C/C2y/n3411.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -verify=c2y -std=c2y -Wall -pedantic %s
+// RUN: %clang_cc1 -verify -Wnewline-eof -std=c2y -Wall -pedantic %s
+// RUN: %clang_cc1 -verify -std=c23 -Wall -pedantic %s
+
+/* WG14 N3411: Yes
+ * Slay Some Earthly Demons XII
+ *
+ * Allow a non-empty source file to end without a final newline character. Note
+ * that this file intentionally does not end with a trailing newline.
+ */
+// c2y-no-diagnostics
+
+int x; // Ensure the file contains at least one declaration.
+// expected-warning {{no newline at end of file}}
\ No newline at end of file
diff --git a/clang/www/c_status.html b/clang/www/c_status.html
index 4e912987b69c6..e8b50a37093f9 100644
--- a/clang/www/c_status.html
+++ b/clang/www/c_status.html
@@ -294,7 +294,7 @@ <h2 id="c2y">C2y implementation status</h2>
     <tr>
       <td>Slay Some Earthly Demons XII</td>
       <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3411.pdf">N3411</a></td>
-      <td class="unknown" align="center">Unknown</td>
+      <td class="unreleased" align="center">Clang 21</td>
 	</tr>
     <tr>
       <td>Slay Some Earthly Demons XIII</td>

Comment on lines +3204 to +3207
// This is conforming in C2y, but is an extension in earlier language
// modes.
if (!LangOpts.C2y)
DiagID = diag::ext_no_newline_eof;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that the corresponding change in C++ was introduced by a CWG issue (CWG787). Would it be preferred to treat N3411 as a DR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, WG14 has a list of such things and this paper isn't on the list: https://www.open-std.org/jtc1/sc22/wg14/www/previous.html

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly, GCC does not warn https://compiler-explorer.com/z/vWMf6W551 , so I question the value of bundling that warning in -fpedantic.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-pedantic exists to diagnose extensions and this is definitively an extension. So that's a GCC bug IMO. :-)

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy to approve as-is, but would you be willing to ask WG14 if they would consider encouraging backporting the feature?

@AaronBallman
Copy link
Collaborator Author

I'm happy to approve as-is, but would you be willing to ask WG14 if they would consider encouraging backporting the feature?

Absolutely!

@AaronBallman AaronBallman merged commit 9fc3310 into llvm:main Mar 7, 2025
10 of 11 checks passed
@AaronBallman AaronBallman deleted the aballman-wg14-n3411 branch March 7, 2025 13:34
jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
This paper (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3411.pdf)
allows a source file to end without a newline. Clang has supported this
as a conforming extension for a long time, so this suppresses the
diagnotic in C2y mode but continues to diagnose as an extension in
earlier language modes. It also continues to diagnose if the user passes
-Wnewline-eof explicitly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c2y clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants