Skip to content

Commit b4fc141

Browse files
committed
[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.
1 parent 684e4c0 commit b4fc141

File tree

2 files changed

+19
-13
lines changed

2 files changed

+19
-13
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -820,14 +820,24 @@ bool ByteCodeExprGen<Emitter>::VisitArrayInitLoopExpr(
820820
// Investigate compiling this to a loop.
821821

822822
const Expr *SubExpr = E->getSubExpr();
823+
const Expr *CommonExpr = E->getCommonExpr();
823824
size_t Size = E->getArraySize().getZExtValue();
824825
std::optional<PrimType> ElemT = classify(SubExpr->getType());
825826

827+
// If the common expression is an opaque expression, we visit it
828+
// here once so we have its value cached.
829+
// FIXME: This might be necessary (or useful) for all expressions.
830+
if (isa<OpaqueValueExpr>(CommonExpr)) {
831+
if (!this->discard(CommonExpr))
832+
return false;
833+
}
834+
826835
// So, every iteration, we execute an assignment here
827836
// where the LHS is on the stack (the target array)
828837
// and the RHS is our SubExpr.
829838
for (size_t I = 0; I != Size; ++I) {
830839
ArrayIndexScope<Emitter> IndexScope(this, I);
840+
BlockScope<Emitter> BS(this);
831841

832842
if (ElemT) {
833843
if (!this->visit(SubExpr))
@@ -856,7 +866,7 @@ bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
856866

857867
PrimType SubExprT = classify(E->getSourceExpr()).value_or(PT_Ptr);
858868
if (auto It = OpaqueExprs.find(E); It != OpaqueExprs.end())
859-
return this->emitGetLocal(SubExprT, It->getSecond(), E);
869+
return this->emitGetLocal(SubExprT, It->second, E);
860870

861871
if (!this->visit(E->getSourceExpr()))
862872
return false;
@@ -873,8 +883,10 @@ bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
873883

874884
// Here the local variable is created but the value is removed from the stack,
875885
// so we put it back, because the caller might need it.
876-
if (!this->emitGetLocal(SubExprT, *LocalIndex, E))
877-
return false;
886+
if (!DiscardResult) {
887+
if (!this->emitGetLocal(SubExprT, *LocalIndex, E))
888+
return false;
889+
}
878890

879891
// FIXME: Ideally the cached value should be cleaned up later.
880892
OpaqueExprs.insert({E, *LocalIndex});

clang/test/AST/Interp/cxx20.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -701,37 +701,31 @@ namespace ThreeWayCmp {
701701
static_assert(pa2 <=> pa1 == 1, "");
702702
}
703703

704-
// FIXME: Interp should also be able to evaluate this snippet properly.
705704
namespace ConstexprArrayInitLoopExprDestructors
706705
{
707706
struct Highlander {
708707
int *p = 0;
709708
constexpr Highlander() {}
710-
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}}
709+
constexpr void set(int *p) { this->p = p; ++*p; if (*p != 1) throw "there can be only one"; }
711710
constexpr ~Highlander() { --*p; }
712711
};
713712

714713
struct X {
715714
int *p;
716715
constexpr X(int *p) : p(p) {}
717716
constexpr X(const X &x, Highlander &&h = Highlander()) : p(x.p) {
718-
h.set(p); // expected-note {{in call to '&Highlander()->set(&n)'}}
717+
h.set(p);
719718
}
720719
};
721720

722721
constexpr int f() {
723722
int n = 0;
724723
X x[3] = {&n, &n, &n};
725-
auto [a, b, c] = x; // expected-note {{in call to 'X(x[0], Highlander())'}}
724+
auto [a, b, c] = x;
726725
return n;
727726
}
728727

729-
static_assert(f() == 0); // expected-error {{not an integral constant expression}} \
730-
// expected-note {{in call to 'f()'}}
731-
732-
int main() {
733-
return f();
734-
}
728+
static_assert(f() == 0);
735729
}
736730

737731
namespace NonPrimitiveOpaqueValue

0 commit comments

Comments
 (0)