Skip to content

[C2y] Implement WG14 N3409 #130299

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 7, 2025
Merged

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



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


jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
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.
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