https://github.com/aditya-chaudhary1 created 
https://github.com/llvm/llvm-project/pull/231092

A bit-field has no address, so a reference cannot bind to it directly. As per 
[[expr.static.cast]](https://en.cppreference.com/cpp/language/static_cast), the 
lvalue-to-rvalue conversion must be applied to the bit-field first, and the 
reference must then bind to a materialized temporary holding the resulting 
value.

Clang does not do this today. `TryLValueToRValueCast` in SemaCast.cpp accepts 
the cast as a `CK_NoOp` xvalue cast without checking for a bit-field, which 
produces this AST:

```
    CXXStaticCastExpr <NoOp> xvalue
    `-MemberExpr lvalue bitfield .a
```

There is no `LValueToRValue` conversion and no `MaterializeTemporaryExpr`. As a 
result, CodeGen reaches `EmitReferenceBindingToExpr` with a bit-field LValue 
and hits `assert(LV.isSimple())`.

[N4971 Document](https://isocpp.org/files/papers/N4971.pdf)


>From 3925f90a0554362496433e8a0bb7c3feb1a5f539 Mon Sep 17 00:00:00 2001
From: Aditya Chaudhary <[email protected]>
Date: Mon, 12 Oct 2026 12:25:04 +0530
Subject: [PATCH] Precommit tests that record clang current handling

---
 .../test/AST/ast-dump-rvalue-ref-bitfield.cpp | 29 +++++++++++++++++++
 clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp | 23 +++++++++++++++
 2 files changed, 52 insertions(+)
 create mode 100644 clang/test/AST/ast-dump-rvalue-ref-bitfield.cpp
 create mode 100644 clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp

diff --git a/clang/test/AST/ast-dump-rvalue-ref-bitfield.cpp 
b/clang/test/AST/ast-dump-rvalue-ref-bitfield.cpp
new file mode 100644
index 0000000000000..38ed402ef3898
--- /dev/null
+++ b/clang/test/AST/ast-dump-rvalue-ref-bitfield.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++11 -fsyntax-only \
+// RUN:   -ast-dump -ast-dump-filter test %s | FileCheck %s
+
+// static_cast<T&&> applied to a bit-field lvalue. A bit-field has no address,
+// so the reference has to bind to a materialized temporary.
+//
+// FIXME: Clang currently binds the reference directly to the bit-field. No
+// MaterializeTemporaryExpr or LValueToRValue conversion is created, and this
+// AST crashes CodeGen (see CodeGenCXX/rvalue-ref-bitfield.cpp).
+
+struct A {
+  int a : 4;
+  int b : 1;
+};
+
+void test(A obj) {
+  int &&r = static_cast<int &&>(obj.a);
+  const int &&cr = static_cast<const int &&>(obj.a);
+}
+
+// CHECK-LABEL: FunctionDecl {{.*}} test 'void (A)'
+// CHECK:       VarDecl {{.*}} r 'int &&' cinit
+// CHECK-NEXT:  `-CXXStaticCastExpr {{.*}} 'int' xvalue static_cast<int &&> 
<NoOp>
+// CHECK-NEXT:    `-MemberExpr {{.*}} 'int' lvalue bitfield .a
+// CHECK-NEXT:      `-DeclRefExpr {{.*}} 'A' lvalue ParmVar {{.*}} 'obj' 'A'
+// CHECK:       VarDecl {{.*}} cr 'const int &&' cinit
+// CHECK-NEXT:  `-CXXStaticCastExpr {{.*}} 'const int' xvalue 
static_cast<const int &&> <NoOp>
+// CHECK-NEXT:    `-MemberExpr {{.*}} 'int' lvalue bitfield .a
+// CHECK-NEXT:      `-DeclRefExpr {{.*}} 'A' lvalue ParmVar {{.*}} 'obj' 'A'
diff --git a/clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp 
b/clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp
new file mode 100644
index 0000000000000..0c0c60ad3a6d5
--- /dev/null
+++ b/clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp
@@ -0,0 +1,23 @@
+// REQUIRES: asserts
+// RUN: not --crash %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown \
+// RUN:   -emit-llvm -o - %s -DNONCONST 2>&1 | FileCheck %s 
--check-prefix=CHECK-NONCONST
+// RUN: not --crash %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown \
+// RUN:   -emit-llvm -o - %s -DCONST 2>&1 | FileCheck %s 
--check-prefix=CHECK-CONST
+
+// static_cast<T&&> of a bit-field lvalue should materialize a temporary.
+// FIXME: Sema binds the reference directly to the bit-field, so CodeGen
+// receives a bit-field LValue and asserts in EmitReferenceBindingToExpr.
+// Each case is guarded by its own macro because the crash aborts the whole
+// compilation.
+
+struct S { int a : 4; };
+
+#ifdef NONCONST
+// CHECK-NONCONST: {{Assertion.*LV.isSimple\(\)}}
+int &&f(S s) { return static_cast<int &&>(s.a); }
+#endif
+
+#ifdef CONST
+// CHECK-CONST: {{Assertion.*LV.isSimple\(\)}}
+const int &&g(const S &s) { return static_cast<const int &&>(s.a); }
+#endif

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to