Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Comment on lines +4250 to +4255

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this mean the order of the second and third operands would matter? Also, it looks like it would make cond?bit-field:non-bit-field promote and check for narrowing conversions based off of the width of the bit-field. Therefore promotion could change the value if the non-bit-field had a value not representable in int but representable in unsigned, and narrowing could happen in contexts where narrowing conversions are disabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if the operands differ in that way, it's handled in Sema::CXXCheckConditionalOperands. If folks can agree on the expected behavior, I'll make sure my patch is correct before marking it as ready.


return nullptr;
}

Expand Down
4 changes: 2 additions & 2 deletions clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions clang/test/CXX/drs/cwg3xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Expand Down
16 changes: 16 additions & 0 deletions clang/test/SemaCXX/bitfield-cond-promotion.cpp
Original file line number Diff line number Diff line change
@@ -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
}
6 changes: 5 additions & 1 deletion clang/test/SemaCXX/conditional-expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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'}}
Expand Down