PrimType Ty,
bool IsConst,
bool IsExtended) {
- // Make sure we don't accidentally register the same decl twice.
- if (const auto *VD =
- dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
- assert(!P.getGlobal(VD));
- assert(Locals.find(VD) == Locals.end());
- }
-
// FIXME: There are cases where Src.is<Expr*>() is wrong, e.g.
// (int){12} in C. Consider using Expr::isTemporaryObject() instead
// or isa<MaterializeTemporaryExpr>().
template <class Emitter>
std::optional<unsigned>
ByteCodeExprGen<Emitter>::allocateLocal(DeclTy &&Src, bool IsExtended) {
- // Make sure we don't accidentally register the same decl twice.
- if (const auto *VD =
- dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
- assert(!P.getGlobal(VD));
- assert(Locals.find(VD) == Locals.end());
- }
-
QualType Ty;
+
const ValueDecl *Key = nullptr;
const Expr *Init = nullptr;
bool IsTemporary = false;
return this->emitRetValue(Exp);
}
-/// Toplevel visitDecl().
-/// We get here from evaluateAsInitializer().
-/// We need to evaluate the initializer and return its value.
template <class Emitter>
bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
- std::optional<PrimType> VarT = classify(VD->getType());
-
- // Create and initialize the variable.
- if (!this->visitVarDecl(VD))
- return false;
-
- // Get a pointer to the variable
- if (shouldBeGloballyIndexed(VD)) {
- auto GlobalIndex = P.getGlobal(VD);
- assert(GlobalIndex); // visitVarDecl() didn't return false.
- if (!this->emitGetPtrGlobal(*GlobalIndex, VD))
- return false;
- } else {
- auto Local = Locals.find(VD);
- assert(Local != Locals.end()); // Same here.
- if (!this->emitGetPtrLocal(Local->second.Offset, VD))
- return false;
- }
-
- // Return the value
- if (VarT) {
- if (!this->emitLoadPop(*VarT, VD))
- return false;
-
- return this->emitRet(*VarT, VD);
- }
-
- return this->emitRetValue(VD);
-}
-
-template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
const Expr *Init = VD->getInit();
- std::optional<PrimType> VarT = classify(VD->getType());
-
- if (shouldBeGloballyIndexed(VD)) {
- std::optional<unsigned> GlobalIndex = P.getOrCreateGlobal(VD, Init);
-
- if (!GlobalIndex)
- return this->bail(VD);
-
- assert(Init);
- {
- DeclScope<Emitter> LocalScope(this, VD);
- if (VarT) {
- if (!this->visit(Init))
+ if (std::optional<unsigned> I = P.createGlobal(VD, Init)) {
+ if (std::optional<PrimType> T = classify(VD->getType())) {
+ {
+ // Primitive declarations - compute the value and set it.
+ DeclScope<Emitter> LocalScope(this, VD);
+ if (!visit(Init))
return false;
- return this->emitInitGlobal(*VarT, *GlobalIndex, VD);
}
- return this->visitGlobalInitializer(Init, *GlobalIndex);
- }
- } else {
- DeclScope<Emitter> LocalScope(this, VD);
-
- if (VarT) {
- unsigned Offset = this->allocateLocalPrimitive(
- VD, *VarT, VD->getType().isConstQualified());
- // Compile the initializer in its own scope.
- if (Init) {
- ExprScope<Emitter> Scope(this);
- if (!this->visit(Init))
- return false;
- return this->emitSetLocal(*VarT, Offset, VD);
- }
+ // If the declaration is global, save the value for later use.
+ if (!this->emitDup(*T, VD))
+ return false;
+ if (!this->emitInitGlobal(*T, *I, VD))
+ return false;
+ return this->emitRet(*T, VD);
} else {
- if (std::optional<unsigned> Offset = this->allocateLocal(VD)) {
- if (Init)
- return this->visitLocalInitializer(Init, *Offset);
+ {
+ // Composite declarations - allocate storage and initialize it.
+ DeclScope<Emitter> LocalScope(this, VD);
+ if (!visitGlobalInitializer(Init, *I))
+ return false;
}
+
+ // Return a pointer to the global.
+ if (!this->emitGetPtrGlobal(*I, VD))
+ return false;
+ return this->emitRetValue(VD);
}
- return true;
}
- return false;
+ return this->bail(VD);
}
template <class Emitter>
for (auto *D : DS->decls()) {
// Variable declarator.
if (auto *VD = dyn_cast<VarDecl>(D)) {
- if (!this->visitVarDecl(VD))
+ if (!visitVarDecl(VD))
return false;
continue;
}
return this->jump(*ContinueLabel);
}
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
+ if (!VD->hasLocalStorage()) {
+ // No code generation required.
+ return true;
+ }
+
+ // Integers, pointers, primitives.
+ if (std::optional<PrimType> T = this->classify(VD->getType())) {
+ const Expr *Init = VD->getInit();
+
+ unsigned Offset =
+ this->allocateLocalPrimitive(VD, *T, VD->getType().isConstQualified());
+ // Compile the initializer in its own scope.
+ if (Init) {
+ ExprScope<Emitter> Scope(this);
+ if (!this->visit(Init))
+ return false;
+
+ return this->emitSetLocal(*T, Offset, VD);
+ }
+ return true;
+ }
+
+ // Composite types - allocate storage and initialize it.
+ if (std::optional<unsigned> Offset = this->allocateLocal(VD)) {
+ if (!VD->getInit())
+ return true;
+
+ return this->visitLocalInitializer(VD->getInit(), *Offset);
+ }
+
+ return this->bail(VD);
+}
+
namespace clang {
namespace interp {