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
