Index: clang/lib/AST/Interp/InterpFrame.h =================================================================== --- clang/lib/AST/Interp/InterpFrame.h +++ clang/lib/AST/Interp/InterpFrame.h @@ -47,6 +47,11 @@ /// Invokes the destructors for a scope. void destroy(unsigned Idx); + /// Invokes the destructors for all scopes. This is used in the + /// InterpFrame destructor to avoid memory leaks in case the + /// interpretation was not successful. + void destroyAll(); + /// Pops the arguments off the stack. void popArgs(); Index: clang/lib/AST/Interp/InterpFrame.cpp =================================================================== --- clang/lib/AST/Interp/InterpFrame.cpp +++ clang/lib/AST/Interp/InterpFrame.cpp @@ -64,6 +64,7 @@ } InterpFrame::~InterpFrame() { + destroyAll(); for (auto &Param : Params) S.deallocate(reinterpret_cast(Param.second.get())); } @@ -74,6 +75,16 @@ } } +void InterpFrame::destroyAll() { + if (!Func) + return; + for (const Scope &Sc : Func->scopes()) { + for (auto &Local : Sc.locals()) { + S.deallocate(reinterpret_cast(localBlock(Local.Offset))); + } + } +} + void InterpFrame::popArgs() { for (PrimType Ty : Func->args_reverse()) TYPE_SWITCH(Ty, S.Stk.discard()); Index: clang/test/AST/Interp/cxx20.cpp =================================================================== --- clang/test/AST/Interp/cxx20.cpp +++ clang/test/AST/Interp/cxx20.cpp @@ -304,3 +304,15 @@ } static_assert(testInc2() == 1, ""); }; + +constexpr int NoLeakHere() { + int abc[2]; + + abc[0] = 1; + return abc[1]; // expected-note {{read of object outside its lifetime}} \ + // ref-note {{read of uninitialized object}} +} +static_assert(NoLeakHere() == 3); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to}}