Skip to content

Commit 24e2e25

Browse files
authored
[C2y] Implement WG14 N3344 (#115313)
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.
1 parent 85eec89 commit 24e2e25

File tree

4 files changed

+50
-4
lines changed

4 files changed

+50
-4
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,12 @@ C2y Feature Support
280280
this is now a C2y extension in C. ``-Wgnu-case-range`` still applies in C++
281281
modes.
282282

283+
- Clang implemented support for `N3344 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3344.pdf>`_
284+
which disallows a ``void`` parameter from having a qualifier or storage class
285+
specifier. Note that ``register void`` was previously accepted in all C
286+
language modes but is now rejected (all of the other qualifiers and storage
287+
class specifiers were previously rejected).
288+
283289
C23 Feature Support
284290
^^^^^^^^^^^^^^^^^^^
285291

clang/lib/Sema/SemaDecl.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15002,6 +15002,12 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D,
1500215002
const DeclSpec &DS = D.getDeclSpec();
1500315003

1500415004
// Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
15005+
// C2y 6.7.7.4p4: A parameter declaration shall not specify a void type,
15006+
// except for the special case of a single unnamed parameter of type void
15007+
// with no storage class specifier, no type qualifier, and no following
15008+
// ellipsis terminator.
15009+
// Clang applies the C2y rules for 'register void' in all C language modes,
15010+
// same as GCC, because it's questionable what that could possibly mean.
1500515011

1500615012
// C++03 [dcl.stc]p2 also permits 'auto'.
1500715013
StorageClass SC = SC_None;
@@ -15010,10 +15016,16 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D,
1501015016
// In C++11, the 'register' storage class specifier is deprecated.
1501115017
// In C++17, it is not allowed, but we tolerate it as an extension.
1501215018
if (getLangOpts().CPlusPlus11) {
15019+
Diag(DS.getStorageClassSpecLoc(), getLangOpts().CPlusPlus17
15020+
? diag::ext_register_storage_class
15021+
: diag::warn_deprecated_register)
15022+
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
15023+
} else if (!getLangOpts().CPlusPlus &&
15024+
DS.getTypeSpecType() == DeclSpec::TST_void) {
1501315025
Diag(DS.getStorageClassSpecLoc(),
15014-
getLangOpts().CPlusPlus17 ? diag::ext_register_storage_class
15015-
: diag::warn_deprecated_register)
15016-
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
15026+
diag::err_invalid_storage_class_in_func_decl)
15027+
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
15028+
D.getMutableDeclSpec().ClearStorageClassSpecs();
1501715029
}
1501815030
} else if (getLangOpts().CPlusPlus &&
1501915031
DS.getStorageClassSpec() == DeclSpec::SCS_auto) {

clang/test/C/C2y/n3344.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %clang_cc1 -verify -std=c2y -Wall -pedantic %s
2+
// RUN: %clang_cc1 -verify -Wall -pedantic %s
3+
4+
/* WG14 N3344: Yes
5+
* Slay Some Earthly Demons VI
6+
*
7+
* A 'void' parameter cannot have any qualifiers, storage class specifiers, or
8+
* be followed by an ellipsis.
9+
*
10+
* Note: Clang treats 'register void' as being a DR and rejects it in all
11+
* language modes; there's no evidence that this will break users and it's not
12+
* clear what the programmer intended if they wrote such code anyway. This
13+
* matches GCC's behavior.
14+
*/
15+
16+
void baz(volatile void); // expected-error {{'void' as parameter must not have type qualifiers}}
17+
void bar(const void); // expected-error {{'void' as parameter must not have type qualifiers}}
18+
void foo(register void); // expected-error {{invalid storage class specifier in function declarator}}
19+
void quux(static void); // expected-error {{invalid storage class specifier in function declarator}}
20+
void quobble(auto void); // expected-error {{invalid storage class specifier in function declarator}}
21+
void quubble(extern void); // expected-error {{invalid storage class specifier in function declarator}}
22+
// FIXME: it's odd that these aren't diagnosed as storage class specifiers.
23+
#if __STDC_VERSION__ >= 202311L
24+
void quibble(constexpr void); // expected-error {{function parameter cannot be constexpr}}
25+
#endif
26+
void quabble(_Thread_local void); // expected-error {{'_Thread_local' is only allowed on variable declarations}}
27+
void bing(void, ...); // expected-error {{'void' must be the first and only parameter if specified}}
28+

clang/www/c_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ <h2 id="c2y">C2y implementation status</h2>
201201
<tr>
202202
<td>Slay Some Earthly Demons VI</td>
203203
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3344.pdf">N3344</a></td>
204-
<td class="unknown" align="center">Unknown</td>
204+
<td class="unreleased" align="center">Clang 20</td>
205205
</tr>
206206
<tr>
207207
<td>Slay Some Earthly Demons VII</td>

0 commit comments

Comments
 (0)