tbaeder updated this revision to Diff 471971.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137070/new/

https://reviews.llvm.org/D137070

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/ByteCodeStmtGen.cpp
  clang/test/AST/Interp/cxx20.cpp

Index: clang/test/AST/Interp/cxx20.cpp
===================================================================
--- clang/test/AST/Interp/cxx20.cpp
+++ clang/test/AST/Interp/cxx20.cpp
@@ -166,3 +166,114 @@
                    // ref-error {{must be initialized by a constant expression}}
 
 };
+
+namespace Destructors {
+
+  class Inc final {
+  public:
+    int &I;
+    constexpr Inc(int &I) : I(I) {}
+    constexpr ~Inc() {
+      I++;
+    }
+  };
+
+  class Dec final {
+  public:
+    int &I;
+    constexpr Dec(int &I) : I(I) {}
+    constexpr ~Dec() {
+      I--;
+    }
+  };
+
+
+
+  constexpr int m() {
+    int i = 0;
+    {
+      Inc f1(i);
+      Inc f2(i);
+      Inc f3(i);
+    }
+    return i;
+  }
+  static_assert(m() == 3, "");
+
+
+  constexpr int C() {
+    int i = 0;
+
+    while (i < 10) {
+      Inc inc(i);
+      continue;
+      Dec dec(i);
+    }
+    return i;
+  }
+  static_assert(C() == 10, "");
+
+
+  constexpr int D() {
+    int i = 0;
+
+    {
+      Inc i1(i);
+      {
+        Inc i2(i);
+        return i;
+      }
+    }
+
+    return i;
+  }
+  static_assert(D() == 0, "");
+
+  constexpr int E() {
+    int i = 0;
+
+    for(;;) {
+      Inc i1(i);
+      break;
+    }
+    return i;
+  }
+  static_assert(E() == 1, "");
+
+
+  /// FIXME: This should be rejected, since we call the destructor
+  ///   twice. However, GCC doesn't care either.
+  constexpr int ManualDtor() {
+    int i = 0;
+    {
+      Inc I(i); // ref-note {{destroying object 'I' whose lifetime has already ended}}
+      I.~Inc();
+    }
+    return i;
+  }
+  static_assert(ManualDtor() == 1, ""); // expected-error {{static assertion failed}} \
+                                        // expected-note {{evaluates to '2 == 1'}} \
+                                        // ref-error {{not an integral constant expression}} \
+                                        // ref-note {{in call to 'ManualDtor()'}}
+
+  constexpr void doInc(int &i) {
+    Inc I(i);
+    return;
+  }
+  constexpr int testInc() {
+    int i = 0;
+    doInc(i);
+    return i;
+  }
+  static_assert(testInc() == 1, "");
+  constexpr void doInc2(int &i) {
+    Inc I(i);
+    // No return statement.
+  }
+   constexpr int testInc2() {
+    int i = 0;
+    doInc2(i);
+    return i;
+  }
+  static_assert(testInc2() == 1, "");
+};
Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -375,6 +375,7 @@
   if (!BreakLabel)
     return false;
 
+  this->emitCleanup();
   return this->jump(*BreakLabel);
 }
 
@@ -383,6 +384,7 @@
   if (!ContinueLabel)
     return false;
 
+  this->emitCleanup();
   return this->jump(*ContinueLabel);
 }
 
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -340,7 +340,7 @@
 public:
   LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {}
 
-  ~LocalScope() override { this->emitDestruction(); }
+  virtual ~LocalScope() override { this->emitDestruction(); }
 
   void addLocal(const Scope::Local &Local) override {
     if (!Idx) {
@@ -354,6 +354,29 @@
   void emitDestruction() override {
     if (!Idx)
       return;
+
+    // Emit destructor calls for local variables of record
+    // type with a destructor.
+    for (Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {
+      const Record *TypeRecord = Local.Desc->ElemRecord;
+      if (!TypeRecord)
+        continue;
+
+      const auto *RDecl = dyn_cast<CXXRecordDecl>(TypeRecord->getDecl());
+      if (!RDecl)
+        continue;
+
+      if (const auto *DtorDecl = RDecl->getDestructor()) {
+        const Function *Dtor = this->Ctx->getFunction(DtorDecl);
+        if (Dtor && Dtor->isConstexpr()) {
+          assert(Dtor->hasThisPointer());
+          assert(Dtor->getNumParams() == 1);
+          // Emit destructor call.
+          this->Ctx->emitGetPtrLocal(Local.Offset, DtorDecl);
+          this->Ctx->emitCall(Dtor, DtorDecl);
+        }
+      }
+    }
     this->Ctx->emitDestroy(*Idx, SourceInfo{});
   }
 
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -27,10 +27,12 @@
 namespace interp {
 
 /// Scope used to handle temporaries in toplevel variable declarations.
-template <class Emitter> class DeclScope final : public LocalScope<Emitter> {
+template <class Emitter> class DeclScope final : public VariableScope<Emitter> {
 public:
   DeclScope(ByteCodeExprGen<Emitter> *Ctx, const VarDecl *VD)
-      : LocalScope<Emitter>(Ctx), Scope(Ctx->P, VD) {}
+      : VariableScope<Emitter>(Ctx), Scope(Ctx->P, VD) {}
+
+  virtual ~DeclScope() override { this->emitDestruction(); }
 
   void addExtended(const Scope::Local &Local) override {
     return this->addLocal(Local);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to