Skip to content

Conversation

@AaronBallman
Copy link
Collaborator

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.

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.
@AaronBallman AaronBallman added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" c2y labels Mar 7, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 7, 2025

@llvm/pr-subscribers-clang-tools-extra

@llvm/pr-subscribers-clang

Author: Aaron Ballman (AaronBallman)

Changes

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 --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}}
+                                      */
+}
+

@AaronBallman AaronBallman requested a review from Sirraide March 7, 2025 18:26
@AaronBallman AaronBallman merged commit b19ed9c into llvm:main Mar 7, 2025
12 checks passed
@AaronBallman AaronBallman deleted the aballman-wg14-n3409 branch March 7, 2025 19:46
@llvm-ci
Copy link
Collaborator

llvm-ci commented Mar 8, 2025

LLVM Buildbot has detected a new failure on builder llvm-x86_64-debian-dylib running on gribozavr4 while building clang-tools-extra,clang at step 7 "test-build-unified-tree-check-llvm".

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

Here is the relevant piece of the build log for the reference
Step 7 (test-build-unified-tree-check-llvm) failure: test (failure)
******************** TEST 'LLVM-Unit :: Support/./SupportTests/134/174' FAILED ********************
Script(shard):
--
GTEST_OUTPUT=json:/b/1/llvm-x86_64-debian-dylib/build/unittests/Support/./SupportTests-LLVM-Unit-3324496-134-174.json GTEST_SHUFFLE=0 GTEST_TOTAL_SHARDS=174 GTEST_SHARD_INDEX=134 /b/1/llvm-x86_64-debian-dylib/build/unittests/Support/./SupportTests
--

Script:
--
/b/1/llvm-x86_64-debian-dylib/build/unittests/Support/./SupportTests --gtest_filter=Caching.Normal
--
/b/1/llvm-x86_64-debian-dylib/llvm-project/llvm/unittests/Support/Caching.cpp:55: Failure
Value of: AddStream
  Actual: false
Expected: true


/b/1/llvm-x86_64-debian-dylib/llvm-project/llvm/unittests/Support/Caching.cpp:55
Value of: AddStream
  Actual: false
Expected: true



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


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 clang-tools-extra clangd

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants