[clang] 48d703e - Revert "[clang][Interp] Implement dynamic memory allocation handling (#70306)"

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Sun Jul 14 12:18:24 PDT 2024


Author: Timm Bäder
Date: 2024-07-14T21:17:47+02:00
New Revision: 48d703e7f56282ce5d690e45a129a4a7fd040ee6

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

LOG: Revert "[clang][Interp] Implement dynamic memory allocation handling (#70306)"

This reverts commit fa133d3151b5e428b1c5819d29b0ad28a90882a2.

It looks like this has some more serious problems:
https://lab.llvm.org/buildbot/#/builders/39/builds/528

As well as build failures on MacOS.

Added: 
    

Modified: 
    clang/lib/AST/CMakeLists.txt
    clang/lib/AST/Interp/Compiler.cpp
    clang/lib/AST/Interp/Compiler.h
    clang/lib/AST/Interp/EvalEmitter.cpp
    clang/lib/AST/Interp/EvaluationResult.cpp
    clang/lib/AST/Interp/EvaluationResult.h
    clang/lib/AST/Interp/Interp.cpp
    clang/lib/AST/Interp/Interp.h
    clang/lib/AST/Interp/InterpBlock.h
    clang/lib/AST/Interp/InterpState.cpp
    clang/lib/AST/Interp/InterpState.h
    clang/lib/AST/Interp/Opcodes.td
    clang/lib/AST/Interp/Pointer.h
    clang/test/Rewriter/rewrite-modern-catch.m
    clang/test/SemaCXX/delete.cpp
    clang/test/SemaCXX/new-delete.cpp

Removed: 
    clang/lib/AST/Interp/DynamicAllocator.cpp
    clang/lib/AST/Interp/DynamicAllocator.h
    clang/test/AST/Interp/new-delete.cpp


################################################################################
diff  --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt
index 70aecb781c2ff..ceaad8d3c5a86 100644
--- a/clang/lib/AST/CMakeLists.txt
+++ b/clang/lib/AST/CMakeLists.txt
@@ -75,7 +75,6 @@ add_clang_library(clangAST
   Interp/InterpBuiltin.cpp
   Interp/Floating.cpp
   Interp/EvaluationResult.cpp
-  Interp/DynamicAllocator.cpp
   Interp/Interp.cpp
   Interp/InterpBlock.cpp
   Interp/InterpFrame.cpp

diff  --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp
index 1f43f46c399f1..30dc7f5e4840b 100644
--- a/clang/lib/AST/Interp/Compiler.cpp
+++ b/clang/lib/AST/Interp/Compiler.cpp
@@ -2771,109 +2771,6 @@ bool Compiler<Emitter>::VisitCXXInheritedCtorInitExpr(
   return this->emitCall(F, 0, E);
 }
 
-template <class Emitter>
-bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
-  assert(classifyPrim(E->getType()) == PT_Ptr);
-  const Expr *Init = E->getInitializer();
-  QualType ElementType = E->getAllocatedType();
-  std::optional<PrimType> ElemT = classify(ElementType);
-  unsigned PlacementArgs = E->getNumPlacementArgs();
-  bool IsNoThrow = false;
-
-  // FIXME: Better diagnostic. diag::note_constexpr_new_placement
-  if (PlacementArgs != 0) {
-    // The only new-placement list we support is of the form (std::nothrow).
-    //
-    // FIXME: There is no restriction on this, but it's not clear that any
-    // other form makes any sense. We get here for cases such as:
-    //
-    //   new (std::align_val_t{N}) X(int)
-    //
-    // (which should presumably be valid only if N is a multiple of
-    // alignof(int), and in any case can't be deallocated unless N is
-    // alignof(X) and X has new-extended alignment).
-    if (PlacementArgs != 1 || !E->getPlacementArg(0)->getType()->isNothrowT())
-      return this->emitInvalid(E);
-
-    if (!this->discard(E->getPlacementArg(0)))
-      return false;
-    IsNoThrow = true;
-  }
-
-  const Descriptor *Desc;
-  if (ElemT) {
-    if (E->isArray())
-      Desc = nullptr; // We're not going to use it in this case.
-    else
-      Desc = P.createDescriptor(E, *ElemT, Descriptor::InlineDescMD,
-                                /*IsConst=*/false, /*IsTemporary=*/false,
-                                /*IsMutable=*/false);
-  } else {
-    Desc = P.createDescriptor(
-        E, ElementType.getTypePtr(),
-        E->isArray() ? std::nullopt : Descriptor::InlineDescMD,
-        /*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false, Init);
-  }
-
-  if (E->isArray()) {
-    std::optional<const Expr *> ArraySizeExpr = E->getArraySize();
-    if (!ArraySizeExpr)
-      return false;
-    PrimType SizeT = classifyPrim((*ArraySizeExpr)->getType());
-
-    if (!this->visit(*ArraySizeExpr))
-      return false;
-
-    if (ElemT) {
-      // N primitive elements.
-      if (!this->emitAllocN(SizeT, *ElemT, E, IsNoThrow, E))
-        return false;
-    } else {
-      // N Composite elements.
-      if (!this->emitAllocCN(SizeT, Desc, IsNoThrow, E))
-        return false;
-    }
-
-    if (Init && !this->visitInitializer(Init))
-      return false;
-
-  } else {
-    // Allocate just one element.
-    if (!this->emitAlloc(Desc, E))
-      return false;
-
-    if (Init) {
-      if (ElemT) {
-        if (!this->visit(Init))
-          return false;
-
-        if (!this->emitInit(*ElemT, E))
-          return false;
-      } else {
-        // Composite.
-        if (!this->visitInitializer(Init))
-          return false;
-      }
-    }
-  }
-
-  if (DiscardResult)
-    return this->emitPopPtr(E);
-
-  return true;
-}
-
-template <class Emitter>
-bool Compiler<Emitter>::VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
-  const Expr *Arg = E->getArgument();
-
-  // Arg must be an lvalue.
-  if (!this->visit(Arg))
-    return false;
-
-  return this->emitFree(E->isArrayForm(), E);
-}
-
 template <class Emitter>
 bool Compiler<Emitter>::VisitExpressionTraitExpr(const ExpressionTraitExpr *E) {
   assert(Ctx.getLangOpts().CPlusPlus);

diff  --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h
index 6df723df2b444..23e7afd767e88 100644
--- a/clang/lib/AST/Interp/Compiler.h
+++ b/clang/lib/AST/Interp/Compiler.h
@@ -190,8 +190,6 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
   bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E);
   bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
   bool VisitStmtExpr(const StmtExpr *E);
-  bool VisitCXXNewExpr(const CXXNewExpr *E);
-  bool VisitCXXDeleteExpr(const CXXDeleteExpr *E);
 
   // Statements.
   bool visitCompoundStmt(const CompoundStmt *S);

diff  --git a/clang/lib/AST/Interp/DynamicAllocator.cpp b/clang/lib/AST/Interp/DynamicAllocator.cpp
deleted file mode 100644
index f6ea264766b13..0000000000000
--- a/clang/lib/AST/Interp/DynamicAllocator.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-//==-------- DynamicAllocator.cpp - Dynamic allocations ----------*- C++ -*-==//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "DynamicAllocator.h"
-#include "InterpBlock.h"
-#include "InterpState.h"
-
-using namespace clang;
-using namespace clang::interp;
-
-DynamicAllocator::~DynamicAllocator() { cleanup(); }
-
-void DynamicAllocator::cleanup() {
-  // Invoke destructors of all the blocks and as a last restort,
-  // reset all the pointers pointing to them to null pointees.
-  // This should never show up in diagnostics, but it's necessary
-  // for us to not cause use-after-free problems.
-  for (auto &Iter : AllocationSites) {
-    auto &AllocSite = Iter.second;
-    for (auto &Alloc : AllocSite.Allocations) {
-      Block *B = reinterpret_cast<Block *>(Alloc.Memory.get());
-      B->invokeDtor();
-      if (B->hasPointers()) {
-        while (B->Pointers) {
-          Pointer *Next = B->Pointers->Next;
-          B->Pointers->PointeeStorage.BS.Pointee = nullptr;
-          B->Pointers = Next;
-        }
-        B->Pointers = nullptr;
-      }
-    }
-  }
-
-  AllocationSites.clear();
-}
-
-Block *DynamicAllocator::allocate(const Expr *Source, PrimType T,
-                                  size_t NumElements, unsigned EvalID) {
-  // Create a new descriptor for an array of the specified size and
-  // element type.
-  const Descriptor *D = allocateDescriptor(
-      Source, T, Descriptor::InlineDescMD, NumElements, /*IsConst=*/false,
-      /*IsTemporary=*/false, /*IsMutable=*/false);
-
-  return allocate(D, EvalID);
-}
-
-Block *DynamicAllocator::allocate(const Descriptor *ElementDesc,
-                                  size_t NumElements, unsigned EvalID) {
-  // Create a new descriptor for an array of the specified size and
-  // element type.
-  const Descriptor *D = allocateDescriptor(
-      ElementDesc->asExpr(), ElementDesc, Descriptor::InlineDescMD, NumElements,
-      /*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false);
-  return allocate(D, EvalID);
-}
-
-Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID) {
-  assert(D->asExpr());
-
-  auto Memory =
-      std::make_unique<std::byte[]>(sizeof(Block) + D->getAllocSize());
-  auto *B = new (Memory.get()) Block(EvalID, D, /*isStatic=*/false);
-  B->invokeCtor();
-
-  InlineDescriptor *ID = reinterpret_cast<InlineDescriptor *>(B->rawData());
-  ID->Desc = D;
-  ID->IsActive = true;
-  ID->Offset = sizeof(InlineDescriptor);
-  ID->IsBase = false;
-  ID->IsFieldMutable = false;
-  ID->IsConst = false;
-  ID->IsInitialized = false;
-  assert(ID->Desc);
-
-  B->IsDynamic = true;
-
-  if (auto It = AllocationSites.find(D->asExpr()); It != AllocationSites.end())
-    It->second.Allocations.emplace_back(std::move(Memory));
-  else
-    AllocationSites.insert(
-        {D->asExpr(), AllocationSite(std::move(Memory), D->isArray())});
-  return B;
-}
-
-bool DynamicAllocator::deallocate(const Expr *Source,
-                                  const Block *BlockToDelete, InterpState &S) {
-  auto It = AllocationSites.find(Source);
-  if (It == AllocationSites.end())
-    return false;
-
-  auto &Site = It->second;
-  assert(Site.size() > 0);
-
-  // Find the Block to delete.
-  auto AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {
-    const Block *B = reinterpret_cast<const Block *>(A.Memory.get());
-    return BlockToDelete == B;
-  });
-
-  assert(AllocIt != Site.Allocations.end());
-
-  Block *B = reinterpret_cast<Block *>(AllocIt->Memory.get());
-  B->invokeDtor();
-
-  S.deallocate(B);
-  Site.Allocations.erase(AllocIt);
-
-  if (Site.size() == 0)
-    AllocationSites.erase(It);
-
-  return true;
-}

diff  --git a/clang/lib/AST/Interp/DynamicAllocator.h b/clang/lib/AST/Interp/DynamicAllocator.h
deleted file mode 100644
index 3a6be28866223..0000000000000
--- a/clang/lib/AST/Interp/DynamicAllocator.h
+++ /dev/null
@@ -1,96 +0,0 @@
-//==--------- DynamicAllocator.h - Dynamic allocations ------------*- C++ -*-=//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_AST_INTERP_DYNAMIC_ALLOCATOR_H
-#define LLVM_CLANG_AST_INTERP_DYNAMIC_ALLOCATOR_H
-
-#include "Descriptor.h"
-#include "InterpBlock.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/iterator_range.h"
-#include "llvm/Support/Allocator.h"
-
-namespace clang {
-class Expr;
-namespace interp {
-class Block;
-class InterpState;
-
-/// Manages dynamic memory allocations done during bytecode interpretation.
-///
-/// We manage allocations as a map from their new-expression to a list
-/// of allocations. This is called an AllocationSite. For each site, we
-/// record whether it was allocated using new or new[], the
-/// IsArrayAllocation flag.
-///
-/// For all array allocations, we need to allocat new Descriptor instances,
-/// so the DynamicAllocator has a llvm::BumpPtrAllocator similar to Program.
-class DynamicAllocator final {
-  struct Allocation {
-    std::unique_ptr<std::byte[]> Memory;
-    Allocation(std::unique_ptr<std::byte[]> Memory)
-        : Memory(std::move(Memory)) {}
-  };
-
-  struct AllocationSite {
-    llvm::SmallVector<Allocation> Allocations;
-    bool IsArrayAllocation = false;
-
-    AllocationSite(std::unique_ptr<std::byte[]> Memory, bool Array)
-        : IsArrayAllocation(Array) {
-      Allocations.push_back({std::move(Memory)});
-    }
-
-    size_t size() const { return Allocations.size(); }
-  };
-
-public:
-  DynamicAllocator() = default;
-  ~DynamicAllocator();
-
-  void cleanup();
-
-  unsigned getNumAllocations() const { return AllocationSites.size(); }
-
-  /// Allocate ONE element of the given descriptor.
-  Block *allocate(const Descriptor *D, unsigned EvalID);
-  /// Allocate \p NumElements primitive elements of the given type.
-  Block *allocate(const Expr *Source, PrimType T, size_t NumElements,
-                  unsigned EvalID);
-  /// Allocate \p NumElements elements of the given descriptor.
-  Block *allocate(const Descriptor *D, size_t NumElements, unsigned EvalID);
-
-  /// Deallocate the given source+block combination.
-  /// Returns \c true if anything has been deallocatd, \c false otherwise.
-  bool deallocate(const Expr *Source, const Block *BlockToDelete,
-                  InterpState &S);
-
-  /// Checks whether the allocation done at the given source is an array
-  /// allocation.
-  bool isArrayAllocation(const Expr *Source) const {
-    if (auto It = AllocationSites.find(Source); It != AllocationSites.end())
-      return It->second.IsArrayAllocation;
-    return false;
-  }
-
-  // FIXME: Public because I'm not sure how to expose an iterator to it.
-  llvm::DenseMap<const Expr *, AllocationSite> AllocationSites;
-
-private:
-  using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>;
-  PoolAllocTy DescAllocator;
-
-  /// Allocates a new descriptor.
-  template <typename... Ts> Descriptor *allocateDescriptor(Ts &&...Args) {
-    return new (DescAllocator) Descriptor(std::forward<Ts>(Args)...);
-  }
-};
-
-} // namespace interp
-} // namespace clang
-#endif

diff  --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp
index 968f21ea974c2..9701796fb9303 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -133,17 +133,9 @@ bool EvalEmitter::fallthrough(const LabelTy &Label) {
   return true;
 }
 
-static bool checkReturnState(InterpState &S) {
-  return S.maybeDiagnoseDanglingAllocations();
-}
-
 template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
   if (!isActive())
     return true;
-
-  if (!checkReturnState(S))
-    return false;
-
   using T = typename PrimConv<OpType>::T;
   EvalResult.setValue(S.Stk.pop<T>().toAPValue());
   return true;
@@ -155,14 +147,9 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
 
   const Pointer &Ptr = S.Stk.pop<Pointer>();
 
-  if (!EvalResult.checkReturnValue(S, Ctx, Ptr, Info))
-    return false;
   if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
     return false;
 
-  if (!checkReturnState(S))
-    return false;
-
   // Implicitly convert lvalue to rvalue, if requested.
   if (ConvertResultToRValue) {
     // Never allow reading from a non-const pointer, unless the memory
@@ -185,17 +172,12 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
 template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) {
   if (!isActive())
     return true;
-
-  if (!checkReturnState(S))
-    return false;
   // Function pointers cannot be converted to rvalues.
   EvalResult.setFunctionPointer(S.Stk.pop<FunctionPointer>());
   return true;
 }
 
 bool EvalEmitter::emitRetVoid(const SourceInfo &Info) {
-  if (!checkReturnState(S))
-    return false;
   EvalResult.setValid();
   return true;
 }
@@ -203,14 +185,9 @@ bool EvalEmitter::emitRetVoid(const SourceInfo &Info) {
 bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
   const auto &Ptr = S.Stk.pop<Pointer>();
 
-  if (!EvalResult.checkReturnValue(S, Ctx, Ptr, Info))
-    return false;
   if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
     return false;
 
-  if (!checkReturnState(S))
-    return false;
-
   if (std::optional<APValue> APV =
           Ptr.toRValue(S.getCtx(), EvalResult.getSourceType())) {
     EvalResult.setValue(*APV);

diff  --git a/clang/lib/AST/Interp/EvaluationResult.cpp b/clang/lib/AST/Interp/EvaluationResult.cpp
index 0bebfd4ad984e..d0d68f75dd803 100644
--- a/clang/lib/AST/Interp/EvaluationResult.cpp
+++ b/clang/lib/AST/Interp/EvaluationResult.cpp
@@ -10,7 +10,6 @@
 #include "InterpState.h"
 #include "Record.h"
 #include "clang/AST/ExprCXX.h"
-#include "llvm/ADT/SetVector.h"
 
 namespace clang {
 namespace interp {
@@ -153,11 +152,6 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S,
   if (Ptr.isZero())
     return true;
 
-  // We can't inspect dead pointers at all. Return true here so we can
-  // diagnose them later.
-  if (!Ptr.isLive())
-    return true;
-
   SourceLocation InitLoc;
   if (const auto *D = Source.dyn_cast<const Decl *>())
     InitLoc = cast<VarDecl>(D)->getAnyInitializer()->getExprLoc();
@@ -174,71 +168,5 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S,
   return true;
 }
 
-static void collectBlocks(const Pointer &Ptr,
-                          llvm::SetVector<const Block *> &Blocks) {
-  auto isUsefulPtr = [](const Pointer &P) -> bool {
-    return P.isLive() && !P.isZero() && !P.isDummy() &&
-           !P.isUnknownSizeArray() && !P.isOnePastEnd() && P.isBlockPointer();
-  };
-
-  if (!isUsefulPtr(Ptr))
-    return;
-
-  Blocks.insert(Ptr.block());
-
-  const Descriptor *Desc = Ptr.getFieldDesc();
-  if (!Desc)
-    return;
-
-  if (const Record *R = Desc->ElemRecord) {
-    for (const Record::Field &F : R->fields()) {
-      const Pointer &FieldPtr = Ptr.atField(F.Offset);
-      assert(FieldPtr.block() == Ptr.block());
-      collectBlocks(FieldPtr, Blocks);
-    }
-  } else if (Desc->isPrimitive() && Desc->getPrimType() == PT_Ptr) {
-    const Pointer &Pointee = Ptr.deref<Pointer>();
-    if (isUsefulPtr(Pointee) && !Blocks.contains(Pointee.block()))
-      collectBlocks(Pointee, Blocks);
-
-  } else if (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) {
-    for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
-      const Pointer &ElemPointee = Ptr.atIndex(I).deref<Pointer>();
-      if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.block()))
-        collectBlocks(ElemPointee, Blocks);
-    }
-  } else if (Desc->isCompositeArray()) {
-    for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
-      const Pointer &ElemPtr = Ptr.atIndex(I).narrow();
-      collectBlocks(ElemPtr, Blocks);
-    }
-  }
-}
-
-bool EvaluationResult::checkReturnValue(InterpState &S, const Context &Ctx,
-                                        const Pointer &Ptr,
-                                        const SourceInfo &Info) {
-  // Collect all blocks that this pointer (transitively) points to and
-  // return false if any of them is a dynamic block.
-  llvm::SetVector<const Block *> Blocks;
-
-  collectBlocks(Ptr, Blocks);
-
-  for (const Block *B : Blocks) {
-    if (B->isDynamic()) {
-      assert(B->getDescriptor());
-      assert(B->getDescriptor()->asExpr());
-
-      S.FFDiag(Info, diag::note_constexpr_dynamic_alloc)
-          << Ptr.getType()->isReferenceType() << !Ptr.isRoot();
-      S.Note(B->getDescriptor()->asExpr()->getExprLoc(),
-             diag::note_constexpr_dynamic_alloc_here);
-      return false;
-    }
-  }
-
-  return true;
-}
-
 } // namespace interp
 } // namespace clang

diff  --git a/clang/lib/AST/Interp/EvaluationResult.h b/clang/lib/AST/Interp/EvaluationResult.h
index ef662e3779bc3..378f1ccdb0af4 100644
--- a/clang/lib/AST/Interp/EvaluationResult.h
+++ b/clang/lib/AST/Interp/EvaluationResult.h
@@ -98,12 +98,7 @@ class EvaluationResult final {
   /// LValue and we can't read from it.
   std::optional<APValue> toRValue() const;
 
-  /// Check that all subobjects of the given pointer have been initialized.
   bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const;
-  /// Check that none of the blocks the given pointer (transitively) points
-  /// to are dynamically allocated.
-  bool checkReturnValue(InterpState &S, const Context &Ctx, const Pointer &Ptr,
-                        const SourceInfo &Info);
 
   QualType getSourceType() const {
     if (const auto *D =
@@ -118,7 +113,6 @@ class EvaluationResult final {
   void dump() const;
 
   friend class EvalEmitter;
-  friend class InterpState;
 };
 
 } // namespace interp

diff  --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index cafe2175f5cc4..70a470021e7f2 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -693,58 +693,6 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
   return true;
 }
 
-bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC) {
-  if (S.getLangOpts().CPlusPlus20)
-    return true;
-
-  const SourceInfo &E = S.Current->getSource(OpPC);
-  S.FFDiag(E, diag::note_constexpr_new);
-  return false;
-}
-
-bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray,
-                         bool DeleteIsArray, const Descriptor *D,
-                         const Expr *NewExpr) {
-  if (NewWasArray == DeleteIsArray)
-    return true;
-
-  QualType TypeToDiagnose;
-  // We need to shuffle things around a bit here to get a better diagnostic,
-  // because the expression we allocated the block for was of type int*,
-  // but we want to get the array size right.
-  if (D->isArray()) {
-    QualType ElemQT = D->getType()->getPointeeType();
-    TypeToDiagnose = S.getCtx().getConstantArrayType(
-        ElemQT, APInt(64, D->getNumElems(), false), nullptr,
-        ArraySizeModifier::Normal, 0);
-  } else
-    TypeToDiagnose = D->getType()->getPointeeType();
-
-  const SourceInfo &E = S.Current->getSource(OpPC);
-  S.FFDiag(E, diag::note_constexpr_new_delete_mismatch)
-      << DeleteIsArray << 0 << TypeToDiagnose;
-  S.Note(NewExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here)
-      << NewExpr->getSourceRange();
-  return false;
-}
-
-bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
-                       const Pointer &Ptr) {
-  if (Source && isa<CXXNewExpr>(Source))
-    return true;
-
-  // Whatever this is, we didn't heap allocate it.
-  const SourceInfo &Loc = S.Current->getSource(OpPC);
-  S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
-      << Ptr.toDiagnosticString(S.getCtx());
-
-  if (Ptr.isTemporary())
-    S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
-  else
-    S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
-  return false;
-}
-
 /// We aleady know the given DeclRefExpr is invalid for some reason,
 /// now figure out why and print appropriate diagnostics.
 bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {

diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 955b002c3b3f4..c7d8604c7dc2a 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -15,7 +15,6 @@
 
 #include "../ExprConstShared.h"
 #include "Boolean.h"
-#include "DynamicAllocator.h"
 #include "Floating.h"
 #include "Function.h"
 #include "FunctionPointer.h"
@@ -123,20 +122,6 @@ bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
 bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
                       const CallExpr *CE, unsigned ArgSize);
 
-/// Checks if dynamic memory allocation is available in the current
-/// language mode.
-bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);
-
-/// Diagnose mismatched new[]/delete or new/delete[] pairs.
-bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray,
-                         bool DeleteIsArray, const Descriptor *D,
-                         const Expr *NewExpr);
-
-/// Check the source of the pointer passed to delete/delete[] has actually
-/// been heap allocated by us.
-bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
-                       const Pointer &Ptr);
-
 /// Sets the given integral value to the pointer, which is of
 /// a std::{weak,partial,strong}_ordering type.
 bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
@@ -204,30 +189,6 @@ bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
   return true;
 }
 
-template <typename SizeT>
-bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
-                    bool IsNoThrow) {
-  // FIXME: Both the SizeT::from() as well as the
-  // NumElements.toAPSInt() in this function are rather expensive.
-
-  // FIXME: GH63562
-  // APValue stores array extents as unsigned,
-  // so anything that is greater that unsigned would overflow when
-  // constructing the array, we catch this here.
-  SizeT MaxElements = SizeT::from(std::numeric_limits<unsigned>::max());
-  if (NumElements->toAPSInt().getActiveBits() >
-          ConstantArrayType::getMaxSizeBits(S.getCtx()) ||
-      *NumElements > MaxElements) {
-    if (!IsNoThrow) {
-      const SourceInfo &Loc = S.Current->getSource(OpPC);
-      S.FFDiag(Loc, diag::note_constexpr_new_too_large)
-          << NumElements->toDiagnosticString(S.getCtx());
-    }
-    return false;
-  }
-  return true;
-}
-
 /// Checks if the result of a floating-point operation is valid
 /// in the current context.
 bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
@@ -2806,118 +2767,6 @@ inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
   return true;
 }
 
-inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
-  assert(Desc);
-
-  if (!CheckDynamicMemoryAllocation(S, OpPC))
-    return false;
-
-  DynamicAllocator &Allocator = S.getAllocator();
-  Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID());
-  assert(B);
-
-  S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
-
-  return true;
-}
-
-template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
-inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
-                   bool IsNoThrow) {
-  if (!CheckDynamicMemoryAllocation(S, OpPC))
-    return false;
-
-  SizeT NumElements = S.Stk.pop<SizeT>();
-  if (!CheckArraySize(S, OpPC, &NumElements, IsNoThrow)) {
-    if (!IsNoThrow)
-      return false;
-
-    // If this failed and is nothrow, just return a null ptr.
-    S.Stk.push<Pointer>(0, nullptr);
-    return true;
-  }
-
-  DynamicAllocator &Allocator = S.getAllocator();
-  Block *B = Allocator.allocate(Source, T, static_cast<size_t>(NumElements),
-                                S.Ctx.getEvalID());
-  assert(B);
-  S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
-
-  return true;
-}
-
-template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
-inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
-                    bool IsNoThrow) {
-  if (!CheckDynamicMemoryAllocation(S, OpPC))
-    return false;
-
-  SizeT NumElements = S.Stk.pop<SizeT>();
-  if (!CheckArraySize(S, OpPC, &NumElements, IsNoThrow)) {
-    if (!IsNoThrow)
-      return false;
-
-    // If this failed and is nothrow, just return a null ptr.
-    S.Stk.push<Pointer>(0, ElementDesc);
-    return true;
-  }
-
-  DynamicAllocator &Allocator = S.getAllocator();
-  Block *B = Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),
-                                S.Ctx.getEvalID());
-  assert(B);
-
-  S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
-
-  return true;
-}
-
-static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) {
-
-  if (!CheckDynamicMemoryAllocation(S, OpPC))
-    return false;
-
-  const Expr *Source = nullptr;
-  const Block *BlockToDelete = nullptr;
-  {
-    // Extra scope for this so the block doesn't have this pointer
-    // pointing to it when we destroy it.
-    const Pointer &Ptr = S.Stk.pop<Pointer>();
-
-    // Deleteing nullptr is always fine.
-    if (Ptr.isZero())
-      return true;
-
-    if (!Ptr.isRoot() || Ptr.isOnePastEnd() || Ptr.isArrayElement()) {
-      const SourceInfo &Loc = S.Current->getSource(OpPC);
-      S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
-          << Ptr.toDiagnosticString(S.getCtx()) << Ptr.isOnePastEnd();
-      return false;
-    }
-
-    Source = Ptr.getDeclDesc()->asExpr();
-    BlockToDelete = Ptr.block();
-
-    if (!CheckDeleteSource(S, OpPC, Source, Ptr))
-      return false;
-  }
-  assert(Source);
-  assert(BlockToDelete);
-
-  DynamicAllocator &Allocator = S.getAllocator();
-  bool WasArrayAlloc = Allocator.isArrayAllocation(Source);
-  const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
-
-  if (!Allocator.deallocate(Source, BlockToDelete, S)) {
-    // Nothing has been deallocated, this must be a double-delete.
-    const SourceInfo &Loc = S.Current->getSource(OpPC);
-    S.FFDiag(Loc, diag::note_constexpr_double_delete);
-    return false;
-  }
-  return CheckNewDeleteForms(S, OpPC, WasArrayAlloc, DeleteIsArrayForm,
-                             BlockDesc, Source);
-}
-
 //===----------------------------------------------------------------------===//
 // Read opcode arguments
 //===----------------------------------------------------------------------===//

diff  --git a/clang/lib/AST/Interp/InterpBlock.h b/clang/lib/AST/Interp/InterpBlock.h
index e86f411704479..1f25de3589630 100644
--- a/clang/lib/AST/Interp/InterpBlock.h
+++ b/clang/lib/AST/Interp/InterpBlock.h
@@ -52,14 +52,14 @@ class Block final {
   Block(unsigned EvalID, const std::optional<unsigned> &DeclID,
         const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false)
       : EvalID(EvalID), DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern),
-        IsDynamic(false), Desc(Desc) {
+        Desc(Desc) {
     assert(Desc);
   }
 
   Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false,
         bool IsExtern = false)
       : EvalID(EvalID), DeclID((unsigned)-1), IsStatic(IsStatic),
-        IsExtern(IsExtern), IsDynamic(false), Desc(Desc) {
+        IsExtern(IsExtern), Desc(Desc) {
     assert(Desc);
   }
 
@@ -73,7 +73,6 @@ class Block final {
   bool isStatic() const { return IsStatic; }
   /// Checks if the block is temporary.
   bool isTemporary() const { return Desc->IsTemporary; }
-  bool isDynamic() const { return IsDynamic; }
   /// Returns the size of the block.
   unsigned getSize() const { return Desc->getAllocSize(); }
   /// Returns the declaration ID.
@@ -136,12 +135,11 @@ class Block final {
   friend class Pointer;
   friend class DeadBlock;
   friend class InterpState;
-  friend class DynamicAllocator;
 
   Block(unsigned EvalID, const Descriptor *Desc, bool IsExtern, bool IsStatic,
         bool IsDead)
       : EvalID(EvalID), IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true),
-        IsDynamic(false), Desc(Desc) {
+        Desc(Desc) {
     assert(Desc);
   }
 
@@ -171,9 +169,6 @@ class Block final {
   /// Flag indicating if the block contents have been initialized
   /// via invokeCtor.
   bool IsInitialized = false;
-  /// Flag indicating if this block has been allocated via dynamic
-  /// memory allocation (e.g. malloc).
-  bool IsDynamic = false;
   /// Pointer to the stack slot descriptor.
   const Descriptor *Desc;
 };

diff  --git a/clang/lib/AST/Interp/InterpState.cpp b/clang/lib/AST/Interp/InterpState.cpp
index fa4d220299e46..a8538541f4915 100644
--- a/clang/lib/AST/Interp/InterpState.cpp
+++ b/clang/lib/AST/Interp/InterpState.cpp
@@ -41,8 +41,6 @@ void InterpState::cleanup() {
       P->PointeeStorage.BS.Pointee = nullptr;
     }
   }
-
-  Alloc.cleanup();
 }
 
 Frame *InterpState::getCurrentFrame() {
@@ -83,18 +81,3 @@ void InterpState::deallocate(Block *B) {
     B->invokeDtor();
   }
 }
-
-bool InterpState::maybeDiagnoseDanglingAllocations() {
-  bool NoAllocationsLeft = (Alloc.getNumAllocations() == 0);
-
-  if (!checkingPotentialConstantExpression()) {
-    for (const auto &It : Alloc.AllocationSites) {
-      assert(It.second.size() > 0);
-
-      const Expr *Source = It.first;
-      CCEDiag(Source->getExprLoc(), diag::note_constexpr_memory_leak)
-          << (It.second.size() - 1) << Source->getSourceRange();
-    }
-  }
-  return NoAllocationsLeft;
-}

diff  --git a/clang/lib/AST/Interp/InterpState.h b/clang/lib/AST/Interp/InterpState.h
index 61ee54331c65d..138e1d7ac95d5 100644
--- a/clang/lib/AST/Interp/InterpState.h
+++ b/clang/lib/AST/Interp/InterpState.h
@@ -14,7 +14,6 @@
 #define LLVM_CLANG_AST_INTERP_INTERPSTATE_H
 
 #include "Context.h"
-#include "DynamicAllocator.h"
 #include "Function.h"
 #include "InterpFrame.h"
 #include "InterpStack.h"
@@ -103,23 +102,13 @@ class InterpState final : public State, public SourceMapper {
 
   void setEvalLocation(SourceLocation SL) { this->EvalLocation = SL; }
 
-  DynamicAllocator &getAllocator() { return Alloc; }
-
-  /// Diagnose any dynamic allocations that haven't been freed yet.
-  /// Will return \c false if there were any allocations to diagnose,
-  /// \c true otherwise.
-  bool maybeDiagnoseDanglingAllocations();
-
 private:
-  friend class EvaluationResult;
   /// AST Walker state.
   State &Parent;
   /// Dead block chain.
   DeadBlock *DeadBlocks = nullptr;
   /// Reference to the offset-source mapping.
   SourceMapper *M;
-  /// Allocator used for dynamic allocations performed via the program.
-  DynamicAllocator Alloc;
 
 public:
   /// Reference to the module containing all bytecode.

diff  --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 3e69098570bd7..8d01fe1ac2bd1 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -58,14 +58,12 @@ def ArgRoundingMode : ArgType { let Name = "llvm::RoundingMode"; }
 def ArgLETD: ArgType { let Name = "const LifetimeExtendedTemporaryDecl *"; }
 def ArgCastKind : ArgType { let Name = "CastKind"; }
 def ArgCallExpr : ArgType { let Name = "const CallExpr *"; }
-def ArgExpr : ArgType { let Name = "const Expr *"; }
 def ArgOffsetOfExpr : ArgType { let Name = "const OffsetOfExpr *"; }
 def ArgDeclRef : ArgType { let Name = "const DeclRefExpr *"; }
+def ArgDesc : ArgType { let Name = "const Descriptor *"; }
 def ArgCCI : ArgType { let Name = "const ComparisonCategoryInfo *"; }
 def ArgDecl : ArgType { let Name = "const Decl*"; }
 def ArgVarDecl : ArgType { let Name = "const VarDecl*"; }
-def ArgDesc : ArgType { let Name = "const Descriptor *"; }
-def ArgPrimType : ArgType { let Name = "PrimType"; }
 
 //===----------------------------------------------------------------------===//
 // Classes of types instructions operate on.
@@ -749,23 +747,3 @@ def GetMemberPtrDecl : Opcode;
 // Debugging.
 //===----------------------------------------------------------------------===//
 def Dump : Opcode;
-
-def Alloc : Opcode {
-  let Args = [ArgDesc];
-}
-
-def AllocN : Opcode {
-  let Types = [IntegerTypeClass];
-  let Args = [ArgPrimType, ArgExpr, ArgBool];
-  let HasGroup = 1;
-}
-
-def AllocCN : Opcode {
-  let Types = [IntegerTypeClass];
-  let Args = [ArgDesc, ArgBool];
-  let HasGroup = 1;
-}
-
-def Free : Opcode {
-  let Args = [ArgBool];
-}

diff  --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h
index 2beb83590dde5..6e9e8675306ef 100644
--- a/clang/lib/AST/Interp/Pointer.h
+++ b/clang/lib/AST/Interp/Pointer.h
@@ -637,7 +637,6 @@ class Pointer {
   friend class MemberPointer;
   friend class InterpState;
   friend struct InitMap;
-  friend class DynamicAllocator;
 
   Pointer(Block *Pointee, unsigned Base, uint64_t Offset);
 

diff  --git a/clang/test/AST/Interp/new-delete.cpp b/clang/test/AST/Interp/new-delete.cpp
deleted file mode 100644
index 744b142492924..0000000000000
--- a/clang/test/AST/Interp/new-delete.cpp
+++ /dev/null
@@ -1,488 +0,0 @@
-// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s
-// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s
-// RUN: %clang_cc1 -verify=ref,both %s
-// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s
-
-#if __cplusplus >= 202002L
-
-constexpr int *Global = new int(12); // both-error {{must be initialized by a constant expression}} \
-                                     // both-note {{pointer to heap-allocated object}} \
-                                     // both-note {{heap allocation performed here}}
-
-static_assert(*(new int(12)) == 12); // both-error {{not an integral constant expression}} \
-                                     // both-note {{allocation performed here was not deallocated}}
-
-
-constexpr int a() {
-  new int(12); // both-note {{allocation performed here was not deallocated}}
-  return 1;
-}
-static_assert(a() == 1, ""); // both-error {{not an integral constant expression}}
-
-constexpr int b() {
-  int *i = new int(12);
-  int m = *i;
-  delete(i);
-  return m;
-}
-static_assert(b() == 12, "");
-
-
-struct S {
-  int a;
-  int b;
-
-  static constexpr S *create(int a, int b) {
-    return new S(a, b);
-  }
-};
-
-constexpr int c() {
-  S *s = new S(12, 13);
-
-  int i = s->a;
-  delete s;
-
-  return i;
-}
-static_assert(c() == 12, "");
-
-/// Dynamic allocation in function ::create(), freed in function d().
-constexpr int d() {
-  S* s = S::create(12, 14);
-
-  int sum = s->a + s->b;
-  delete s;
-  return sum;
-}
-static_assert(d() == 26);
-
-
-/// Test we emit the right diagnostic for several allocations done on
-/// the same site.
-constexpr int loop() {
-  for (int i = 0; i < 10; ++i) {
-    int *a = new int[10]; // both-note {{not deallocated (along with 9 other memory leaks)}}
-  }
-
-  return 1;
-}
-static_assert(loop() == 1, ""); // both-error {{not an integral constant expression}}
-
-/// No initializer.
-constexpr int noInit() {
-  int *i = new int;
-  delete i;
-  return 0;
-}
-static_assert(noInit() == 0, "");
-
-/// Try to delete a pointer that hasn't been heap allocated.
-constexpr int notHeapAllocated() { // both-error {{never produces a constant expression}}
-  int A = 0; // both-note 2{{declared here}}
-  delete &A; // ref-note 2{{delete of pointer '&A' that does not point to a heap-allocated object}} \
-             // expected-note 2{{delete of pointer '&A' that does not point to a heap-allocated object}}
-
-  return 1;
-}
-static_assert(notHeapAllocated() == 1, ""); // both-error {{not an integral constant expression}} \
-                                            // both-note {{in call to 'notHeapAllocated()'}}
-
-consteval int deleteNull() {
-  int *A = nullptr;
-  delete A;
-  return 1;
-}
-static_assert(deleteNull() == 1, "");
-
-consteval int doubleDelete() { // both-error {{never produces a constant expression}}
-  int *A = new int;
-  delete A;
-  delete A; // both-note 2{{delete of pointer that has already been deleted}}
-  return 1;
-}
-static_assert(doubleDelete() == 1); // both-error {{not an integral constant expression}} \
-                                    // both-note {{in call to 'doubleDelete()'}}
-
-constexpr int AutoArray() {
-  auto array = new int[]{0, 1, 2, 3};
-  int ret = array[3];
-  delete [] array;
-  return ret;
-}
-
-static_assert(AutoArray() == 3);
-
-#if 0
-consteval int largeArray1(bool b) {
-  if (b) {
-    int *a = new int[1ull<<32]; // both-note {{cannot allocate array; evaluated array bound 4294967296 is too large}}
-    delete[] a;
-  }
-  return 1;
-}
-static_assert(largeArray1(false) == 1, "");
-static_assert(largeArray1(true) == 1, ""); // both-error {{not an integral constant expression}} \
-                                           // both-note {{in call to 'largeArray1(true)'}}
-
-consteval int largeArray2(bool b) {
-  if (b) {
-    S *a = new S[1ull<<32]; // both-note {{cannot allocate array; evaluated array bound 4294967296 is too large}}
-    delete[] a;
-  }
-  return 1;
-}
-static_assert(largeArray2(false) == 1, "");
-static_assert(largeArray2(true) == 1, ""); // both-error {{not an integral constant expression}} \
-                                           // both-note {{in call to 'largeArray2(true)'}}
-#endif
-namespace Arrays {
-  constexpr int d() {
-    int *Arr = new int[12];
-
-    Arr[0] = 1;
-    Arr[1] = 5;
-
-    int sum = Arr[0] + Arr[1];
-    delete[] Arr;
-    return sum;
-  }
-  static_assert(d() == 6);
-
-
-  constexpr int mismatch1() { // both-error {{never produces a constant expression}}
-    int *i = new int(12); // both-note {{allocated with 'new' here}} \
-                          // both-note 2{{heap allocation performed here}}
-    delete[] i; // both-warning {{'delete[]' applied to a pointer that was allocated with 'new'}} \
-                // both-note 2{{array delete used to delete pointer to non-array object of type 'int'}}
-    return 6;
-  }
-  static_assert(mismatch1() == 6); // both-error {{not an integral constant expression}} \
-                                   // both-note {{in call to 'mismatch1()'}}
-
-  constexpr int mismatch2() { // both-error {{never produces a constant expression}}
-    int *i = new int[12]; // both-note {{allocated with 'new[]' here}} \
-                          // both-note 2{{heap allocation performed here}}
-    delete i; // both-warning {{'delete' applied to a pointer that was allocated with 'new[]'}} \
-              // both-note 2{{non-array delete used to delete pointer to array object of type 'int[12]'}}
-    return 6;
-  }
-  static_assert(mismatch2() == 6); // both-error {{not an integral constant expression}} \
-                                   // both-note {{in call to 'mismatch2()'}}
-  /// Array of composite elements.
-  constexpr int foo() {
-    S *ss = new S[12];
-
-    ss[0].a = 12;
-
-    int m = ss[0].a;
-
-    delete[] ss;
-    return m;
-  }
-  static_assert(foo() == 12);
-
-
-
-  constexpr int ArrayInit() {
-    auto array = new int[4]{0, 1, 2, 3};
-    int ret = array[0];
-    delete [] array;
-    return ret;
-  }
-  static_assert(ArrayInit() == 0, "");
-
-  struct S {
-    float F;
-  };
-  constexpr float ArrayInit2() {
-    auto array = new S[4]{};
-    float ret = array[0].F;
-    delete [] array;
-    return ret;
-  }
-  static_assert(ArrayInit2() == 0.0f, "");
-}
-
-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 {};
-};
-
-[[nodiscard]] void *operator new(std::size_t, const std::nothrow_t&) noexcept;
-[[nodiscard]] void *operator new(std::size_t, std::align_val_t, const std::nothrow_t&) noexcept;
-[[nodiscard]] void *operator new[](std::size_t, const std::nothrow_t&) noexcept;
-[[nodiscard]] void *operator new[](std::size_t, std::align_val_t, const std::nothrow_t&) noexcept;
-[[nodiscard]] void *operator new[](std::size_t, std::align_val_t);
-void operator delete(void*, const std::nothrow_t&) noexcept;
-void operator delete(void*, std::align_val_t, const std::nothrow_t&) noexcept;
-void operator delete[](void*, const std::nothrow_t&) noexcept;
-void operator delete[](void*, std::align_val_t, const std::nothrow_t&) noexcept;
-
-struct placement_new_arg {};
-void *operator new(std::size_t, placement_new_arg);
-void operator delete(void*, placement_new_arg);
-
-
-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(); }
-}
-
-
-
-/// FIXME: The new interpreter produces the wrong diagnostic.
-namespace PlacementNew {
-  constexpr int foo() { // both-error {{never produces a constant expression}}
-    char c[sizeof(int)];
-    new (c) int{12}; // ref-note {{call to placement 'operator new'}} \
-                     // expected-note {{subexpression not valid in a constant expression}}
-    return 0;
-  }
-}
-
-namespace NowThrowNew {
-  constexpr bool erroneous_array_bound_nothrow(long long n) {
-    int *p = new (std::nothrow) int[n];
-    bool result = p != nullptr;
-    delete[] p;
-    return result;
-  }
-  static_assert(erroneous_array_bound_nothrow(3));
-  static_assert(erroneous_array_bound_nothrow(0));
-  static_assert(erroneous_array_bound_nothrow(-1) == 0);
-  static_assert(!erroneous_array_bound_nothrow(1LL << 62));
-
-  struct S { int a; };
-  constexpr bool erroneous_array_bound_nothrow2(long long n) {
-    S *p = new (std::nothrow) S[n];
-    bool result = p != nullptr;
-    delete[] p;
-    return result;
-  }
-  /// This needs support for CXXConstrucExprs with non-constant array sizes.
-  static_assert(erroneous_array_bound_nothrow2(3)); // expected-error {{not an integral constant expression}}
-  static_assert(erroneous_array_bound_nothrow2(0));// expected-error {{not an integral constant expression}}
-  static_assert(erroneous_array_bound_nothrow2(-1) == 0);// expected-error {{not an integral constant expression}}
-  static_assert(!erroneous_array_bound_nothrow2(1LL << 62));// expected-error {{not an integral constant expression}}
-
-  constexpr bool evaluate_nothrow_arg() {
-    bool ok = false;
-    delete new ((ok = true, std::nothrow)) int;
-    return ok;
-  }
-  static_assert(evaluate_nothrow_arg());
-}
-
-namespace placement_new_delete {
-  struct ClassSpecificNew {
-    void *operator new(std::size_t);
-  };
-  struct ClassSpecificDelete {
-    void operator delete(void*);
-  };
-  struct DestroyingDelete {
-    void operator delete(DestroyingDelete*, std::destroying_delete_t);
-  };
-  struct alignas(64) Overaligned {};
-
-  constexpr bool ok() {
-    delete new Overaligned;
-    delete ::new ClassSpecificNew;
-    ::delete new ClassSpecificDelete;
-    ::delete new DestroyingDelete;
-    return true;
-  }
-  static_assert(ok());
-
-  /// FIXME: Diagnosting placement new.
-  constexpr bool bad(int which) {
-    switch (which) {
-    case 0:
-      delete new (placement_new_arg{}) int; // ref-note {{call to placement 'operator new'}} \
-                                            // expected-note {{subexpression not valid in a constant expression}}
-      break;
-
-    case 1:
-      delete new ClassSpecificNew; // ref-note {{call to class-specific 'operator new'}}
-      break;
-
-    case 2:
-      delete new ClassSpecificDelete; // ref-note {{call to class-specific 'operator delete'}}
-      break;
-
-    case 3:
-      delete new DestroyingDelete; // ref-note {{call to class-specific 'operator delete'}}
-      break;
-
-    case 4:
-      // FIXME: This technically follows the standard's rules, but it seems
-      // unreasonable to expect implementations to support this.
-      delete new (std::align_val_t{64}) Overaligned; // ref-note {{placement new expression is not yet supported}} \
-                                                     // expected-note {{subexpression not valid in a constant expression}}
-      break;
-    }
-
-    return true;
-  }
-  static_assert(bad(0)); // both-error {{constant expression}} \
-                         // both-note {{in call}}
-  static_assert(bad(1)); // ref-error {{constant expression}} ref-note {{in call}}
-  static_assert(bad(2)); // ref-error {{constant expression}} ref-note {{in call}}
-  static_assert(bad(3)); // ref-error {{constant expression}} ref-note {{in call}}
-  static_assert(bad(4)); // both-error {{constant expression}} \
-                         // both-note {{in call}}
-}
-
-
-
-
-namespace delete_random_things {
-  static_assert((delete new int, true));
-  static_assert((delete (int*)0, true));
-  int n; // both-note {{declared here}}
-  static_assert((delete &n, true)); // both-error {{}} \
-                                    // both-note {{delete of pointer '&n' that does not point to a heap-allocated object}}
-  struct A { int n; };
-  static_assert((delete &(new A)->n, true)); // both-error {{}} \
-                                             // both-note {{delete of pointer to subobject }}
-  static_assert((delete (new int + 1), true)); // both-error {{}} \
-                                               // ref-note {{delete of pointer '&{*new int#0} + 1' that does not point to complete object}} \
-                                               // expected-note {{delete of pointer '&new int + 1' that does not point to complete object}}
-  static_assert((delete[] (new int[3] + 1), true)); // both-error {{}} \
-                                                    // both-note {{delete of pointer to subobject}}
-  static_assert((delete &(int&)(int&&)0, true)); // both-error {{}} \
-                                                 // both-note {{delete of pointer '&0' that does not point to a heap-allocated object}} \
-                                                 // both-note {{temporary created here}}
-}
-
-namespace value_dependent_delete {
-  template<typename T> void f(T *p) {
-    int arr[(delete p, 0)];
-  }
-}
-
-namespace memory_leaks {
-  static_assert(*new bool(true)); // both-error {{}} both-note {{allocation performed here was not deallocated}}
-
-  constexpr bool *f() { return new bool(true); } // both-note {{allocation performed here was not deallocated}}
-  static_assert(*f()); // both-error {{}}
-
-  struct UP {
-    bool *p;
-    constexpr ~UP() { delete p; }
-    constexpr bool &operator*() { return *p; }
-  };
-  constexpr UP g() { return {new bool(true)}; }
-  static_assert(*g()); // ok
-
-  constexpr bool h(UP p) { return *p; }
-  static_assert(h({new bool(true)})); // ok
-}
-
-/// From test/SemaCXX/cxx2a-consteval.cpp
-
-namespace std {
-template <typename T> struct remove_reference { using type = T; };
-template <typename T> struct remove_reference<T &> { using type = T; };
-template <typename T> struct remove_reference<T &&> { using type = T; };
-template <typename T>
-constexpr typename std::remove_reference<T>::type&& move(T &&t) noexcept {
-  return static_cast<typename std::remove_reference<T>::type &&>(t);
-}
-}
-
-namespace cxx2a {
-struct A {
-  int* p = new int(42); // both-note 7{{heap allocation performed here}}
-  consteval int ret_i() const { return p ? *p : 0; }
-  consteval A ret_a() const { return A{}; }
-  constexpr ~A() { delete p; }
-};
-
-consteval int by_value_a(A a) { return a.ret_i(); }
-
-consteval int const_a_ref(const A &a) {
-  return a.ret_i();
-}
-
-consteval int rvalue_ref(const A &&a) {
-  return a.ret_i();
-}
-
-consteval const A &to_lvalue_ref(const A &&a) {
-  return a;
-}
-
-void test() {
-  constexpr A a{ nullptr };
-  { int k = A().ret_i(); }
-
-  { A k = A().ret_a(); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
-                         // both-note {{heap-allocated object is not a constant expression}}
-  { A k = to_lvalue_ref(A()); } // both-error {{'cxx2a::to_lvalue_ref' is not a constant expression}} \
-                                // both-note {{reference to temporary is not a constant expression}} \
-                                // both-note {{temporary created here}}
-  { A k = to_lvalue_ref(A().ret_a()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
-                                        // both-note {{heap-allocated object is not a constant expression}} \
-                                        // both-error {{'cxx2a::to_lvalue_ref' is not a constant expression}} \
-                                        // both-note {{reference to temporary is not a constant expression}} \
-                                        // both-note {{temporary created here}}
-  { int k = A().ret_a().ret_i(); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
-                                   // both-note {{heap-allocated object is not a constant expression}}
-  { int k = by_value_a(A()); }
-  { int k = const_a_ref(A()); }
-  { int k = const_a_ref(a); }
-  { int k = rvalue_ref(A()); }
-  { int k = rvalue_ref(std::move(a)); }
-  { int k = const_a_ref(A().ret_a()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
-                                        // both-note {{is not a constant expression}}
-  { int k = const_a_ref(to_lvalue_ref(A().ret_a())); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
-                                                       // both-note {{is not a constant expression}}
-  { int k = const_a_ref(to_lvalue_ref(std::move(a))); }
-  { int k = by_value_a(A().ret_a()); }
-  { int k = by_value_a(to_lvalue_ref(static_cast<const A&&>(a))); }
-  { int k = (A().ret_a(), A().ret_i()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
-                                          // both-note {{is not a constant expression}} \
-                                          // both-warning {{left operand of comma operator has no effect}}
-  { int k = (const_a_ref(A().ret_a()), A().ret_i()); }  // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
-                                                        // both-note {{is not a constant expression}} \
-                                                        // both-warning {{left operand of comma operator has no effect}}
-}
-}
-
-constexpr int *const &p = new int; // both-error {{must be initialized by a constant expression}} \
-                                   // both-note {{pointer to heap-allocated object}} \
-                                   // both-note {{allocation performed here}}
-
-constexpr const int *A[] = {nullptr, nullptr, new int{12}}; // both-error {{must be initialized by a constant expression}} \
-                                                            // both-note {{pointer to heap-allocated object}} \
-                                                            // both-note {{allocation performed here}}
-
-struct Sp {
-  const int *p;
-};
-constexpr Sp ss[] = {Sp{new int{154}}}; // both-error {{must be initialized by a constant expression}} \
-                                        // both-note {{pointer to heap-allocated object}} \
-                                        // both-note {{allocation performed here}}
-
-
-
-
-#else
-/// Make sure we reject this prior to C++20
-constexpr int a() { // both-error {{never produces a constant expression}}
-  delete new int(12); // both-note 2{{dynamic memory allocation is not permitted in constant expressions until C++20}}
-  return 1;
-}
-static_assert(a() == 1, ""); // both-error {{not an integral constant expression}} \
-                             // both-note {{in call to 'a()'}}
-#endif

diff  --git a/clang/test/Rewriter/rewrite-modern-catch.m b/clang/test/Rewriter/rewrite-modern-catch.m
index 621c7ec45bae8..1900301e91129 100644
--- a/clang/test/Rewriter/rewrite-modern-catch.m
+++ b/clang/test/Rewriter/rewrite-modern-catch.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
 // RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -fexceptions  -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
 
 void foo(id arg);

diff  --git a/clang/test/SemaCXX/delete.cpp b/clang/test/SemaCXX/delete.cpp
index 7d1f51cb218ce..08cc1766e9f7e 100644
--- a/clang/test/SemaCXX/delete.cpp
+++ b/clang/test/SemaCXX/delete.cpp
@@ -1,5 +1,5 @@
 // Test without PCH
-// RUN: %clang_cc1 -fsyntax-only -include %S/delete-mismatch.h -fdiagnostics-parseable-fixits -std=c++11 %s 2>&1 -fexperimental-new-constant-interpreter | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -include %S/delete-mismatch.h -fdiagnostics-parseable-fixits -std=c++11 %s 2>&1 | FileCheck %s
 
 // Test with PCH
 // RUN: %clang_cc1 -x c++-header -std=c++11 -emit-pch -o %t %S/delete-mismatch.h

diff  --git a/clang/test/SemaCXX/new-delete.cpp b/clang/test/SemaCXX/new-delete.cpp
index 595bdc689d694..ec6ad43476f94 100644
--- a/clang/test/SemaCXX/new-delete.cpp
+++ b/clang/test/SemaCXX/new-delete.cpp
@@ -6,14 +6,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++23
 // RUN: %clang_cc1 -fsyntax-only -verify=expected,since-cxx26,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++2c
 
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++98 -fexperimental-new-constant-interpreter -DNEW_INTERP
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++11 -fexperimental-new-constant-interpreter -DNEW_INTERP
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++14 -fexperimental-new-constant-interpreter -DNEW_INTERP
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++17 -fexperimental-new-constant-interpreter -DNEW_INTERP
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++20 -fexperimental-new-constant-interpreter -DNEW_INTERP
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++23 -fexperimental-new-constant-interpreter -DNEW_INTERP
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,since-cxx26,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++2c -fexperimental-new-constant-interpreter -DNEW_INTERP
-
 // FIXME Location is (frontend)
 // cxx17-note@*:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
 
@@ -661,22 +653,10 @@ int *fail = dependent_array_size("hello"); // expected-note {{instantiation of}}
 // FIXME: Our behavior here is incredibly inconsistent. GCC allows
 // constant-folding in array bounds in new-expressions.
 int (*const_fold)[12] = new int[3][&const_fold + 12 - &const_fold];
-#if __cplusplus >= 201402L && !defined(NEW_INTERP)
+#if __cplusplus >= 201402L
 // expected-error at -2 {{array size is not a constant expression}}
 // expected-note at -3 {{cannot refer to element 12 of non-array}}
-#elif __cplusplus < 201103L && !defined(NEW_INTERP)
+#elif __cplusplus < 201103L
 // expected-error at -5 {{cannot allocate object of variably modified type}}
 // expected-warning at -6 {{variable length arrays in C++ are a Clang extension}}
 #endif
-#ifdef NEW_INTERP
-#if __cplusplus >= 201402L
-// expected-error at -10 {{array size is not a constant expression}}
-// expected-note at -11 {{cannot refer to element 12 of non-array}}
-#elif __cplusplus >= 201103L
-// expected-error at -13 {{only the first dimension of an allocated array may have dynamic size}}
-// expected-note at -14 {{cannot refer to element 12 of non-array}}
-#else
-// expected-error at -16 {{only the first dimension of an allocated array may have dynamic size}}
-// expected-note at -17 {{cannot refer to element 12 of non-array}}
-#endif
-#endif


        


More information about the cfe-commits mailing list