Skip to content

[C2y] Implement WG14 N3344 #115313

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 1 commit into from
Nov 7, 2024
Merged

Conversation

AaronBallman
Copy link
Collaborator

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3344.pdf

This paper disallows a single void parameter from having qualifiers or storage class specifiers. Clang has diagnosed most of these as an error for a long time, but register void was previously accepted in all C language modes and is now being rejected in all C language modes.

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3344.pdf

This paper disallows a single `void` parameter from having qualifiers
or storage class specifiers. Clang has diagnosed most of these as an
error for a long time, but `register void` was previously accepted in
all C language modes and is now being rejected in all C language modes.
@AaronBallman AaronBallman added clang:frontend Language frontend issues, e.g. anything involving "Sema" c2y labels Nov 7, 2024
@llvmbot llvmbot added the clang Clang issues not falling into any other category label Nov 7, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 7, 2024

@llvm/pr-subscribers-clang

Author: Aaron Ballman (AaronBallman)

Changes

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3344.pdf

This paper disallows a single void parameter from having qualifiers or storage class specifiers. Clang has diagnosed most of these as an error for a long time, but register void was previously accepted in all C language modes and is now being rejected in all C language modes.


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

4 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+6)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+15-3)
  • (added) clang/test/C/C2y/n3344.c (+28)
  • (modified) clang/www/c_status.html (+1-1)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 061a1fed3f7d48..3e7d8e15110f9d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -280,6 +280,12 @@ C2y Feature Support
   this is now a C2y extension in C. ``-Wgnu-case-range`` still applies in C++
   modes.
 
+- Clang implemented support for `N3344 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3344.pdf>`_
+  which disallows a ``void`` parameter from having a qualifier or storage class
+  specifier. Note that ``register void`` was previously accepted in all C
+  language modes but is now rejected (all of the other qualifiers and storage
+  class specifiers were previously rejected).
+
 C23 Feature Support
 ^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index aba6b555ff28f3..c9cd81a48fbe51 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15002,6 +15002,12 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D,
   const DeclSpec &DS = D.getDeclSpec();
 
   // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
+  // C2y 6.7.7.4p4: A parameter declaration shall not specify a void type,
+  // except for the special case of a single unnamed parameter of type void
+  // with no storage class specifier, no type qualifier, and no following
+  // ellipsis terminator.
+  // Clang applies the C2y rules for 'register void' in all C language modes,
+  // same as GCC, because it's questionable what that could possibly mean.
 
   // C++03 [dcl.stc]p2 also permits 'auto'.
   StorageClass SC = SC_None;
@@ -15010,10 +15016,16 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D,
     // In C++11, the 'register' storage class specifier is deprecated.
     // In C++17, it is not allowed, but we tolerate it as an extension.
     if (getLangOpts().CPlusPlus11) {
+      Diag(DS.getStorageClassSpecLoc(), getLangOpts().CPlusPlus17
+                                            ? diag::ext_register_storage_class
+                                            : diag::warn_deprecated_register)
+          << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
+    } else if (!getLangOpts().CPlusPlus &&
+               DS.getTypeSpecType() == DeclSpec::TST_void) {
       Diag(DS.getStorageClassSpecLoc(),
-           getLangOpts().CPlusPlus17 ? diag::ext_register_storage_class
-                                     : diag::warn_deprecated_register)
-        << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
+           diag::err_invalid_storage_class_in_func_decl)
+          << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
+      D.getMutableDeclSpec().ClearStorageClassSpecs();
     }
   } else if (getLangOpts().CPlusPlus &&
              DS.getStorageClassSpec() == DeclSpec::SCS_auto) {
diff --git a/clang/test/C/C2y/n3344.c b/clang/test/C/C2y/n3344.c
new file mode 100644
index 00000000000000..bd3d440cb5d12a
--- /dev/null
+++ b/clang/test/C/C2y/n3344.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -verify -std=c2y -Wall -pedantic %s
+// RUN: %clang_cc1 -verify -Wall -pedantic %s
+
+/* WG14 N3344: Yes
+ * Slay Some Earthly Demons VI
+ *
+ * A 'void' parameter cannot have any qualifiers, storage class specifiers, or
+ * be followed by an ellipsis.
+ *
+ * Note: Clang treats 'register void' as being a DR and rejects it in all
+ * language modes; there's no evidence that this will break users and it's not
+ * clear what the programmer intended if they wrote such code anyway. This
+ * matches GCC's behavior.
+ */
+
+void baz(volatile void);         // expected-error {{'void' as parameter must not have type qualifiers}}
+void bar(const void);            // expected-error {{'void' as parameter must not have type qualifiers}}
+void foo(register void);         // expected-error {{invalid storage class specifier in function declarator}}
+void quux(static void);          // expected-error {{invalid storage class specifier in function declarator}}
+void quobble(auto void);         // expected-error {{invalid storage class specifier in function declarator}}
+void quubble(extern void);       // expected-error {{invalid storage class specifier in function declarator}}
+// FIXME: it's odd that these aren't diagnosed as storage class specifiers.
+#if __STDC_VERSION__ >= 202311L
+void quibble(constexpr void);    // expected-error {{function parameter cannot be constexpr}}
+#endif
+void quabble(_Thread_local void); // expected-error {{'_Thread_local' is only allowed on variable declarations}}
+void bing(void, ...);            // expected-error {{'void' must be the first and only parameter if specified}}
+
diff --git a/clang/www/c_status.html b/clang/www/c_status.html
index 8b677095cee182..e66424290e6d50 100644
--- a/clang/www/c_status.html
+++ b/clang/www/c_status.html
@@ -201,7 +201,7 @@ <h2 id="c2y">C2y implementation status</h2>
     <tr>
       <td>Slay Some Earthly Demons VI</td>
       <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3344.pdf">N3344</a></td>
-      <td class="unknown" align="center">Unknown</td>
+      <td class="unreleased" align="center">Clang 20</td>
     </tr>
     <tr>
       <td>Slay Some Earthly Demons VII</td>

Copy link
Collaborator

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

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

Paper doesn't say, but presumably based on this patch, 'alternative #1' is what was accepted?

@AaronBallman
Copy link
Collaborator Author

Paper doesn't say, but presumably based on this patch, 'alternative #1' is what was accepted?

Correct, alternative #1 :-)

@AaronBallman AaronBallman merged commit 24e2e25 into llvm:main Nov 7, 2024
13 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Nov 7, 2024

LLVM Buildbot has detected a new failure on builder llvm-clang-x86_64-sie-ubuntu-fast running on sie-linux-worker while building clang at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/144/builds/11070

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'Clang :: C/C2y/n3344.c' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang -cc1 -internal-isystem /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/20/include -nostdsysteminc -verify -std=c2y -Wall -pedantic /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/C/C2y/n3344.c
+ /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang -cc1 -internal-isystem /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/20/include -nostdsysteminc -verify -std=c2y -Wall -pedantic /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/C/C2y/n3344.c
RUN: at line 2: /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang -cc1 -internal-isystem /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/20/include -nostdsysteminc -verify -Wall -pedantic /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/C/C2y/n3344.c
+ /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/bin/clang -cc1 -internal-isystem /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/lib/clang/20/include -nostdsysteminc -verify -Wall -pedantic /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/C/C2y/n3344.c
error: 'expected-warning' diagnostics seen but not expected: 
  File /home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/llvm-project/clang/test/C/C2y/n3344.c Line 26: '_Thread_local' is a C11 extension
1 error generated.

--

********************


@AaronBallman AaronBallman deleted the aballman-wg14-n3344 branch November 7, 2024 15:51
@mstorsjo
Copy link
Member

mstorsjo commented Nov 8, 2024

This change broke building Wine, which bundles the lcms2 library. The case there, which broke, seems to be somewhat different than what the paper talks about though. The paper talks about rejecting int func(register void);, but the case in lcms2 is int func(register void *ptr); which now also gets rejected.

I don't see the register void *ptr case mentioned in the paper at all. Is it intentional that this case now also is disallowed?

See https://github.com/mm2/Little-CMS/blob/lcms2.16/include/lcms2.h#L1311-L1317 for the full context of the breaking case (plus a dozen of more cases scattered around in the definition of static functions).

@Sirraide
Copy link
Member

Sirraide commented Nov 8, 2024

Is it intentional that this case now also is disallowed?

That seems like an accidental result of how this was implemented. I’m surprised we didn’t have register void* as a parameter anywhere in our tests.

@AaronBallman
Copy link
Collaborator Author

Thank you for letting me know I broke this -- that was not intentional, and I'll get on a fix or revert this morning.

@AaronBallman
Copy link
Collaborator Author

This should be addressed now with 0daca80, sorry for the trouble!

Groverkss pushed a commit to iree-org/llvm-project that referenced this pull request Nov 15, 2024
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3344.pdf

This paper disallows a single `void` parameter from having qualifiers or
storage class specifiers. Clang has diagnosed most of these as an error
for a long time, but `register void` was previously accepted in all C
language modes and is now being rejected in all C language modes.
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.

6 participants