Skip to content

Commit 6172960

Browse files
committed
[clang][Interp] Basic support for bit fields
Differential Revision: https://reviews.llvm.org/D155548
1 parent b4343ab commit 6172960

File tree

5 files changed

+75
-13
lines changed

5 files changed

+75
-13
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

+13-4
Original file line numberDiff line numberDiff line change
@@ -342,8 +342,10 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
342342
return Discard(this->emitDiv(*T, BO));
343343
case BO_Assign:
344344
if (DiscardResult)
345-
return this->emitStorePop(*T, BO);
346-
return this->emitStore(*T, BO);
345+
return LHS->refersToBitField() ? this->emitStoreBitFieldPop(*T, BO)
346+
: this->emitStorePop(*T, BO);
347+
return LHS->refersToBitField() ? this->emitStoreBitField(*T, BO)
348+
: this->emitStore(*T, BO);
347349
case BO_And:
348350
return Discard(this->emitBitAnd(*T, BO));
349351
case BO_Or:
@@ -547,8 +549,15 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
547549
const Record::Field *FieldToInit = R->getField(InitIndex);
548550
if (!this->visit(Init))
549551
return false;
550-
if (!this->emitInitField(*T, FieldToInit->Offset, E))
551-
return false;
552+
553+
if (FieldToInit->isBitField()) {
554+
if (!this->emitInitBitField(*T, FieldToInit, E))
555+
return false;
556+
} else {
557+
if (!this->emitInitField(*T, FieldToInit->Offset, E))
558+
return false;
559+
}
560+
552561
if (!this->emitPopPtr(E))
553562
return false;
554563
++InitIndex;

clang/lib/AST/Interp/ByteCodeStmtGen.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,13 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
166166
if (!this->visit(InitExpr))
167167
return false;
168168

169-
if (!this->emitInitThisField(*T, F->Offset, InitExpr))
170-
return false;
169+
if (F->isBitField()) {
170+
if (!this->emitInitThisBitField(*T, F, InitExpr))
171+
return false;
172+
} else {
173+
if (!this->emitInitThisField(*T, F->Offset, InitExpr))
174+
return false;
175+
}
171176
} else {
172177
// Non-primitive case. Get a pointer to the field-to-initialize
173178
// on the stack and call visitInitialzer() for it.

clang/lib/AST/Interp/Interp.h

+7-7
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,7 @@ bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
10711071

10721072
template <PrimType Name, class T = typename PrimConv<Name>::T>
10731073
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1074+
assert(F->isBitField());
10741075
if (S.checkingPotentialConstantExpression())
10751076
return false;
10761077
const Pointer &This = S.Current->getThis();
@@ -1112,8 +1113,9 @@ bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
11121113

11131114
template <PrimType Name, class T = typename PrimConv<Name>::T>
11141115
bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1116+
assert(F->isBitField());
11151117
const T &Value = S.Stk.pop<T>();
1116-
const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
1118+
const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
11171119
Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
11181120
Field.activate();
11191121
Field.initialize();
@@ -1334,11 +1336,10 @@ bool StoreBitField(InterpState &S, CodePtr OpPC) {
13341336
return false;
13351337
if (!Ptr.isRoot())
13361338
Ptr.initialize();
1337-
if (auto *FD = Ptr.getField()) {
1339+
if (const auto *FD = Ptr.getField())
13381340
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1339-
} else {
1341+
else
13401342
Ptr.deref<T>() = Value;
1341-
}
13421343
return true;
13431344
}
13441345

@@ -1350,11 +1351,10 @@ bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
13501351
return false;
13511352
if (!Ptr.isRoot())
13521353
Ptr.initialize();
1353-
if (auto *FD = Ptr.getField()) {
1354+
if (const auto *FD = Ptr.getField())
13541355
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1355-
} else {
1356+
else
13561357
Ptr.deref<T>() = Value;
1357-
}
13581358
return true;
13591359
}
13601360

clang/lib/AST/Interp/Record.h

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class Record final {
2929
const FieldDecl *Decl;
3030
unsigned Offset;
3131
Descriptor *Desc;
32+
bool isBitField() const { return Decl->isBitField(); }
3233
};
3334

3435
/// Describes a base class.

clang/test/AST/Interp/bitfields.cpp

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -Wno-bitfield-constant-conversion -verify %s
2+
// RUN: %clang_cc1 -verify=ref -Wno-bitfield-constant-conversion %s
3+
4+
// expected-no-diagnostics
5+
// ref-no-diagnostics
6+
7+
namespace Basic {
8+
struct A {
9+
unsigned int a : 2;
10+
constexpr A() : a(0) {}
11+
constexpr A(int a) : a(a) {}
12+
};
13+
14+
constexpr A a{1};
15+
static_assert(a.a == 1, "");
16+
17+
constexpr A a2{10};
18+
static_assert(a2.a == 2, "");
19+
20+
21+
constexpr int storeA() {
22+
A a;
23+
a.a = 10;
24+
25+
return a.a;
26+
}
27+
static_assert(storeA() == 2, "");
28+
29+
constexpr int storeA2() {
30+
A a;
31+
return a.a = 10;
32+
}
33+
static_assert(storeA2() == 2, "");
34+
35+
// TODO: +=, -=, etc. operators.
36+
}
37+
38+
namespace Overflow {
39+
struct A {int c:3;};
40+
41+
constexpr int f() {
42+
A a1{3};
43+
return a1.c++;
44+
}
45+
46+
static_assert(f() == 3, "");
47+
}

0 commit comments

Comments
 (0)