[libc-commits] [libc] [libc][stdbit] Support compound literals in type-generic macros (PR #228721)

via libc-commits libc-commits at lists.llvm.org
Sat Oct 3 08:04:47 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: Chen Miao (ChenMiaoi)

<details>
<summary>Changes</summary>

Calls such as the following fail because the preprocessor treats the comma in the initializer as a macro argument separator:

``` c
struct PairUI { unsigned int first, second; };
stdc_count_ones((struct PairUI){ 2U, 3U }.first);
```

Use variadic macros so `__VA_ARGS__` preserves all argument tokens, including the separating commas, reconstructing the original expression.

Fixes #<!-- -->81503.

---
Full diff: https://github.com/llvm/llvm-project/pull/228721.diff


3 Files Affected:

- (modified) libc/include/llvm-libc-macros/stdbit-macros.h (+43-42) 
- (modified) libc/test/include/stdbit_stub.h (+6-15) 
- (modified) libc/test/include/stdbit_test.c (+21) 


``````````diff
diff --git a/libc/include/llvm-libc-macros/stdbit-macros.h b/libc/include/llvm-libc-macros/stdbit-macros.h
index c5b2f097783440..d665ebc071b7b3 100644
--- a/libc/include/llvm-libc-macros/stdbit-macros.h
+++ b/libc/include/llvm-libc-macros/stdbit-macros.h
@@ -213,104 +213,105 @@ inline unsigned long long stdc_bit_ceil(unsigned long long x) {
   return stdc_bit_ceil_ull(x);
 }
 #else
-#define stdc_leading_zeros(x)                                                  \
-  _Generic((x),                                                                \
+// Use variadic macros to accept compound literals containing commas.
+#define stdc_leading_zeros(...)                                                \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_leading_zeros_uc,                                    \
       unsigned short: stdc_leading_zeros_us,                                   \
       unsigned: stdc_leading_zeros_ui,                                         \
       unsigned long: stdc_leading_zeros_ul,                                    \
-      unsigned long long: stdc_leading_zeros_ull)(x)
-#define stdc_leading_ones(x)                                                   \
-  _Generic((x),                                                                \
+      unsigned long long: stdc_leading_zeros_ull)(__VA_ARGS__)
+#define stdc_leading_ones(...)                                                 \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_leading_ones_uc,                                     \
       unsigned short: stdc_leading_ones_us,                                    \
       unsigned: stdc_leading_ones_ui,                                          \
       unsigned long: stdc_leading_ones_ul,                                     \
-      unsigned long long: stdc_leading_ones_ull)(x)
-#define stdc_trailing_zeros(x)                                                 \
-  _Generic((x),                                                                \
+      unsigned long long: stdc_leading_ones_ull)(__VA_ARGS__)
+#define stdc_trailing_zeros(...)                                               \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_trailing_zeros_uc,                                   \
       unsigned short: stdc_trailing_zeros_us,                                  \
       unsigned: stdc_trailing_zeros_ui,                                        \
       unsigned long: stdc_trailing_zeros_ul,                                   \
-      unsigned long long: stdc_trailing_zeros_ull)(x)
-#define stdc_trailing_ones(x)                                                  \
-  _Generic((x),                                                                \
+      unsigned long long: stdc_trailing_zeros_ull)(__VA_ARGS__)
+#define stdc_trailing_ones(...)                                                \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_trailing_ones_uc,                                    \
       unsigned short: stdc_trailing_ones_us,                                   \
       unsigned: stdc_trailing_ones_ui,                                         \
       unsigned long: stdc_trailing_ones_ul,                                    \
-      unsigned long long: stdc_trailing_ones_ull)(x)
-#define stdc_first_leading_zero(x)                                             \
-  _Generic((x),                                                                \
+      unsigned long long: stdc_trailing_ones_ull)(__VA_ARGS__)
+#define stdc_first_leading_zero(...)                                           \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_first_leading_zero_uc,                               \
       unsigned short: stdc_first_leading_zero_us,                              \
       unsigned: stdc_first_leading_zero_ui,                                    \
       unsigned long: stdc_first_leading_zero_ul,                               \
-      unsigned long long: stdc_first_leading_zero_ull)(x)
-#define stdc_first_leading_one(x)                                              \
-  _Generic((x),                                                                \
+      unsigned long long: stdc_first_leading_zero_ull)(__VA_ARGS__)
+#define stdc_first_leading_one(...)                                            \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_first_leading_one_uc,                                \
       unsigned short: stdc_first_leading_one_us,                               \
       unsigned: stdc_first_leading_one_ui,                                     \
       unsigned long: stdc_first_leading_one_ul,                                \
-      unsigned long long: stdc_first_leading_one_ull)(x)
-#define stdc_first_trailing_zero(x)                                            \
-  _Generic((x),                                                                \
+      unsigned long long: stdc_first_leading_one_ull)(__VA_ARGS__)
+#define stdc_first_trailing_zero(...)                                          \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_first_trailing_zero_uc,                              \
       unsigned short: stdc_first_trailing_zero_us,                             \
       unsigned: stdc_first_trailing_zero_ui,                                   \
       unsigned long: stdc_first_trailing_zero_ul,                              \
-      unsigned long long: stdc_first_trailing_zero_ull)(x)
-#define stdc_first_trailing_one(x)                                             \
-  _Generic((x),                                                                \
+      unsigned long long: stdc_first_trailing_zero_ull)(__VA_ARGS__)
+#define stdc_first_trailing_one(...)                                           \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_first_trailing_one_uc,                               \
       unsigned short: stdc_first_trailing_one_us,                              \
       unsigned: stdc_first_trailing_one_ui,                                    \
       unsigned long: stdc_first_trailing_one_ul,                               \
-      unsigned long long: stdc_first_trailing_one_ull)(x)
-#define stdc_count_zeros(x)                                                    \
-  _Generic((x),                                                                \
+      unsigned long long: stdc_first_trailing_one_ull)(__VA_ARGS__)
+#define stdc_count_zeros(...)                                                  \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_count_zeros_uc,                                      \
       unsigned short: stdc_count_zeros_us,                                     \
       unsigned: stdc_count_zeros_ui,                                           \
       unsigned long: stdc_count_zeros_ul,                                      \
-      unsigned long long: stdc_count_zeros_ull)(x)
-#define stdc_count_ones(x)                                                     \
-  _Generic((x),                                                                \
+      unsigned long long: stdc_count_zeros_ull)(__VA_ARGS__)
+#define stdc_count_ones(...)                                                   \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_count_ones_uc,                                       \
       unsigned short: stdc_count_ones_us,                                      \
       unsigned: stdc_count_ones_ui,                                            \
       unsigned long: stdc_count_ones_ul,                                       \
-      unsigned long long: stdc_count_ones_ull)(x)
-#define stdc_has_single_bit(x)                                                 \
-  _Generic((x),                                                                \
+      unsigned long long: stdc_count_ones_ull)(__VA_ARGS__)
+#define stdc_has_single_bit(...)                                               \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_has_single_bit_uc,                                   \
       unsigned short: stdc_has_single_bit_us,                                  \
       unsigned: stdc_has_single_bit_ui,                                        \
       unsigned long: stdc_has_single_bit_ul,                                   \
-      unsigned long long: stdc_has_single_bit_ull)(x)
-#define stdc_bit_width(x)                                                      \
-  _Generic((x),                                                                \
+      unsigned long long: stdc_has_single_bit_ull)(__VA_ARGS__)
+#define stdc_bit_width(...)                                                    \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_bit_width_uc,                                        \
       unsigned short: stdc_bit_width_us,                                       \
       unsigned: stdc_bit_width_ui,                                             \
       unsigned long: stdc_bit_width_ul,                                        \
-      unsigned long long: stdc_bit_width_ull)(x)
-#define stdc_bit_floor(x)                                                      \
-  _Generic((x),                                                                \
+      unsigned long long: stdc_bit_width_ull)(__VA_ARGS__)
+#define stdc_bit_floor(...)                                                    \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_bit_floor_uc,                                        \
       unsigned short: stdc_bit_floor_us,                                       \
       unsigned: stdc_bit_floor_ui,                                             \
       unsigned long: stdc_bit_floor_ul,                                        \
-      unsigned long long: stdc_bit_floor_ull)(x)
-#define stdc_bit_ceil(x)                                                       \
-  _Generic((x),                                                                \
+      unsigned long long: stdc_bit_floor_ull)(__VA_ARGS__)
+#define stdc_bit_ceil(...)                                                     \
+  _Generic((__VA_ARGS__),                                                      \
       unsigned char: stdc_bit_ceil_uc,                                         \
       unsigned short: stdc_bit_ceil_us,                                        \
       unsigned: stdc_bit_ceil_ui,                                              \
       unsigned long: stdc_bit_ceil_ul,                                         \
-      unsigned long long: stdc_bit_ceil_ull)(x)
+      unsigned long long: stdc_bit_ceil_ull)(__VA_ARGS__)
 #endif // __cplusplus
 
 #endif // __LLVM_LIBC_MACROS_STDBIT_MACROS_H
diff --git a/libc/test/include/stdbit_stub.h b/libc/test/include/stdbit_stub.h
index 4ca26b6d81d825..1174fe55402b3b 100644
--- a/libc/test/include/stdbit_stub.h
+++ b/libc/test/include/stdbit_stub.h
@@ -46,21 +46,12 @@ STDBIT_STUB_FUNCTION(stdc_first_trailing_one, 0x1)
 STDBIT_STUB_FUNCTION(stdc_count_zeros, 0x2)
 STDBIT_STUB_FUNCTION(stdc_count_ones, 0x3)
 
-bool stdc_has_single_bit_uc(unsigned char __attribute__((unused)) x) {
-  return false;
-}
-bool stdc_has_single_bit_us(unsigned short __attribute__((unused)) x) {
-  return false;
-}
-bool stdc_has_single_bit_ui(unsigned __attribute__((unused)) x) {
-  return false;
-}
-bool stdc_has_single_bit_ul(unsigned long __attribute__((unused)) x) {
-  return false;
-}
-bool stdc_has_single_bit_ull(unsigned long long __attribute__((unused)) x) {
-  return false;
-}
+// Distinct accepted values let tests distinguish the bool-returning overloads.
+bool stdc_has_single_bit_uc(unsigned char x) { return x == 0xAU; }
+bool stdc_has_single_bit_us(unsigned short x) { return x == 0xBU; }
+bool stdc_has_single_bit_ui(unsigned x) { return x == 0xCU; }
+bool stdc_has_single_bit_ul(unsigned long x) { return x == 0xDU; }
+bool stdc_has_single_bit_ull(unsigned long long x) { return x == 0xEU; }
 
 STDBIT_STUB_FUNCTION(stdc_bit_width, 0x4)
 
diff --git a/libc/test/include/stdbit_test.c b/libc/test/include/stdbit_test.c
index 3f444ec70b2290..cadc81ce88b053 100644
--- a/libc/test/include/stdbit_test.c
+++ b/libc/test/include/stdbit_test.c
@@ -25,6 +25,17 @@
 #include "include/llvm-libc-macros/stdbit-macros.h"
 #include "test/UnitTest/LibcCTest.h"
 
+// The trailing comma in a compound literal must not be treated as a macro
+// argument separator. Also check that the initializer is evaluated only once.
+#define CHECK_COMPOUND_LITERAL(FUNC_NAME, TYPE, VALUE, EXPECTED)               \
+  do {                                                                         \
+    unsigned evaluations = 0;                                                  \
+    EXPECT_TRUE(FUNC_NAME((TYPE){                                              \
+                    (evaluations++, VALUE),                                    \
+                }) == EXPECTED);                                               \
+    EXPECT_TRUE(evaluations == 1);                                             \
+  } while (0)
+
 #define CHECK_FUNCTION(FUNC_NAME, VAL)                                         \
   do {                                                                         \
     EXPECT_TRUE(FUNC_NAME((unsigned char)0U) == VAL##AU);                      \
@@ -32,6 +43,11 @@
     EXPECT_TRUE(FUNC_NAME(0U) == VAL##CU);                                     \
     EXPECT_TRUE(FUNC_NAME(0UL) == VAL##DU);                                    \
     EXPECT_TRUE(FUNC_NAME(0ULL) == VAL##EU);                                   \
+    CHECK_COMPOUND_LITERAL(FUNC_NAME, unsigned char, 0, VAL##AU);              \
+    CHECK_COMPOUND_LITERAL(FUNC_NAME, unsigned short, 0, VAL##BU);             \
+    CHECK_COMPOUND_LITERAL(FUNC_NAME, unsigned int, 0, VAL##CU);               \
+    CHECK_COMPOUND_LITERAL(FUNC_NAME, unsigned long, 0, VAL##DU);              \
+    CHECK_COMPOUND_LITERAL(FUNC_NAME, unsigned long long, 0, VAL##EU);         \
   } while (0)
 
 TEST(stdbit) {
@@ -51,6 +67,11 @@ TEST(stdbit) {
   EXPECT_FALSE(stdc_has_single_bit(1U));
   EXPECT_FALSE(stdc_has_single_bit(1UL));
   EXPECT_FALSE(stdc_has_single_bit(1ULL));
+  CHECK_COMPOUND_LITERAL(stdc_has_single_bit, unsigned char, 0xAU, true);
+  CHECK_COMPOUND_LITERAL(stdc_has_single_bit, unsigned short, 0xBU, true);
+  CHECK_COMPOUND_LITERAL(stdc_has_single_bit, unsigned int, 0xCU, true);
+  CHECK_COMPOUND_LITERAL(stdc_has_single_bit, unsigned long, 0xDU, true);
+  CHECK_COMPOUND_LITERAL(stdc_has_single_bit, unsigned long long, 0xEU, true);
 
   CHECK_FUNCTION(stdc_bit_width, 0x4);
   CHECK_FUNCTION(stdc_bit_floor, 0x5);

``````````

</details>


https://github.com/llvm/llvm-project/pull/228721


More information about the libc-commits mailing list