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

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

---
 .../test/AST/ast-dump-rvalue-ref-bitfield.cpp | 29 +++++++++++++++++++
 clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp | 28 ++++++++++++++++++
 2 files changed, 57 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 00000000000000..38ed402ef38982
--- /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 00000000000000..8966178f3a9bad
--- /dev/null
+++ b/clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp
@@ -0,0 +1,28 @@
+// 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 A {
+  int a : 4;
+};
+
+// CHECK-LABEL: define {{.*}} @_Z4test1A(
+void test(A obj) {
+  #ifdef NONCONST
+  // CHECK-NONCONST: {{Assertion.*LV.isSimple\(\)}}
+  int &&ri = static_cast<int&&>(obj.a);
+  #endif
+
+#ifdef CONST
+  // CHECK-CONST: {{Assertion.*LV.isSimple\(\)}}
+  const int &&cri = static_cast<const int &&>(obj.a);
+  #endif
+}

>From 6c1138217d1ccab7050f583fa46ea77e5255316e Mon Sep 17 00:00:00 2001
From: Aditya Chaudhary <[email protected]>
Date: Thu, 15 Oct 2026 00:35:10 +0530
Subject: [PATCH 2/3] moved ast test and format the test as well

---
 clang/test/AST/ast-dump-expr.cpp              | 22 ++++++++++++++
 .../test/AST/ast-dump-rvalue-ref-bitfield.cpp | 29 -------------------
 clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp | 14 +++++----
 3 files changed, 30 insertions(+), 35 deletions(-)
 delete mode 100644 clang/test/AST/ast-dump-rvalue-ref-bitfield.cpp

diff --git a/clang/test/AST/ast-dump-expr.cpp b/clang/test/AST/ast-dump-expr.cpp
index e19c6d4b12451d..d48a72b4d9511f 100644
--- a/clang/test/AST/ast-dump-expr.cpp
+++ b/clang/test/AST/ast-dump-expr.cpp
@@ -596,3 +596,25 @@ void f() {
 }
 // CHECK: CXXTemporaryObjectExpr {{.*}} <col:5, col:11> 'S' 'void (int, int)'
 }
+
+// static_cast<T&&> of a bit-field lvalue.
+// FIXME: Clang binds the reference directly to the bit-field without inserting
+// an LValueToRValue conversion or MaterializeTemporaryExpr, which crashes
+// CodeGen (see CodeGenCXX/rvalue-ref-bitfield.cpp).
+namespace BitFieldRvalueRef {
+struct BF {
+  int a : 4;
+};
+void test(BF obj) {
+  int &&r = static_cast<int &&>(obj.a);
+  // CHECK: VarDecl 0x{{[^ ]*}} <col:3, col:38> col:9 r 'int &&' cinit
+  // CHECK-NEXT: CXXStaticCastExpr 0x{{[^ ]*}} <col:13, col:38> 'int' xvalue 
static_cast<int &&> <NoOp>
+  // CHECK-NEXT: MemberExpr 0x{{[^ ]*}} <col:33, col:37> 'int' lvalue bitfield 
.a
+  // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:33> 'BF' lvalue ParmVar 0x{{[^ 
]*}} 'obj' 'BF'
+  const int &&cr = static_cast<const int &&>(obj.a);
+  // CHECK: VarDecl 0x{{[^ ]*}} <col:3, col:51> col:15 cr 'const int &&' cinit
+  // CHECK-NEXT: CXXStaticCastExpr 0x{{[^ ]*}} <col:20, col:51> 'const int' 
xvalue static_cast<const int &&> <NoOp>
+  // CHECK-NEXT: MemberExpr 0x{{[^ ]*}} <col:46, col:50> 'int' lvalue bitfield 
.a
+  // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:46> 'BF' lvalue ParmVar 0x{{[^ 
]*}} 'obj' 'BF'
+}
+} // namespace BitFieldRvalueRef
diff --git a/clang/test/AST/ast-dump-rvalue-ref-bitfield.cpp 
b/clang/test/AST/ast-dump-rvalue-ref-bitfield.cpp
deleted file mode 100644
index 38ed402ef38982..00000000000000
--- a/clang/test/AST/ast-dump-rvalue-ref-bitfield.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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
index 8966178f3a9bad..0e7f5a87bc7fea 100644
--- a/clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp
+++ b/clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp
@@ -1,8 +1,10 @@
 // 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:   -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
+// 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
@@ -16,13 +18,13 @@ struct A {
 
 // CHECK-LABEL: define {{.*}} @_Z4test1A(
 void test(A obj) {
-  #ifdef NONCONST
+#ifdef NONCONST
   // CHECK-NONCONST: {{Assertion.*LV.isSimple\(\)}}
-  int &&ri = static_cast<int&&>(obj.a);
-  #endif
+  int &&ri = static_cast<int &&>(obj.a);
+#endif
 
 #ifdef CONST
   // CHECK-CONST: {{Assertion.*LV.isSimple\(\)}}
   const int &&cri = static_cast<const int &&>(obj.a);
-  #endif
+#endif
 }

>From 1f8ab9ea17d8aeabecd907ed491671476bb53e21 Mon Sep 17 00:00:00 2001
From: Aditya Chaudhary <[email protected]>
Date: Mon, 19 Oct 2026 10:17:23 +0530
Subject: [PATCH 3/3] add test in the SemaCXX

---
 clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp |  6 +--
 .../static-cast-bitfield-temporary.cpp        | 46 +++++++++++++++++++
 2 files changed, 48 insertions(+), 4 deletions(-)
 create mode 100644 clang/test/SemaCXX/static-cast-bitfield-temporary.cpp

diff --git a/clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp 
b/clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp
index 0e7f5a87bc7fea..9a57d9d6ea2609 100644
--- a/clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp
+++ b/clang/test/CodeGenCXX/rvalue-ref-bitfield.cpp
@@ -1,10 +1,8 @@
 // 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:   -emit-llvm -O0 -disable-llvm-passes -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
+// RUN:   -emit-llvm -O0 -disable-llvm-passes -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
diff --git a/clang/test/SemaCXX/static-cast-bitfield-temporary.cpp 
b/clang/test/SemaCXX/static-cast-bitfield-temporary.cpp
new file mode 100644
index 00000000000000..5a10b20e89cfaa
--- /dev/null
+++ b/clang/test/SemaCXX/static-cast-bitfield-temporary.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown -fsyntax-only 
-verify %s
+// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown -fsyntax-only 
-verify -fexperimental-new-constant-interpreter %s
+
+struct A {
+  unsigned x : 1;
+};
+
+// FIXME: static_cast<T&&> of a bit-field should bind to an independent
+// temporary; currently Sema binds directly to the bit-field so r aliases a.x.
+constexpr unsigned f1() {
+  A a{0};
+  unsigned &&r = static_cast<unsigned &&>(a.x);
+  r = 7;
+  a.x = 0;
+  return r;
+}
+static_assert(f1() == 7); // expected-error {{static assertion failed due to 
requirement 'f1() == 7'}}
+                           // expected-note@-1 {{expression evaluates to '0 == 
7'}}
+
+// FIXME: the temporary's lifetime should expire at the end of the
+// full-expression; reading through p after that point must be rejected.
+// Currently a different Sema error fires due to the direct bit-field binding.
+constexpr auto &q(auto &&a) { return a; } // expected-error {{non-const lvalue 
reference to type 'unsigned int' cannot bind to a temporary of type 'unsigned 
int'}}
+constexpr unsigned f2() {
+  A a{0};
+  unsigned *p;
+  *(p = &q(static_cast<unsigned &&>(a.x))) = 1; // expected-note {{in 
instantiation of function template specialization 'q<unsigned int>' requested 
here}}
+  // expected-note@-1 {{subexpression not valid in a constant expression}}
+  return *p;
+}
+static_assert(f2() == 1); // expected-error {{static assertion expression is 
not an integral constant expression}}
+                           // expected-note@-1 {{in call to 'f2()'}}
+
+// FIXME: cv-qualification from static_cast<const T&&> must be preserved on the
+// materialized temporary; const_cast cannot enable modification through it.
+// f3() must never produce a constant expression. Currently no error is emitted
+// because the direct binding lets the modification silently succeed.
+// When fixed, this function should be diagnosed as never producing a constant
+// expression, with a note pointing at the modification of the const temporary.
+// The new interpreter has a separate bug and may not emit the note.
+constexpr unsigned f3() { // FIXME-expected-error {{never produces a constant 
expression}}
+  A a{0};
+  unsigned &&r = const_cast<unsigned &&>(static_cast<const unsigned &&>(a.x));
+  r = 0; // FIXME-expected-note {{modification of object of const-qualified 
type 'const unsigned int'}}
+  return a.x;
+}

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

Reply via email to