Skip to content

Commit 8ee44f1

Browse files
committed
[C2y] Implement WG14 N3409
This paper removes UB around use of void expressions. Previously, code like this had undefined behavior: void foo(void) { (void)(void)1; extern void x; x; } and this is now well-defined in C2y. Functionally, this now means that it is valid to use `void` as a `_Generic` association.
1 parent d1bd1c7 commit 8ee44f1

File tree

4 files changed

+49
-3
lines changed

4 files changed

+49
-3
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ C2y Feature Support
114114
- Implemented N3411 which allows a source file to not end with a newline
115115
character. This is still reported as a conforming extension in earlier
116116
language modes.
117+
- Implement `WG14 N3409 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3409.pdf>`_
118+
which removes UB around use of ``void`` expressions. In practice, this means
119+
that ``_Generic`` selection associations may now have ``void`` type, but it
120+
also removes UB with code like ``(void)(void)1;``.
117121

118122
C23 Feature Support
119123
^^^^^^^^^^^^^^^^^^^

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10425,8 +10425,13 @@ def warn_type_safety_null_pointer_required : Warning<
1042510425
"specified %0 type tag requires a null pointer">, InGroup<TypeSafety>;
1042610426

1042710427
// Generic selections.
10428-
def err_assoc_type_incomplete : Error<
10429-
"type %0 in generic association incomplete">;
10428+
def ext_assoc_type_incomplete : Extension<
10429+
"ISO C requires a complete type in a '_Generic' association; %0 is an "
10430+
"incomplete type">;
10431+
def warn_c2y_compat_assoc_type_incomplete : Warning<
10432+
"use of an incomplete type in a '_Generic' association is incompatible with "
10433+
"C standards before C2y; %0 is an incomplete type">,
10434+
InGroup<CPre2yCompat>, DefaultIgnore;
1043010435
def err_assoc_type_nonobject : Error<
1043110436
"type %0 in generic association not an object type">;
1043210437
def err_assoc_type_variably_modified : Error<

clang/lib/Sema/SemaExpr.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1748,9 +1748,14 @@ ExprResult Sema::CreateGenericSelectionExpr(
17481748
//
17491749
// C11 6.5.1.1p2 "The type name in a generic association shall specify a
17501750
// complete object type other than a variably modified type."
1751+
// C2y removed the requirement that an expression form must
1752+
// use a complete type, though it's still as-if the type has undergone
1753+
// lvalue conversion. We support this as an extension in C23 and
1754+
// earlier because GCC does so.
17511755
unsigned D = 0;
17521756
if (ControllingExpr && Types[i]->getType()->isIncompleteType())
1753-
D = diag::err_assoc_type_incomplete;
1757+
D = LangOpts.C2y ? diag::warn_c2y_compat_assoc_type_incomplete
1758+
: diag::ext_assoc_type_incomplete;
17541759
else if (ControllingExpr && !Types[i]->getType()->isObjectType())
17551760
D = diag::err_assoc_type_nonobject;
17561761
else if (Types[i]->getType()->isVariablyModifiedType())

clang/test/C/C2y/n3409.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %clang_cc1 -verify -std=c2y -pedantic %s
2+
// RUN: %clang_cc1 -verify=pre-c2y -std=c2y -Wpre-c2y-compat %s
3+
// RUN: %clang_cc1 -verify=ext -std=c23 -pedantic %s
4+
// expected-no-diagnostics
5+
6+
/* WG14 N3409: Clang 21
7+
* Slay Some Earthly Demons X
8+
*
9+
* Removes the requirement that an expression with type void cannot be used in
10+
* any way. This was making it UB to use a void expression in a _Generic
11+
* selection expression for no good reason, as well as making it UB to cast a
12+
* void expression to void, etc.
13+
*/
14+
15+
extern void x;
16+
void foo() {
17+
// FIXME: this is technically an extension before C2y and should be diagnosed
18+
// under -pedantic.
19+
(void)(void)1;
20+
// FIXME: same with this.
21+
x;
22+
_Generic(x, void: 1); /* pre-c2y-warning {{use of an incomplete type in a '_Generic' association is incompatible with C standards before C2y; 'void' is an incomplete type}}
23+
ext-warning {{ISO C requires a complete type in a '_Generic' association; 'void' is an incomplete type}}
24+
*/
25+
_Generic(x, typeof(x): 1); /* pre-c2y-warning {{use of an incomplete type in a '_Generic' association is incompatible with C standards before C2y; 'typeof (x)' (aka 'void') is an incomplete type}}
26+
ext-warning {{ISO C requires a complete type in a '_Generic' association; 'typeof (x)' (aka 'void') is an incomplete type}}
27+
*/
28+
(void)_Generic(void, default : 1); /* pre-c2y-warning {{passing a type argument as the first operand to '_Generic' is incompatible with C standards before C2y}}
29+
ext-warning {{passing a type argument as the first operand to '_Generic' is a C2y extension}}
30+
*/
31+
}
32+

0 commit comments

Comments
 (0)