diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d830928a13d4d..4b01f018005ed 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -82,6 +82,9 @@ Improvements to Clang's diagnostics - ``-Wformat`` now recognizes ``%b`` for the ``printf``/``scanf`` family of functions and ``%B`` for the ``printf`` family of functions. Fixes `Issue 56885: `_. +- ``-Wbitfield-constant-conversion`` now diagnoses implicit truncation when 1 is + assigned to a 1-bit signed integer bitfield. This fixes + `Issue 53253 `_. Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 5a1c21d3a367b..a0ea35e1234f6 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -13064,11 +13064,6 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, if (llvm::APSInt::isSameValue(Value, TruncatedValue)) return false; - // Special-case bitfields of width 1: booleans are naturally 0/1, and - // therefore don't strictly fit into a signed bitfield of width 1. - if (FieldWidth == 1 && Value == 1) - return false; - std::string PrettyValue = toString(Value, 10); std::string PrettyTrunc = toString(TruncatedValue, 10); diff --git a/clang/test/CXX/class/class.bit/p1.cpp b/clang/test/CXX/class/class.bit/p1.cpp index ab15e3a356cfc..5df1ab52cdd8d 100644 --- a/clang/test/CXX/class/class.bit/p1.cpp +++ b/clang/test/CXX/class/class.bit/p1.cpp @@ -9,11 +9,11 @@ struct A { int [[]] c : 1; // OK, attribute applies to the type. int : 2 = 1; // expected-error {{anonymous bit-field cannot have a default member initializer}} int : 0 { 1 }; // expected-error {{anonymous bit-field cannot have a default member initializer}} - int : 0, d : 1 = 1; + unsigned int : 0, d : 1 = 1; int : 1 = 12, e : 1; // expected-error {{anonymous bit-field cannot have a default member initializer}} - int : 0, f : 1 = 1; - int g [[]] : 1 = 1; - int h [[]] : 1 {1}; - int i : foo() = foo(); + unsigned int : 0, f : 1 = 1; + unsigned int g [[]] : 1 = 1; + unsigned int h [[]] : 1 {1}; + unsigned int i : foo() = foo(); int j, [[]] k; // expected-error {{an attribute list cannot appear here}} }; diff --git a/clang/test/CXX/drs/dr6xx.cpp b/clang/test/CXX/drs/dr6xx.cpp index ad87c7295cfe8..432fd6e6c5efa 100644 --- a/clang/test/CXX/drs/dr6xx.cpp +++ b/clang/test/CXX/drs/dr6xx.cpp @@ -911,9 +911,9 @@ namespace dr674 { // dr674: 8 namespace dr675 { // dr675: dup 739 template struct A { T n : 1; }; #if __cplusplus >= 201103L - static_assert(A{1}.n < 0, ""); - static_assert(A{1}.n < 0, ""); - static_assert(A{1}.n < 0, ""); + static_assert(A{1}.n < 0, ""); // expected-warning {{implicit truncation from 'int' to bit-field changes value from 1 to -1}} + static_assert(A{1}.n < 0, ""); // expected-warning {{implicit truncation from 'int' to bit-field changes value from 1 to -1}} + static_assert(A{1}.n < 0, ""); // expected-warning {{implicit truncation from 'int' to bit-field changes value from 1 to -1}} #endif } diff --git a/clang/test/CodeGen/bitfield.c b/clang/test/CodeGen/bitfield.c index c624d0045d330..4845d7c478429 100644 --- a/clang/test/CodeGen/bitfield.c +++ b/clang/test/CodeGen/bitfield.c @@ -87,3 +87,19 @@ int g3(void) { // PATH: ret i32 1 return f3(20) + 130725747; } + +static int f4(void) { + struct s5 { + int b:1; + } x; + x.b = 1; + return x.b; +} + +int g4(void) { +// CHECK-LABEL: @g4() +// CHECK: ret i32 1 +// PATH-LABEL: @g4() +// PATH: ret i32 1 + return f4() + 2; +} diff --git a/clang/test/CodeGenCXX/bitfield-layout.cpp b/clang/test/CodeGenCXX/bitfield-layout.cpp index d570b8f33e343..0e0d712fd8aae 100644 --- a/clang/test/CodeGenCXX/bitfield-layout.cpp +++ b/clang/test/CodeGenCXX/bitfield-layout.cpp @@ -105,6 +105,15 @@ int test_trunc_three_bits() { // CHECK: define{{.*}} i32 @test_trunc_three_bits() // CHECK: ret i32 -1 +int test_trunc_one_bit() { + union { + int i : 1; // truncated to 0b1 == -1 + } const U = {1}; // 0b00000001 + return U.i; +} +// CHECK: define{{.*}} i32 @test_trunc_one_bit() +// CHECK: ret i32 -1 + int test_trunc_1() { union { int i : 1; // truncated to 0b1 == -1 diff --git a/clang/test/Rewriter/rewrite-modern-struct-ivar-1.mm b/clang/test/Rewriter/rewrite-modern-struct-ivar-1.mm index a17fe3f85675d..e54b1cdaab3af 100644 --- a/clang/test/Rewriter/rewrite-modern-struct-ivar-1.mm +++ b/clang/test/Rewriter/rewrite-modern-struct-ivar-1.mm @@ -34,7 +34,7 @@ @interface Foo{ @implementation Foo - (void)x:(Foo *)other { bar.x = 0; - bar.y = 1; + bar.y = -1; self->_internal._singleRange._range = (( other ->bar.x) ? &( other ->_internal._singleRange._range) : ((NSRange *)(&(((_NSRangeInfo *)( other ->_internal._multipleRanges._data))->_ranges))))[0]; } @end diff --git a/clang/test/Rewriter/rewrite-modern-struct-ivar.mm b/clang/test/Rewriter/rewrite-modern-struct-ivar.mm index 9f56cd8b1b837..f98bdbc460d32 100644 --- a/clang/test/Rewriter/rewrite-modern-struct-ivar.mm +++ b/clang/test/Rewriter/rewrite-modern-struct-ivar.mm @@ -41,10 +41,10 @@ @interface Foo{ @implementation Foo - (void)x { bar.x = 0; - bar.y = 1; + bar.y = -1; s.x = 0; - s.y = 1; + s.y = -1; } @end diff --git a/clang/test/Sema/constant-conversion.c b/clang/test/Sema/constant-conversion.c index 025f4709a7d5f..d386d21f24aad 100644 --- a/clang/test/Sema/constant-conversion.c +++ b/clang/test/Sema/constant-conversion.c @@ -15,8 +15,16 @@ void test_7809123(void) { } void test(void) { - struct { int bit : 1; } a; - a.bit = 1; // shouldn't warn + struct S { + int b : 1; // The only valid values are 0 and -1. + } s; + + s.b = -3; // expected-warning {{implicit truncation from 'int' to bit-field changes value from -3 to -1}} + s.b = -2; // expected-warning {{implicit truncation from 'int' to bit-field changes value from -2 to 0}} + s.b = -1; // no-warning + s.b = 0; // no-warning + s.b = 1; // expected-warning {{implicit truncation from 'int' to bit-field changes value from 1 to -1}} + s.b = 2; // expected-warning {{implicit truncation from 'int' to bit-field changes value from 2 to 0}} } enum Test2 { K_zero, K_one }; diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index e145ca982cdd0..c5742ad8c2cbb 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -2035,6 +2035,7 @@ namespace Bitfields { } }; static_assert(X::f(3) == -1, "3 should truncate to -1"); + static_assert(X::f(1) == -1, "1 should truncate to -1"); } struct HasUnnamedBitfield { diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index 13fe826759a34..305a9ac2ebc24 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -84,7 +84,7 @@ void enclosing() { (void)[outerbit1]{}; // expected-error {{'outerbit1' cannot be captured because it does not have automatic storage duration}} - auto [bit, var] = S2{1, 1}; // expected-note 2{{'bit' declared here}} + auto [bit, var] = S2{-1, 1}; // expected-note 2{{'bit' declared here}} (void)[&bit] { // expected-error {{non-const reference cannot bind to bit-field 'a'}} \ // expected-warning {{C++20}} diff --git a/clang/test/SemaCXX/decomposition-blocks.cpp b/clang/test/SemaCXX/decomposition-blocks.cpp index 21f66f8c7c1b8..0676463d12c78 100644 --- a/clang/test/SemaCXX/decomposition-blocks.cpp +++ b/clang/test/SemaCXX/decomposition-blocks.cpp @@ -7,7 +7,7 @@ struct S { void run(void (^)()); void test() { - auto [i, j] = S{1, 42}; // expected-note {{'i' declared here}} + auto [i, j] = S{-1, 42}; // expected-note {{'i' declared here}} run(^{ (void)i; // expected-error {{reference to local binding 'i' declared in enclosing function 'test'}} });