From: Eli Friedman Date: Thu, 26 Jan 2012 23:11:39 +0000 (+0000) Subject: Make the bitfield implicit truncation warning slightly more aggressive, and make... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3a643afa402d51b5fc4faccb4329e9c4392d4551;p=clang Make the bitfield implicit truncation warning slightly more aggressive, and make the printed warning a bit more accurate. The new behavior matches gcc's -Wconversion. . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149089 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 950a575891..8d01352fd2 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/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/test/Sema/constant-conversion.c b/test/Sema/constant-conversion.c index a2c48d3549..c97eb05cd1 100644 --- a/test/Sema/constant-conversion.c +++ b/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}} +}