diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 061a1fed3f7d4..3e7d8e15110f9 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 `_ + 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 aba6b555ff28f..c9cd81a48fbe5 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 0000000000000..bd3d440cb5d12 --- /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 8b677095cee18..e66424290e6d5 100644 --- a/clang/www/c_status.html +++ b/clang/www/c_status.html @@ -201,7 +201,7 @@

C2y implementation status

Slay Some Earthly Demons VI N3344 - Unknown + Clang 20 Slay Some Earthly Demons VII