r187782 - PR16755: When initializing or modifying a bitfield member in a constant
Richard Smith
richard-llvm at metafoo.co.uk
Tue Aug 6 00:09:20 PDT 2013
Author: rsmith
Date: Tue Aug 6 02:09:20 2013
New Revision: 187782
URL: http://llvm.org/viewvc/llvm-project?rev=187782&view=rev
Log:
PR16755: When initializing or modifying a bitfield member in a constant
expression, truncate the stored value to the size of the bitfield.
Modified:
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=187782&r1=187781&r2=187782&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Aug 6 02:09:20 2013
@@ -1386,6 +1386,27 @@ static bool HandleIntToFloatCast(EvalInf
return true;
}
+static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
+ APValue &Value, const FieldDecl *FD) {
+ assert(FD->isBitField() && "truncateBitfieldValue on non-bitfield");
+
+ if (!Value.isInt()) {
+ // Trying to store a pointer-cast-to-integer into a bitfield.
+ // FIXME: In this case, we should provide the diagnostic for casting
+ // a pointer to an integer.
+ assert(Value.isLValue() && "integral value neither int nor lvalue?");
+ Info.Diag(E);
+ return false;
+ }
+
+ APSInt &Int = Value.getInt();
+ unsigned OldBitWidth = Int.getBitWidth();
+ unsigned NewBitWidth = FD->getBitWidthValue(Info.Ctx);
+ if (NewBitWidth < OldBitWidth)
+ Int = Int.trunc(NewBitWidth).extend(OldBitWidth);
+ return true;
+}
+
static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E,
llvm::APInt &Res) {
APValue SVal;
@@ -1953,6 +1974,8 @@ findSubobject(EvalInfo &Info, const Expr
APValue *O = Obj.Value;
QualType ObjType = Obj.Type;
+ const FieldDecl *LastField = 0;
+
// Walk the designator's path to find the subobject.
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
if (O->isUninit()) {
@@ -1961,9 +1984,20 @@ findSubobject(EvalInfo &Info, const Expr
return handler.failed();
}
- if (I == N)
- return handler.found(*O, ObjType);
+ if (I == N) {
+ if (!handler.found(*O, ObjType))
+ return false;
+
+ // If we modified a bit-field, truncate it to the right width.
+ if (handler.AccessKind != AK_Read &&
+ LastField && LastField->isBitField() &&
+ !truncateBitfieldValue(Info, E, *O, LastField))
+ return false;
+ return true;
+ }
+
+ LastField = 0;
if (ObjType->isArrayType()) {
// Next subobject is an array element.
const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType);
@@ -2065,6 +2099,8 @@ findSubobject(EvalInfo &Info, const Expr
}
return handler.failed();
}
+
+ LastField = Field;
} else {
// Next subobject is a base class.
const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl();
@@ -3522,6 +3558,7 @@ static bool HandleConstructorCall(Source
APValue *Value = &Result;
// Determine the subobject to initialize.
+ FieldDecl *FD = 0;
if ((*I)->isBaseInitializer()) {
QualType BaseType((*I)->getBaseClass(), 0);
#ifndef NDEBUG
@@ -3536,7 +3573,7 @@ static bool HandleConstructorCall(Source
BaseType->getAsCXXRecordDecl(), &Layout))
return false;
Value = &Result.getStructBase(BasesSeen++);
- } else if (FieldDecl *FD = (*I)->getMember()) {
+ } else if ((FD = (*I)->getMember())) {
if (!HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout))
return false;
if (RD->isUnion()) {
@@ -3551,7 +3588,7 @@ static bool HandleConstructorCall(Source
for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(),
CE = IFD->chain_end();
C != CE; ++C) {
- FieldDecl *FD = cast<FieldDecl>(*C);
+ FD = cast<FieldDecl>(*C);
CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent());
// Switch the union field if it differs. This happens if we had
// preceding zero-initialization, and we're now initializing a union
@@ -3578,7 +3615,9 @@ static bool HandleConstructorCall(Source
}
FullExpressionRAII InitScope(Info);
- if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit())) {
+ if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit()) ||
+ (FD && FD->isBitField() && !truncateBitfieldValue(Info, (*I)->getInit(),
+ *Value, FD))) {
// If we're checking for a potential constant expression, evaluate all
// initializers even if some of them fail.
if (!Info.keepEvaluatingAfterFailure())
@@ -4918,8 +4957,10 @@ bool RecordExprEvaluator::VisitInitListE
ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This,
isa<CXXDefaultInitExpr>(Init));
- if (!EvaluateInPlace(Result.getStructField(Field->getFieldIndex()), Info,
- Subobject, Init)) {
+ APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
+ if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
+ (Field->isBitField() && !truncateBitfieldValue(Info, Init,
+ FieldVal, *Field))) {
if (!Info.keepEvaluatingAfterFailure())
return false;
Success = false;
Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=187782&r1=187781&r2=187782&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Tue Aug 6 02:09:20 2013
@@ -1727,3 +1727,40 @@ namespace Lifetime {
constexpr int k1 = S().t; // ok, int is lifetime-extended to end of constructor
constexpr int k2 = S(0).t; // expected-error {{constant expression}} expected-note {{in call}}
}
+
+namespace Bitfields {
+ struct A {
+ bool b : 1;
+ unsigned u : 5;
+ int n : 5;
+ bool b2 : 3;
+ unsigned u2 : 74; // expected-warning {{exceeds the size of its type}}
+ int n2 : 81; // expected-warning {{exceeds the size of its type}}
+ };
+
+ constexpr A a = { false, 33, 31, false, 0xffffffff, 0x7fffffff }; // expected-warning 2{{truncation}}
+ static_assert(a.b == 0 && a.u == 1 && a.n == -1 && a.b2 == 0 &&
+ a.u2 + 1 == 0 && a.n2 == 0x7fffffff,
+ "bad truncation of bitfield values");
+
+ struct B {
+ int n : 3;
+ constexpr B(int k) : n(k) {}
+ };
+ static_assert(B(3).n == 3, "");
+ static_assert(B(4).n == -4, "");
+ static_assert(B(7).n == -1, "");
+ static_assert(B(8).n == 0, "");
+ static_assert(B(-1).n == -1, "");
+ static_assert(B(-8889).n == -1, "");
+
+ namespace PR16755 {
+ struct X {
+ int x : 1;
+ constexpr static int f(int x) {
+ return X{x}.x;
+ }
+ };
+ static_assert(X::f(3) == -1, "3 should truncate to -1");
+ }
+}
Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp?rev=187782&r1=187781&r2=187782&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp Tue Aug 6 02:09:20 2013
@@ -870,3 +870,20 @@ namespace Lifetime {
}
static_assert((lifetime_versus_loops(), true), "");
}
+
+namespace Bitfields {
+ struct A {
+ bool b : 3;
+ int n : 4;
+ unsigned u : 5;
+ };
+ constexpr bool test() {
+ A a {};
+ a.b += 2;
+ --a.n;
+ --a.u;
+ a.n = -a.n * 3;
+ return a.b == false && a.n == 3 && a.u == 31;
+ }
+ static_assert(test(), "");
+}
More information about the cfe-commits
mailing list