Author: Timm Bäder Date: 2023-10-24T12:20:02+02:00 New Revision: b4fc1418d9765bfb605387efc70ecf233d27b383
URL: https://github.com/llvm/llvm-project/commit/b4fc1418d9765bfb605387efc70ecf233d27b383 DIFF: https://github.com/llvm/llvm-project/commit/b4fc1418d9765bfb605387efc70ecf233d27b383.diff LOG: [clang][Interp] Fix ArrayInitLoop common expr life time The local variable needs to survive for all the interations of the ArrayInitLoopExpr. So, visit it explicitly before we iterate. Added: Modified: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/test/AST/Interp/cxx20.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index eb96f021258b114..1b33c69b93aa4b9 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -820,14 +820,24 @@ bool ByteCodeExprGen<Emitter>::VisitArrayInitLoopExpr( // Investigate compiling this to a loop. const Expr *SubExpr = E->getSubExpr(); + const Expr *CommonExpr = E->getCommonExpr(); size_t Size = E->getArraySize().getZExtValue(); std::optional<PrimType> ElemT = classify(SubExpr->getType()); + // If the common expression is an opaque expression, we visit it + // here once so we have its value cached. + // FIXME: This might be necessary (or useful) for all expressions. + if (isa<OpaqueValueExpr>(CommonExpr)) { + if (!this->discard(CommonExpr)) + 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); + BlockScope<Emitter> BS(this); if (ElemT) { if (!this->visit(SubExpr)) @@ -856,7 +866,7 @@ bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) { PrimType SubExprT = classify(E->getSourceExpr()).value_or(PT_Ptr); if (auto It = OpaqueExprs.find(E); It != OpaqueExprs.end()) - return this->emitGetLocal(SubExprT, It->getSecond(), E); + return this->emitGetLocal(SubExprT, It->second, E); if (!this->visit(E->getSourceExpr())) return false; @@ -873,8 +883,10 @@ bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) { // Here the local variable is created but the value is removed from the stack, // so we put it back, because the caller might need it. - if (!this->emitGetLocal(SubExprT, *LocalIndex, E)) - return false; + if (!DiscardResult) { + if (!this->emitGetLocal(SubExprT, *LocalIndex, E)) + return false; + } // FIXME: Ideally the cached value should be cleaned up later. OpaqueExprs.insert({E, *LocalIndex}); diff --git a/clang/test/AST/Interp/cxx20.cpp b/clang/test/AST/Interp/cxx20.cpp index 553bc6eb4d5244f..f0bb4e9e0d0711b 100644 --- a/clang/test/AST/Interp/cxx20.cpp +++ b/clang/test/AST/Interp/cxx20.cpp @@ -701,13 +701,12 @@ namespace ThreeWayCmp { static_assert(pa2 <=> pa1 == 1, ""); } -// FIXME: Interp should also be able to evaluate this snippet properly. namespace ConstexprArrayInitLoopExprDestructors { struct Highlander { int *p = 0; constexpr Highlander() {} - constexpr void set(int *p) { this->p = p; ++*p; if (*p != 1) throw "there can be only one"; } // expected-note {{not valid in a constant expression}} + constexpr void set(int *p) { this->p = p; ++*p; if (*p != 1) throw "there can be only one"; } constexpr ~Highlander() { --*p; } }; @@ -715,23 +714,18 @@ namespace ConstexprArrayInitLoopExprDestructors int *p; constexpr X(int *p) : p(p) {} constexpr X(const X &x, Highlander &&h = Highlander()) : p(x.p) { - h.set(p); // expected-note {{in call to '&Highlander()->set(&n)'}} + h.set(p); } }; constexpr int f() { int n = 0; X x[3] = {&n, &n, &n}; - auto [a, b, c] = x; // expected-note {{in call to 'X(x[0], Highlander())'}} + auto [a, b, c] = x; return n; } - static_assert(f() == 0); // expected-error {{not an integral constant expression}} \ - // expected-note {{in call to 'f()'}} - - int main() { - return f(); - } + static_assert(f() == 0); } namespace NonPrimitiveOpaqueValue _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits