Author: Timm Bäder Date: 2023-08-10T08:50:10+02:00 New Revision: 8065b1cc133c9e4b6900d5c11220617180706b94
URL: https://github.com/llvm/llvm-project/commit/8065b1cc133c9e4b6900d5c11220617180706b94 DIFF: https://github.com/llvm/llvm-project/commit/8065b1cc133c9e4b6900d5c11220617180706b94.diff LOG: [clang][Interp] Basic support for bit fields Differential Revision: https://reviews.llvm.org/D155270 Added: clang/test/AST/Interp/bitfields.cpp Modified: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeStmtGen.cpp clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Record.h Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 8a756e4fc2db42..4c0b599cbb182d 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -305,8 +305,10 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) { 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: @@ -1590,8 +1592,13 @@ bool ByteCodeExprGen<Emitter>::visitRecordInitializer(const Expr *Initializer) { 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; diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp index e54805cd931aef..cce706778e3544 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -169,8 +169,13 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) { 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. diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index c278144a387130..f1fb4e34114e17 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1007,6 +1007,7 @@ bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) { template <PrimType Name, class T = typename PrimConv<Name>::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(); @@ -1048,8 +1049,9 @@ bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) { template <PrimType Name, class T = typename PrimConv<Name>::T> bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { + assert(F->isBitField()); const T &Value = S.Stk.pop<T>(); - const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset); + const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset); Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx())); Field.activate(); Field.initialize(); @@ -1247,11 +1249,10 @@ bool StoreBitField(InterpState &S, CodePtr OpPC) { return false; if (!Ptr.isRoot()) Ptr.initialize(); - if (auto *FD = Ptr.getField()) { + if (const auto *FD = Ptr.getField()) Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx())); - } else { + else Ptr.deref<T>() = Value; - } return true; } @@ -1263,11 +1264,10 @@ bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) { return false; if (!Ptr.isRoot()) Ptr.initialize(); - if (auto *FD = Ptr.getField()) { + if (const auto *FD = Ptr.getField()) Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx())); - } else { + else Ptr.deref<T>() = Value; - } return true; } diff --git a/clang/lib/AST/Interp/Record.h b/clang/lib/AST/Interp/Record.h index 940b4c9ebf592a..5219734f845102 100644 --- a/clang/lib/AST/Interp/Record.h +++ b/clang/lib/AST/Interp/Record.h @@ -29,6 +29,7 @@ class Record final { const FieldDecl *Decl; unsigned Offset; Descriptor *Desc; + bool isBitField() const { return Decl->isBitField(); } }; /// Describes a base class. diff --git a/clang/test/AST/Interp/bitfields.cpp b/clang/test/AST/Interp/bitfields.cpp new file mode 100644 index 00000000000000..e078704fce51ff --- /dev/null +++ b/clang/test/AST/Interp/bitfields.cpp @@ -0,0 +1,47 @@ +// 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. +} + +namespace Overflow { + struct A {int c:3;}; + + constexpr int f() { + A a1{3}; + return a1.c++; + } + + static_assert(f() == 3, ""); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits