template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitArrayInitIndexExpr(
const ArrayInitIndexExpr *E) {
- assert(ArrayIndex);
+ // ArrayIndex might not be set if a ArrayInitIndexExpr is being evaluated
+ // stand-alone, e.g. via EvaluateAsInt().
+ if (!ArrayIndex)
+ return false;
QualType IndexType = E->getType();
APInt Value(getIntWidth(IndexType), *ArrayIndex);
return this->emitConst(classifyPrim(IndexType), 0, Value, E);
if (const auto *InitList = dyn_cast<InitListExpr>(Initializer)) {
unsigned ElementIndex = 0;
for (const Expr *Init : InitList->inits()) {
- QualType InitType = Init->getType();
-
- if (InitType->isArrayType()) {
+ if (Optional<PrimType> T = classify(Init->getType())) {
+ // Visit the primitive element like normal.
+ if (!this->emitDupPtr(Init))
+ return false;
+ if (!this->visit(Init))
+ return false;
+ if (!this->emitInitElem(*T, ElementIndex, Init))
+ return false;
+ } else {
// Advance the pointer currently on the stack to the given
// dimension and narrow().
if (!this->emitDupPtr(Init))
return false;
if (!this->emitNarrowPtr(Init))
return false;
- if (!visitArrayInitializer(Init))
+
+ if (!visitInitializer(Init))
return false;
+ }
if (!this->emitPopPtr(Init))
return false;
- } else if (Optional<PrimType> T = classify(InitType)) {
- // Visit the primitive element like normal.
- if (!this->emitDupPtr(Init))
- return false;
- if (!this->visit(Init))
- return false;
- if (!this->emitInitElemPop(*T, ElementIndex, Init))
- return false;
- } else {
- assert(false && "Unhandled type in array initializer initlist");
- }
++ElementIndex;
}
size_t Size = AILE->getArraySize().getZExtValue();
Optional<PrimType> ElemT = classify(SubExpr->getType());
- if (!ElemT)
- return false;
-
+ // So, every iteration, we execute an assignment here
+ // where the LHS is on the stack (the target array)
+ // and the RHS is our SubExpr.
for (size_t I = 0; I != Size; ++I) {
ArrayIndexScope<Emitter> IndexScope(this, I);
- if (!this->emitDupPtr(SubExpr))
- return false;
- if (!this->visit(SubExpr))
+ if (!this->emitDupPtr(SubExpr)) // LHS
return false;
- if (!this->emitInitElem(*ElemT, I, Initializer))
- return false;
+ if (ElemT) {
+ if (!this->visit(SubExpr))
+ return false;
+ if (!this->emitInitElem(*ElemT, I, Initializer))
+ return false;
+ } else {
+ // Narrow to our array element and recurse into visitInitializer()
+ if (!this->emitConstUint64(I, SubExpr))
+ return false;
+
+ if (!this->emitAddOffsetUint64(SubExpr))
+ return false;
+
+ if (!this->emitNarrowPtr(SubExpr))
+ return false;
+
+ if (!visitInitializer(SubExpr))
+ return false;
+ }
if (!this->emitPopPtr(Initializer))
return false;
/// 1) Pops the value from the stack
/// 2) Pops a pointer from the stack
-/// 3) Writes the value to field I of the pointer
+/// 3) Pushes the value to field I of the pointer on the stack
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
const T &Value = S.Stk.pop<T>();
return true;
}
+/// 1) Pops a Pointer from the stack
+/// 2) Pushes Pointer.atField(Off) on the stack
inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckNull(S, OpPC, Ptr, CSK_Field))
static_assert(foo() == 12, ""); // ref-error {{not an integral constant expression}} \
// ref-note {{in call to 'foo()'}}
};
+
+struct FourBoolPairs {
+ BoolPair v[4] = {
+ {false, false},
+ {false, true},
+ {true, false},
+ {true, true },
+ };
+};
+// Init
+constexpr FourBoolPairs LT;
+// Copy ctor
+constexpr FourBoolPairs LT2 = LT;
+// FIXME: The copy constructor call above
+// works, but APValue we generate for it is
+// not sufficiently correct, so the lvalue-to-rvalue
+// conversion in ExprConstant.c runs into an assertion.
+//static_assert(LT2.v[0].first == false, "");
+//static_assert(LT2.v[0].second == false, "");
+//static_assert(LT2.v[2].first == true, "");
+//static_assert(LT2.v[2].second == false, "");