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
