diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 950a57589189..8d01352fd221 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3655,19 +3655,20 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, if (OriginalWidth <= FieldWidth) return false; + // Compute the value which the bitfield will contain. llvm::APSInt TruncatedValue = Value.trunc(FieldWidth); + TruncatedValue.setIsSigned(Bitfield->getType()->isSignedIntegerType()); - // It's fairly common to write values into signed bitfields - // that, if sign-extended, would end up becoming a different - // value. We don't want to warn about that. - if (Value.isSigned() && Value.isNegative()) - TruncatedValue = TruncatedValue.sext(OriginalWidth); - else - TruncatedValue = TruncatedValue.zext(OriginalWidth); - + // Check whether the stored value is equal to the original value. + TruncatedValue = TruncatedValue.extend(OriginalWidth); if (Value == TruncatedValue) return false; + // Special-case bitfields of width 1: booleans are naturally 0/1, and + // therefore don't strictly fit into a bitfield of width 1. + if (FieldWidth == 1 && Value.getBoolValue() == TruncatedValue.getBoolValue()) + return false; + std::string PrettyValue = Value.toString(10); std::string PrettyTrunc = TruncatedValue.toString(10); diff --git a/clang/test/Sema/constant-conversion.c b/clang/test/Sema/constant-conversion.c index a2c48d3549c8..c97eb05cd190 100644 --- a/clang/test/Sema/constant-conversion.c +++ b/clang/test/Sema/constant-conversion.c @@ -31,8 +31,8 @@ void test3() { int bar : 2; }; - struct A a = { 0, 10 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}} - struct A b[] = { 0, 10, 0, 0 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}} + struct A a = { 0, 10 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to -2}} + struct A b[] = { 0, 10, 0, 0 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to -2}} struct A c[] = {{10, 0}}; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}} struct A d = (struct A) { 10, 0 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}} struct A e = { .foo = 10 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}} @@ -62,3 +62,13 @@ void test6() { unsigned char y = 1 ? 65535 : 1; // expected-warning {{changes value}} } +void test7() { + struct { + unsigned int twoBits1:2; + unsigned int twoBits2:2; + unsigned int reserved:28; + } f; + + f.twoBits1 = ~1; // expected-warning {{implicit truncation from 'int' to bitfield changes value from -2 to 2}} + f.twoBits2 = ~2; // expected-warning {{implicit truncation from 'int' to bitfield changes value from -3 to 1}} +}