https://github.com/MitchBriles created https://github.com/llvm/llvm-project/pull/169480
Fixes #169197. This also seems to improve diagnostics in some cases. Let me know if this is not the expected behavior. Note: I am new to this part of the project. I would appreciate any feedback/nits. cc: @Sirraide, @Fznamznon >From e0df041167306660224dc152920e502956fd76c4 Mon Sep 17 00:00:00 2001 From: Mitch <[email protected]> Date: Tue, 25 Nov 2025 02:33:38 -0700 Subject: [PATCH] [Clang][Sema] Preserve bit-field info in conditional operator --- clang/lib/AST/Expr.cpp | 7 +++++++ .../CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp | 4 ++-- clang/test/CXX/drs/cwg3xx.cpp | 1 + clang/test/SemaCXX/bitfield-cond-promotion.cpp | 16 ++++++++++++++++ clang/test/SemaCXX/conditional-expr.cpp | 6 +++++- 5 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 clang/test/SemaCXX/bitfield-cond-promotion.cpp diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 1d914fa876759..67197274f51bf 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4247,6 +4247,13 @@ FieldDecl *Expr::getSourceBitField() { if (UnOp->isPrefix() && UnOp->isIncrementDecrementOp()) return UnOp->getSubExpr()->getSourceBitField(); + if (const ConditionalOperator *Cond = dyn_cast<ConditionalOperator>(E)) { + if (FieldDecl *FD = Cond->getTrueExpr()->getSourceBitField()) + return FD; + if (FieldDecl *FD = Cond->getFalseExpr()->getSourceBitField()) + return FD; + } + return nullptr; } diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp index 3e8f18c93077e..72ee1ce400d8d 100644 --- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp @@ -41,8 +41,8 @@ namespace PR6066 { namespace test3 { struct A { - unsigned bitX : 4; // expected-note 3 {{bit-field is declared here}} - unsigned bitY : 4; // expected-note {{bit-field is declared here}} + unsigned bitX : 4; // expected-note 6 {{bit-field is declared here}} + unsigned bitY : 4; // expected-note 2 {{bit-field is declared here}} unsigned var; void foo(); diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp index bbd87c060801a..c1864abd0e466 100644 --- a/clang/test/CXX/drs/cwg3xx.cpp +++ b/clang/test/CXX/drs/cwg3xx.cpp @@ -397,6 +397,7 @@ namespace cwg324 { // cwg324: 3.6 // expected-error@-1 {{non-const reference cannot bind to bit-field}} int *f = &(true ? s.n : s.n); // expected-error@-1 {{address of bit-field requested}} + // expected-note@#cwg324-n {{bit-field is declared here}} int &g = (void(), s.n); // expected-error@-1 {{non-const reference cannot bind to bit-field 'n'}} // expected-note@#cwg324-n {{bit-field is declared here}} diff --git a/clang/test/SemaCXX/bitfield-cond-promotion.cpp b/clang/test/SemaCXX/bitfield-cond-promotion.cpp new file mode 100644 index 0000000000000..2f287193e351f --- /dev/null +++ b/clang/test/SemaCXX/bitfield-cond-promotion.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s -std=c++11 +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s -std=c++14 +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s -std=c++17 +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s -std=c++20 +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s -std=c++23 + +void test_runtime_behavior() { + struct { + unsigned f : 1; + } constexpr s{}; + + constexpr int result = (0 ? throw 0 : s.f) - 1; + static_assert(result == -1, "Bit-field should promote to int"); // expected-no-diagnostics + constexpr int result2 = (1 ? s.f : s.f) - 1; + static_assert(result2 == -1, "Bit-field should promote to int"); // expected-no-diagnostics +} diff --git a/clang/test/SemaCXX/conditional-expr.cpp b/clang/test/SemaCXX/conditional-expr.cpp index 8f17555fd806f..d081be60d5520 100644 --- a/clang/test/SemaCXX/conditional-expr.cpp +++ b/clang/test/SemaCXX/conditional-expr.cpp @@ -42,7 +42,8 @@ struct BadBase { operator BadDerived&(); }; struct BadDerived : BadBase {}; struct Fields { - int i1, i2, b1 : 3, b2 : 3; + int i1, i2, b1 : 3, b2 : 3; // expected-note 2 {{bit-field is declared here}} + unsigned u1: 1; }; struct MixedFields { int i; @@ -201,6 +202,9 @@ void test() (void)&(i1 ? flds.b1 : flds.i1); // expected-error {{address of bit-field requested}} (void)&(i1 ? flds.i1 : flds.b1); // expected-error {{address of bit-field requested}} + // shouldn't be considered narrowing + unsigned char uc1{0 ? throw 0 : flds.u1}; + unsigned char uc2{1 ? flds.u1 : flds.u1}; unsigned long test0 = 5; test0 = test0 ? (long) test0 : test0; // expected-warning {{operand of ? changes signedness: 'long' to 'unsigned long'}} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
