llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Aaron Ballman (AaronBallman) <details> <summary>Changes</summary> 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. --- Full diff: https://github.com/llvm/llvm-project/pull/130299.diff 4 Files Affected: - (modified) clang/docs/ReleaseNotes.rst (+4) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+7-2) - (modified) clang/lib/Sema/SemaExpr.cpp (+6-1) - (added) clang/test/C/C2y/n3409.c (+32) ``````````diff diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 577b3f2130df7..df8d2eed1ec0c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -114,6 +114,10 @@ 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. +- Implement `WG14 N3409 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3409.pdf>`_ + which removes UB around use of ``void`` expressions. In practice, this means + that ``_Generic`` selection associations may now have ``void`` type, but it + also removes UB with code like ``(void)(void)1;``. C23 Feature Support ^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 1b46920e09619..d6e5005003322 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10425,8 +10425,13 @@ def warn_type_safety_null_pointer_required : Warning< "specified %0 type tag requires a null pointer">, InGroup<TypeSafety>; // Generic selections. -def err_assoc_type_incomplete : Error< - "type %0 in generic association incomplete">; +def ext_assoc_type_incomplete : Extension< + "ISO C requires a complete type in a '_Generic' association; %0 is an " + "incomplete type">; +def warn_c2y_compat_assoc_type_incomplete : Warning< + "use of an incomplete type in a '_Generic' association is incompatible with " + "C standards before C2y; %0 is an incomplete type">, + InGroup<CPre2yCompat>, DefaultIgnore; def err_assoc_type_nonobject : Error< "type %0 in generic association not an object type">; def err_assoc_type_variably_modified : Error< diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index f896ccab53a54..de7be6b2805af 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1748,9 +1748,14 @@ ExprResult Sema::CreateGenericSelectionExpr( // // C11 6.5.1.1p2 "The type name in a generic association shall specify a // complete object type other than a variably modified type." + // C2y removed the requirement that an expression form must + // use a complete type, though it's still as-if the type has undergone + // lvalue conversion. We support this as an extension in C23 and + // earlier because GCC does so. unsigned D = 0; if (ControllingExpr && Types[i]->getType()->isIncompleteType()) - D = diag::err_assoc_type_incomplete; + D = LangOpts.C2y ? diag::warn_c2y_compat_assoc_type_incomplete + : diag::ext_assoc_type_incomplete; else if (ControllingExpr && !Types[i]->getType()->isObjectType()) D = diag::err_assoc_type_nonobject; else if (Types[i]->getType()->isVariablyModifiedType()) diff --git a/clang/test/C/C2y/n3409.c b/clang/test/C/C2y/n3409.c new file mode 100644 index 0000000000000..2fc789891c71d --- /dev/null +++ b/clang/test/C/C2y/n3409.c @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -verify -std=c2y -pedantic %s +// RUN: %clang_cc1 -verify=pre-c2y -std=c2y -Wpre-c2y-compat %s +// RUN: %clang_cc1 -verify=ext -std=c23 -pedantic %s +// expected-no-diagnostics + +/* WG14 N3409: Clang 21 + * Slay Some Earthly Demons X + * + * Removes the requirement that an expression with type void cannot be used in + * any way. This was making it UB to use a void expression in a _Generic + * selection expression for no good reason, as well as making it UB to cast a + * void expression to void, etc. + */ + +extern void x; +void foo() { + // FIXME: this is technically an extension before C2y and should be diagnosed + // under -pedantic. + (void)(void)1; + // FIXME: same with this. + x; + _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}} + ext-warning {{ISO C requires a complete type in a '_Generic' association; 'void' is an incomplete type}} + */ + _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}} + ext-warning {{ISO C requires a complete type in a '_Generic' association; 'typeof (x)' (aka 'void') is an incomplete type}} + */ + (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}} + ext-warning {{passing a type argument as the first operand to '_Generic' is a C2y extension}} + */ +} + `````````` </details> https://github.com/llvm/llvm-project/pull/130299 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits