return false;
}
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitArrayInitIndexExpr(
+ const ArrayInitIndexExpr *E) {
+ assert(ArrayIndex);
+ return this->emitConstUint64(*ArrayIndex, E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
+ return this->visit(E->getSourceExpr());
+}
+
template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true);
return this->Visit(E);
return true;
} else if (const auto *DIE = dyn_cast<CXXDefaultInitExpr>(Initializer)) {
return this->visitInitializer(DIE->getExpr());
+ } else if (const auto *AILE = dyn_cast<ArrayInitLoopExpr>(Initializer)) {
+ // TODO: This compiles to quite a lot of bytecode if the array is larger.
+ // Investigate compiling this to a loop, or at least try to use
+ // the AILE's Common expr.
+ const Expr *SubExpr = AILE->getSubExpr();
+ size_t Size = AILE->getArraySize().getZExtValue();
+ Optional<PrimType> ElemT = classify(SubExpr->getType());
+
+ if (!ElemT)
+ return false;
+
+ for (size_t I = 0; I != Size; ++I) {
+ ArrayIndexScope<Emitter> IndexScope(this, I);
+ if (!this->emitDupPtr(SubExpr))
+ return false;
+
+ if (!this->visit(SubExpr))
+ return false;
+
+ if (!this->emitInitElem(*ElemT, I, Initializer))
+ return false;
+
+ if (!this->emitPopPtr(Initializer))
+ return false;
+ }
+ return true;
}
assert(false && "Unknown expression for array initialization");
if (const auto CtorExpr = dyn_cast<CXXConstructExpr>(Initializer)) {
const Function *Func = getFunction(CtorExpr->getConstructor());
- if (!Func)
+ if (!Func || !Func->isConstexpr())
return false;
// The This pointer is already on the stack because this is an initializer,
// but we need to dup() so the call() below has its own copy.
if (!this->emitDupPtr(Initializer))
return false;
+
+ // Constructor arguments.
+ for (const auto *Arg : CtorExpr->arguments()) {
+ if (!this->visit(Arg))
+ return false;
+ }
+
return this->emitCallVoid(Func, Initializer);
} else if (const auto *InitList = dyn_cast<InitListExpr>(Initializer)) {
const Record *R = getRecord(InitList->getType());
for (const Expr *Init : InitList->inits()) {
const Record::Field *FieldToInit = R->getField(InitIndex);
- if (Optional<PrimType> T = classify(Init->getType())) {
- if (!this->emitDupPtr(Initializer))
- return false;
+ if (!this->emitDupPtr(Initializer))
+ return false;
+ if (Optional<PrimType> T = classify(Init->getType())) {
if (!this->visit(Init))
return false;
if (!this->emitInitField(*T, FieldToInit->Offset, Initializer))
return false;
+ } else {
+ // Non-primitive case. Get a pointer to the field-to-initialize
+ // on the stack and recurse into visitInitializer().
+ if (!this->emitGetPtrField(FieldToInit->Offset, Init))
+ return false;
+
+ if (!this->visitInitializer(Init))
+ return false;
+
+ if (!this->emitPopPtr(Initializer))
+ return false;
}
++InitIndex;
}
template <class Emitter> class VariableScope;
template <class Emitter> class DeclScope;
template <class Emitter> class OptionScope;
+template <class Emitter> class ArrayIndexScope;
/// Compilation context for expressions.
template <class Emitter>
bool VisitConstantExpr(const ConstantExpr *E);
bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
bool VisitMemberExpr(const MemberExpr *E);
+ bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);
+ bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);
protected:
bool visitExpr(const Expr *E) override;
friend class RecordScope<Emitter>;
friend class DeclScope<Emitter>;
friend class OptionScope<Emitter>;
+ friend class ArrayIndexScope<Emitter>;
/// Emits a zero initializer.
bool visitZeroInitializer(PrimType T, const Expr *E);
/// Current scope.
VariableScope<Emitter> *VarScope = nullptr;
- /// Current argument index.
+ /// Current argument index. Needed to emit ArrayInitIndexExpr.
llvm::Optional<uint64_t> ArrayIndex;
/// Flag indicating if return value is to be discarded.
}
};
+template <class Emitter> class ArrayIndexScope final {
+public:
+ ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
+ OldArrayIndex = Ctx->ArrayIndex;
+ Ctx->ArrayIndex = Index;
+ }
+
+ ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }
+
+private:
+ ByteCodeExprGen<Emitter> *Ctx;
+ Optional<uint64_t> OldArrayIndex;
+};
+
} // namespace interp
} // namespace clang
const Record::Field *F = R->getField(Member);
if (Optional<PrimType> T = this->classify(InitExpr->getType())) {
- if (!this->emitDupPtr(InitExpr))
+ if (!this->emitThis(InitExpr))
return false;
if (!this->visit(InitExpr))
} else {
// Non-primitive case. Get a pointer to the field-to-initialize
// on the stack and call visitInitialzer() for it.
- if (!this->emitDupPtr(InitExpr))
+ if (!this->emitThis(InitExpr))
return false;
if (!this->emitGetPtrField(F->Offset, InitExpr))
static_assert(ints.b == 30, "");
static_assert(ints.c, "");
static_assert(ints.getTen() == 10, "");
+static_assert(ints.numbers[0] == 1, "");
+static_assert(ints.numbers[1] == 2, "");
+static_assert(ints.numbers[2] == 3, "");
constexpr const BoolPair &BP = ints.bp;
static_assert(BP.first, "");
static_assert(ints4.a == (40 * 50), "");
static_assert(ints4.b == 0, "");
static_assert(ints4.c, "");
-
-
-// FIXME: Implement initialization by DeclRefExpr.
-//constexpr Ints ints4 = ints3; TODO
-
+static_assert(ints4.numbers[0] == 1, "");
+static_assert(ints4.numbers[1] == 2, "");
+static_assert(ints4.numbers[2] == 3, "");
+
+constexpr Ints ints5 = ints4;
+static_assert(ints5.a == (40 * 50), "");
+static_assert(ints5.b == 0, "");
+static_assert(ints5.c, "");
+static_assert(ints5.numbers[0] == 1, "");
+static_assert(ints5.numbers[1] == 2, "");
+static_assert(ints5.numbers[2] == 3, "");
struct Ints2 {