Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -282,8 +282,10 @@ return Discard(this->emitDiv(*T, BO)); case BO_Assign: if (DiscardResult) - return this->emitStorePop(*T, BO); - return this->emitStore(*T, BO); + return LHS->refersToBitField() ? this->emitStoreBitFieldPop(*T, BO) + : this->emitStorePop(*T, BO); + return LHS->refersToBitField() ? this->emitStoreBitField(*T, BO) + : this->emitStore(*T, BO); case BO_And: return Discard(this->emitBitAnd(*T, BO)); case BO_Or: @@ -1474,8 +1476,13 @@ if (!this->visit(Init)) return false; - if (!this->emitInitField(*T, FieldToInit->Offset, Initializer)) - return false; + if (FieldToInit->isBitField()) { + if (!this->emitInitBitField(*T, FieldToInit, Initializer)) + return false; + } else { + if (!this->emitInitField(*T, FieldToInit->Offset, Initializer)) + return false; + } if (!this->emitPopPtr(Initializer)) return false; Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -113,8 +113,13 @@ if (!this->visit(InitExpr)) return false; - if (!this->emitInitThisField(*T, F->Offset, InitExpr)) - return false; + if (F->isBitField()) { + if (!this->emitInitThisBitField(*T, F, InitExpr)) + return false; + } else { + if (!this->emitInitThisField(*T, F->Offset, InitExpr)) + return false; + } } else { // Non-primitive case. Get a pointer to the field-to-initialize // on the stack and call visitInitialzer() for it. Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -965,6 +965,7 @@ template ::T> bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { + assert(F->isBitField()); if (S.checkingPotentialConstantExpression()) return false; const Pointer &This = S.Current->getThis(); @@ -1006,8 +1007,9 @@ template ::T> bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { + assert(F->isBitField()); const T &Value = S.Stk.pop(); - const Pointer &Field = S.Stk.pop().atField(F->Offset); + const Pointer &Field = S.Stk.peek().atField(F->Offset); Field.deref() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx())); Field.activate(); Field.initialize(); @@ -1205,11 +1207,10 @@ return false; if (!Ptr.isRoot()) Ptr.initialize(); - if (auto *FD = Ptr.getField()) { + if (const auto *FD = Ptr.getField()) Ptr.deref() = Value.truncate(FD->getBitWidthValue(S.getCtx())); - } else { + else Ptr.deref() = Value; - } return true; } @@ -1221,11 +1222,10 @@ return false; if (!Ptr.isRoot()) Ptr.initialize(); - if (auto *FD = Ptr.getField()) { + if (const auto *FD = Ptr.getField()) Ptr.deref() = Value.truncate(FD->getBitWidthValue(S.getCtx())); - } else { + else Ptr.deref() = Value; - } return true; } Index: clang/lib/AST/Interp/Record.h =================================================================== --- clang/lib/AST/Interp/Record.h +++ clang/lib/AST/Interp/Record.h @@ -29,6 +29,7 @@ const FieldDecl *Decl; unsigned Offset; Descriptor *Desc; + bool isBitField() const { return Decl->isBitField(); } }; /// Describes a base class. Index: clang/test/AST/Interp/bitfields.cpp =================================================================== --- /dev/null +++ clang/test/AST/Interp/bitfields.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -Wno-bitfield-constant-conversion -verify %s +// RUN: %clang_cc1 -verify=ref -Wno-bitfield-constant-conversion %s + +// expected-no-diagnostics +// ref-no-diagnostics + +namespace Basic { + struct A { + unsigned int a : 2; + constexpr A() : a(0) {} + constexpr A(int a) : a(a) {} + }; + + constexpr A a{1}; + static_assert(a.a == 1, ""); + + constexpr A a2{10}; + static_assert(a2.a == 2, ""); + + + constexpr int storeA() { + A a; + a.a = 10; + + return a.a; + } + static_assert(storeA() == 2, ""); + + constexpr int storeA2() { + A a; + return a.a = 10; + } + static_assert(storeA2() == 2, ""); + + // TODO: +=, -=, etc. operators. +}