Author: Timm Baeder
Date: 2025-05-16T12:48:22+02:00
New Revision: e5f8998ac86f3cbbc763f0a1a9e23824e70b4af7

URL: 
https://github.com/llvm/llvm-project/commit/e5f8998ac86f3cbbc763f0a1a9e23824e70b4af7
DIFF: 
https://github.com/llvm/llvm-project/commit/e5f8998ac86f3cbbc763f0a1a9e23824e70b4af7.diff

LOG: [clang][bytecode] Explicitly start variable lifetimes via placement new 
(#140221)

placement new /std::construct{,_at} can resurrect a variable after it's
destructor has been called.

Added: 
    clang/test/AST/ByteCode/lifetimes26.cpp

Modified: 
    clang/lib/AST/ByteCode/Compiler.cpp
    clang/lib/AST/ByteCode/Interp.h
    clang/lib/AST/ByteCode/Opcodes.td
    clang/lib/AST/ByteCode/Pointer.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Compiler.cpp 
b/clang/lib/AST/ByteCode/Compiler.cpp
index 2580fb17ce5e3..5017c9b76e6d1 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -3478,6 +3478,8 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr 
*E) {
     if (PlacementDest) {
       if (!this->visit(PlacementDest))
         return false;
+      if (!this->emitStartLifetime(E))
+        return false;
       if (!this->emitGetLocal(SizeT, ArrayLen, E))
         return false;
       if (!this->emitCheckNewTypeMismatchArray(SizeT, E, E))
@@ -3617,6 +3619,8 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr 
*E) {
     if (PlacementDest) {
       if (!this->visit(PlacementDest))
         return false;
+      if (!this->emitStartLifetime(E))
+        return false;
       if (!this->emitCheckNewTypeMismatch(E, E))
         return false;
     } else {

diff  --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 35d97167135f7..9f1a6302eb856 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1326,6 +1326,14 @@ static inline bool Kill(InterpState &S, CodePtr OpPC) {
   return true;
 }
 
+static inline bool StartLifetime(InterpState &S, CodePtr OpPC) {
+  const auto &Ptr = S.Stk.peek<Pointer>();
+  if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
+    return false;
+  Ptr.startLifetime();
+  return true;
+}
+
 /// 1) Pops the value from the stack.
 /// 2) Writes the value to the local variable with the
 ///    given offset.
@@ -1855,10 +1863,8 @@ template <PrimType Name, class T = typename 
PrimConv<Name>::T>
 bool Init(InterpState &S, CodePtr OpPC) {
   const T &Value = S.Stk.pop<T>();
   const Pointer &Ptr = S.Stk.peek<Pointer>();
-  if (!CheckInit(S, OpPC, Ptr)) {
-    assert(false);
+  if (!CheckInit(S, OpPC, Ptr))
     return false;
-  }
   Ptr.activate();
   Ptr.initialize();
   new (&Ptr.deref<T>()) T(Value);

diff  --git a/clang/lib/AST/ByteCode/Opcodes.td 
b/clang/lib/AST/ByteCode/Opcodes.td
index 65a9a0cdad022..9dddcced8ca38 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -395,10 +395,8 @@ def GetLocal : AccessOpcode { let HasCustomEval = 1; }
 // [] -> [Pointer]
 def SetLocal : AccessOpcode { let HasCustomEval = 1; }
 
-def Kill : Opcode {
-  let Types = [];
-  let Args = [];
-}
+def Kill : Opcode;
+def StartLifetime : Opcode;
 
 def CheckDecl : Opcode {
   let Args = [ArgVarDecl];

diff  --git a/clang/lib/AST/ByteCode/Pointer.h 
b/clang/lib/AST/ByteCode/Pointer.h
index 19770aa3b97bc..479da09004685 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -722,6 +722,14 @@ class Pointer {
     getInlineDesc()->LifeState = Lifetime::Ended;
   }
 
+  void startLifetime() const {
+    if (!isBlockPointer())
+      return;
+    if (asBlockPointer().Base < sizeof(InlineDescriptor))
+      return;
+    getInlineDesc()->LifeState = Lifetime::Started;
+  }
+
   /// Compare two pointers.
   ComparisonCategoryResult compare(const Pointer &Other) const {
     if (!hasSameBase(*this, Other))

diff  --git a/clang/test/AST/ByteCode/lifetimes26.cpp 
b/clang/test/AST/ByteCode/lifetimes26.cpp
new file mode 100644
index 0000000000000..a5203ae77bc13
--- /dev/null
+++ b/clang/test/AST/ByteCode/lifetimes26.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -verify=expected,both -std=c++26 %s 
-fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -verify=ref,both      -std=c++26 %s
+
+// both-no-diagnostics
+
+namespace std {
+  struct type_info;
+  struct destroying_delete_t {
+    explicit destroying_delete_t() = default;
+  } inline constexpr destroying_delete{};
+  struct nothrow_t {
+    explicit nothrow_t() = default;
+  } inline constexpr nothrow{};
+  using size_t = decltype(sizeof(0));
+  enum class align_val_t : size_t {};
+};
+
+constexpr void *operator new(std::size_t, void *p) { return p; }
+namespace std {
+  template<typename T> constexpr T *construct(T *p) { return new (p) T; }
+  template<typename T> constexpr void destroy(T *p) { p->~T(); }
+}
+
+constexpr bool foo() {
+  using T = bool;
+  bool b = true;
+  b.~T();
+  new (&b) bool(false);
+  return b;
+}
+static_assert(!foo());
+
+struct S {};
+constexpr bool foo2() {
+  S s;
+  s.~S();
+  new (&s) S{};
+  return true;
+}
+static_assert(foo2());
+
+constexpr void destroy_pointer() {
+  using T = int*;
+  T p;
+  p.~T();
+  std::construct(&p);
+}
+static_assert((destroy_pointer(), true));
+


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to