Index: clang/lib/AST/Interp/ByteCodeExprGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -93,8 +93,8 @@ protected: bool visitExpr(const Expr *E) override; bool visitDecl(const VarDecl *VD) override; + bool visitVarDecl(const VarDecl *VD); -protected: /// Emits scope cleanup instructions. void emitCleanup(); @@ -275,6 +275,12 @@ /// Expression being initialized. llvm::Optional InitFn = {}; + + /// Returns whether we should create a global variable for the + /// given VarDecl. + bool isGlobalDecl(const VarDecl *VD) const { + return !VD->hasLocalStorage() || VD->isConstexpr(); + } }; extern template class ByteCodeExprGen; Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -799,6 +799,12 @@ PrimType Ty, bool IsConst, bool IsExtended) { + // Make sure we don't accidentally register the same decl twice. + if (auto *VD = dyn_cast_if_present(Src.dyn_cast())) { + assert(!P.getGlobal(VD)); + assert(Locals.find(VD) == Locals.end()); + } + const Descriptor::MetadataSize MDSize{sizeof(InlineDescriptor)}; Descriptor *D = P.createDescriptor(Src, Ty, MDSize, IsConst, Src.is()); @@ -812,6 +818,12 @@ template llvm::Optional ByteCodeExprGen::allocateLocal(DeclTy &&Src, bool IsExtended) { + // Make sure we don't accidentally register the same decl twice. + if (auto *VD = dyn_cast_if_present(Src.dyn_cast())) { + assert(!P.getGlobal(VD)); + assert(Locals.find(VD) == Locals.end()); + } + const Descriptor::MetadataSize MDSize{sizeof(InlineDescriptor)}; QualType Ty; @@ -1096,41 +1108,87 @@ return this->emitRetValue(Exp); } +/// Toplevel visitDecl(). +/// We get here from evaluateAsInitializer(). +/// We need to evaluate the initializer and return its value. template bool ByteCodeExprGen::visitDecl(const VarDecl *VD) { - const Expr *Init = VD->getInit(); + Optional VarT = classify(VD->getType()); - if (Optional I = P.createGlobal(VD, Init)) { - if (Optional T = classify(VD->getType())) { - { - // Primitive declarations - compute the value and set it. - DeclScope LocalScope(this, VD); - if (!visit(Init)) - return false; - } + // Create and initialize the variable. + if (!this->visitVarDecl(VD)) + return false; - // If the declaration is global, save the value for later use. - if (!this->emitDup(*T, VD)) + // Get a pointer to the variable + if (isGlobalDecl(VD)) { + if (auto GlobalIndex = P.getGlobal(VD)) { + if (!this->emitGetPtrGlobal(*GlobalIndex, VD)) return false; - if (!this->emitInitGlobal(*T, *I, VD)) + } + } else { + if (auto It = Locals.find(VD); It != Locals.end()) { + if (!this->emitGetPtrLocal(It->second.Offset, VD)) return false; - return this->emitRet(*T, VD); - } else { - { - // Composite declarations - allocate storage and initialize it. - DeclScope LocalScope(this, VD); - if (!visitGlobalInitializer(Init, *I)) + } + } + + // Return the value + if (VarT) { + if (!this->emitLoadPop(*VarT, VD)) + return false; + + return this->emitRet(*VarT, VD); + } + + return this->emitRetValue(VD); +} + +template +bool ByteCodeExprGen::visitVarDecl(const VarDecl *VD) { + const Expr *Init = VD->getInit(); + Optional VarT = classify(VD->getType()); + + if (isGlobalDecl(VD)) { + Optional GlobalIndex = P.getOrCreateGlobal(VD, Init); + + if (!GlobalIndex) + return this->bail(VD); + + { + DeclScope LocalScope(this, VD); + + if (VarT) { + if (!this->visit(Init)) return false; + return this->emitInitGlobal(*VarT, *GlobalIndex, VD); } + return this->visitGlobalInitializer(Init, *GlobalIndex); + } + } else { + DeclScope LocalScope(this, VD); + + if (VarT) { + unsigned Offset = this->allocateLocalPrimitive( + VD, *VarT, VD->getType().isConstQualified()); + // Compile the initializer in its own scope. + if (Init) { + ExprScope Scope(this); + if (!this->visit(Init)) + return false; - // Return a pointer to the global. - if (!this->emitGetPtrGlobal(*I, VD)) - return false; - return this->emitRetValue(VD); + return this->emitSetLocal(*VarT, Offset, VD); + } + return true; + } else { + if (Optional Offset = this->allocateLocal(VD)) { + if (Init) + return this->visitLocalInitializer(Init, *Offset); + return true; + } } } - return this->bail(VD); + return false; } template Index: clang/lib/AST/Interp/ByteCodeStmtGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeStmtGen.h +++ clang/lib/AST/Interp/ByteCodeStmtGen.h @@ -65,7 +65,6 @@ bool visitContinueStmt(const ContinueStmt *S); /// Compiles a variable declaration. - bool visitVarDecl(const VarDecl *VD); private: /// Type of the expression returned by the function. Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -206,7 +206,7 @@ for (auto *D : DS->decls()) { // Variable declarator. if (auto *VD = dyn_cast(D)) { - if (!visitVarDecl(VD)) + if (!this->visitVarDecl(VD)) return false; continue; } @@ -386,37 +386,6 @@ return this->jump(*ContinueLabel); } -template -bool ByteCodeStmtGen::visitVarDecl(const VarDecl *VD) { - if (!VD->hasLocalStorage()) { - // No code generation required. - return true; - } - - // Integers, pointers, primitives. - if (Optional 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 Scope(this); - if (!this->visit(Init)) - return false; - - return this->emitSetLocal(*T, Offset, VD); - } - return true; - } - - // Composite types - allocate storage and initialize it. - if (Optional Offset = this->allocateLocal(VD)) - return this->visitLocalInitializer(VD->getInit(), *Offset); - - return this->bail(VD); -} - namespace clang { namespace interp { Index: clang/lib/AST/Interp/Program.h =================================================================== --- clang/lib/AST/Interp/Program.h +++ clang/lib/AST/Interp/Program.h @@ -78,7 +78,8 @@ llvm::Optional getGlobal(const ValueDecl *VD); /// Returns or creates a global an creates an index to it. - llvm::Optional getOrCreateGlobal(const ValueDecl *VD); + llvm::Optional getOrCreateGlobal(const ValueDecl *VD, + const Expr *Init = nullptr); /// Returns or creates a dummy value for parameters. llvm::Optional getOrCreateDummy(const ParmVarDecl *PD); Index: clang/lib/AST/Interp/Program.cpp =================================================================== --- clang/lib/AST/Interp/Program.cpp +++ clang/lib/AST/Interp/Program.cpp @@ -125,11 +125,12 @@ return Index; } -llvm::Optional Program::getOrCreateGlobal(const ValueDecl *VD) { +llvm::Optional Program::getOrCreateGlobal(const ValueDecl *VD, + const Expr *Init) { if (auto Idx = getGlobal(VD)) return Idx; - if (auto Idx = createGlobal(VD, nullptr)) { + if (auto Idx = createGlobal(VD, Init)) { GlobalIndices[VD] = *Idx; return Idx; } @@ -157,6 +158,7 @@ llvm::Optional Program::createGlobal(const ValueDecl *VD, const Expr *Init) { + assert(!getGlobal(VD)); bool IsStatic, IsExtern; if (auto *Var = dyn_cast(VD)) { IsStatic = !Var->hasLocalStorage();