[clang] [Clang][ExprConst] Accept prvalue for nothrow new (PR #226753)

via cfe-commits cfe-commits at lists.llvm.org
Sun Sep 27 12:00:44 PDT 2026


https://github.com/aokblast updated https://github.com/llvm/llvm-project/pull/226753

>From ff5453f705924f0409df46cc523fcaceedcf459b Mon Sep 17 00:00:00 2001
From: ShengYi Hung <aokblast at FreeBSD.org>
Date: Sat, 26 Sep 2026 23:52:05 -0500
Subject: [PATCH 1/6] [Clang][ExprConst] Accept prvalue for nothrow new

A user defined operator new can accept prvalue for nothrow. There is
no guarantee in spec that it should be lvalue. Relax the check with
side effect only.
---
 clang/lib/AST/ExprConstant.cpp              |  7 +++++--
 clang/test/SemaCXX/new-nothrow-by-value.cpp | 18 ++++++++++++++++++
 2 files changed, 23 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/SemaCXX/new-nothrow-by-value.cpp

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 2df754dc9007f..578ce94e93e3e 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -11030,8 +11030,11 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
     // (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).
-    LValue Nothrow;
-    if (!EvaluateLValue(E->getPlacementArg(0), Nothrow, Info))
+    //
+    // The argument is usually an lvalue (the standard signature takes a
+    // 'const std::nothrow_t &'), but a user-declared allocation function may
+    // take 'std::nothrow_t' by value, in which case it is a prvalue.
+    if (!EvaluateIgnoredValue(Info, E->getPlacementArg(0)))
       return false;
     IsNothrow = true;
   } else if (OperatorNew->isReservedGlobalPlacementOperator()) {
diff --git a/clang/test/SemaCXX/new-nothrow-by-value.cpp b/clang/test/SemaCXX/new-nothrow-by-value.cpp
new file mode 100644
index 0000000000000..acb70803b020c
--- /dev/null
+++ b/clang/test/SemaCXX/new-nothrow-by-value.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+
+// The constant evaluator used to assume the (std::nothrow) placement argument
+// is always an lvalue and crashed when a user-declared allocation function
+// takes std::nothrow_t by value, making the argument a prvalue.
+
+namespace std {
+inline constexpr struct nothrow_t {
+} nothrow;
+} // namespace std
+
+void *operator new[](unsigned long, std::nothrow_t) noexcept;
+void *operator new(unsigned long, std::nothrow_t) noexcept;
+
+void set(int *p) {
+  p = (1 ? new (std::nothrow) int[1] : nullptr);
+  p = (1 ? new (std::nothrow) int : nullptr);
+}

>From ef60af81d777f6a8cbd8a428b7bc7bccad6d1deb Mon Sep 17 00:00:00 2001
From: ShengYi Hung <aokblast at FreeBSD.org>
Date: Sun, 27 Sep 2026 00:29:09 -0500
Subject: [PATCH 2/6] fixup! [Clang][ExprConst] Accept prvalue for nothrow new

---
 clang/test/SemaCXX/new-nothrow-by-value.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/test/SemaCXX/new-nothrow-by-value.cpp b/clang/test/SemaCXX/new-nothrow-by-value.cpp
index acb70803b020c..569ccec204530 100644
--- a/clang/test/SemaCXX/new-nothrow-by-value.cpp
+++ b/clang/test/SemaCXX/new-nothrow-by-value.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter
 
 // The constant evaluator used to assume the (std::nothrow) placement argument
 // is always an lvalue and crashed when a user-declared allocation function

>From c514037b10d0bf7a75f6a3f4e39cadf47440b622 Mon Sep 17 00:00:00 2001
From: ShengYi Hung <aokblast at FreeBSD.org>
Date: Sun, 27 Sep 2026 01:23:48 -0500
Subject: [PATCH 3/6] fixup! [Clang][ExprConst] Accept prvalue for nothrow new

---
 clang/test/SemaCXX/new-nothrow-by-value.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/test/SemaCXX/new-nothrow-by-value.cpp b/clang/test/SemaCXX/new-nothrow-by-value.cpp
index 569ccec204530..5bd784b157d5e 100644
--- a/clang/test/SemaCXX/new-nothrow-by-value.cpp
+++ b/clang/test/SemaCXX/new-nothrow-by-value.cpp
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter
+// expected-no-diagnostics
 
 // The constant evaluator used to assume the (std::nothrow) placement argument
 // is always an lvalue and crashed when a user-declared allocation function

>From 220b5f54e2e2cca92e36d7e0033f0000e8381073 Mon Sep 17 00:00:00 2001
From: ShengYi Hung <aokblast at FreeBSD.org>
Date: Sun, 27 Sep 2026 02:02:22 -0500
Subject: [PATCH 4/6] fixup! [Clang][ExprConst] Accept prvalue for nothrow new

---
 clang/test/SemaCXX/new-nothrow-by-value.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/SemaCXX/new-nothrow-by-value.cpp b/clang/test/SemaCXX/new-nothrow-by-value.cpp
index 5bd784b157d5e..2f7af00b9316b 100644
--- a/clang/test/SemaCXX/new-nothrow-by-value.cpp
+++ b/clang/test/SemaCXX/new-nothrow-by-value.cpp
@@ -11,8 +11,8 @@ inline constexpr struct nothrow_t {
 } nothrow;
 } // namespace std
 
-void *operator new[](unsigned long, std::nothrow_t) noexcept;
-void *operator new(unsigned long, std::nothrow_t) noexcept;
+void *operator new[](__SIZE_TYPE__, std::nothrow_t) noexcept;
+void *operator new(__SIZE_TYPE__, std::nothrow_t) noexcept;
 
 void set(int *p) {
   p = (1 ? new (std::nothrow) int[1] : nullptr);

>From 5402c8aa4637f3295159df5765b7c505e467adf2 Mon Sep 17 00:00:00 2001
From: ShengYi Hung <aokblast at FreeBSD.org>
Date: Sun, 27 Sep 2026 12:27:17 -0500
Subject: [PATCH 5/6] fixup! [Clang][ExprConst] Accept prvalue for nothrow new

---
 clang/lib/AST/ByteCode/Compiler.cpp         |  6 ++-
 clang/lib/AST/ByteCode/Interp.cpp           | 10 +++++
 clang/lib/AST/ExprConstant.cpp              | 45 +++++++++++----------
 clang/test/SemaCXX/new-nothrow-by-value.cpp | 17 ++++++--
 4 files changed, 52 insertions(+), 26 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 81c8fb0b9f17d..408ff5ca446e4 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -4275,7 +4275,11 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
     // alignof(X) and X has new-extended alignment).
     if (PlacementArgs == 1) {
       const Expr *Arg1 = E->getPlacementArg(0);
-      if (Arg1->getType()->isNothrowT()) {
+      // A user-declared allocation function taking std::nothrow_t (for
+      // instance by value) is not usable in a constant expression.
+      if (Arg1->getType()->isNothrowT() &&
+          OperatorNew
+              ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
         if (!this->discard(Arg1))
           return false;
         IsNoThrow = true;
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index f885c0dc9cdb2..4bc1d012f71b7 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -2935,6 +2935,16 @@ bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E) {
     const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();
 
     if (NewExpr->getNumPlacementArgs() > 0) {
+      if (NewExpr->getNumPlacementArgs() == 1 &&
+          NewExpr->getPlacementArg(0)->getType()->isNothrowT() &&
+          !OperatorNew
+               ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
+        S.FFDiag(S.Current->getSource(OpPC),
+                 diag::note_constexpr_new_non_replaceable)
+            << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
+        return false;
+      }
+
       // This is allowed pre-C++26, but only an std function or if
       // [[msvc::constexpr]] was used.
       if (S.getLangOpts().CPlusPlus26 || S.Current->isStdFunction() ||
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 636a6a2449ebb..f7faffc767c1c 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -11018,26 +11018,21 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
   bool IsNothrow = false;
   bool IsPlacement = false;
 
-  if (E->getNumPlacementArgs() == 1 &&
-      E->getPlacementArg(0)->getType()->isNothrowT()) {
-    // 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).
-    //
-    // The argument is usually an lvalue (the standard signature takes a
-    // 'const std::nothrow_t &'), but a user-declared allocation function may
-    // take 'std::nothrow_t' by value, in which case it is a prvalue.
-    if (!EvaluateIgnoredValue(Info, E->getPlacementArg(0)))
-      return false;
-    IsNothrow = true;
-  } else if (OperatorNew->isReservedGlobalPlacementOperator()) {
+  // The only new-placement list we support (other than the reserved placement
+  // form) 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).
+  bool HasNothrowArg = E->getNumPlacementArgs() == 1 &&
+                       E->getPlacementArg(0)->getType()->isNothrowT();
+
+  if (OperatorNew->isReservedGlobalPlacementOperator()) {
     if (Info.CurrentCall->isStdFunction() || Info.getLangOpts().CPlusPlus26 ||
         (Info.CurrentCall->CanEvalMSConstexpr &&
          OperatorNew->hasAttr<MSConstexprAttr>())) {
@@ -11052,15 +11047,23 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
           << /*C++26 feature*/ 1 << E->getSourceRange();
       return false;
     }
-  } else if (E->getNumPlacementArgs()) {
+  } else if (E->getNumPlacementArgs() && !HasNothrowArg) {
     Info.FFDiag(E, diag::note_constexpr_new_placement)
         << /*Unsupported*/ 0 << E->getSourceRange();
     return false;
   } else if (!OperatorNew
                   ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
+    // [expr.const] only permits new-expressions that select a replaceable
+    // global allocation function. Check this before evaluating a
+    // (std::nothrow) placement argument.
     Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
         << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
     return false;
+  } else if (HasNothrowArg) {
+    LValue Nothrow;
+    if (!EvaluateLValue(E->getPlacementArg(0), Nothrow, Info))
+      return false;
+    IsNothrow = true;
   }
 
   const Expr *Init = E->getInitializer();
diff --git a/clang/test/SemaCXX/new-nothrow-by-value.cpp b/clang/test/SemaCXX/new-nothrow-by-value.cpp
index 2f7af00b9316b..c2985ad582219 100644
--- a/clang/test/SemaCXX/new-nothrow-by-value.cpp
+++ b/clang/test/SemaCXX/new-nothrow-by-value.cpp
@@ -1,10 +1,12 @@
 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter
-// expected-no-diagnostics
 
-// The constant evaluator used to assume the (std::nothrow) placement argument
-// is always an lvalue and crashed when a user-declared allocation function
-// takes std::nothrow_t by value, making the argument a prvalue.
+// [expr.const] only permits a new-expression in a constant expression when it
+// selects a replaceable global allocation function. None of them take
+// std::nothrow_t by value, so a user-declared allocation function that does
+// must be rejected before examining its placement argument. The constant
+// evaluator used to assume the argument was always an lvalue and crashed on
+// the prvalue produced here.
 
 namespace std {
 inline constexpr struct nothrow_t {
@@ -18,3 +20,10 @@ void set(int *p) {
   p = (1 ? new (std::nothrow) int[1] : nullptr);
   p = (1 ? new (std::nothrow) int : nullptr);
 }
+
+constexpr bool by_value() { // expected-error {{constexpr function never produces a constant expression}}
+  int *p = new (std::nothrow) int; // expected-note 2{{call to placement 'operator new'}}
+  delete p;
+  return true;
+}
+static_assert(by_value()); // expected-error {{not an integral constant expression}} expected-note {{in call to 'by_value()'}}

>From c155716ee6403804f4341c1293e93df388dfb2cf Mon Sep 17 00:00:00 2001
From: ShengYi Hung <aokblast at FreeBSD.org>
Date: Sun, 27 Sep 2026 14:00:24 -0500
Subject: [PATCH 6/6] fixup! [Clang][ExprConst] Accept prvalue for nothrow new

---
 clang/lib/AST/ByteCode/Compiler.cpp | 20 ++++----
 clang/lib/AST/ByteCode/Interp.cpp   | 79 ++++++++++++-----------------
 clang/lib/AST/ByteCode/Interp.h     |  1 +
 clang/lib/AST/ByteCode/Opcodes.td   |  1 +
 4 files changed, 43 insertions(+), 58 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 408ff5ca446e4..353fd45d8049c 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -4275,23 +4275,21 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
     // alignof(X) and X has new-extended alignment).
     if (PlacementArgs == 1) {
       const Expr *Arg1 = E->getPlacementArg(0);
-      // A user-declared allocation function taking std::nothrow_t (for
-      // instance by value) is not usable in a constant expression.
-      if (Arg1->getType()->isNothrowT() &&
+      if (OperatorNew->isReservedGlobalPlacementOperator()) {
+        if (!this->emitCheckPlacementNew(E, E))
+          return false;
+        PlacementDest = Arg1;
+      } else if (
+          Arg1->getType()->isNothrowT() &&
           OperatorNew
               ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
         if (!this->discard(Arg1))
           return false;
         IsNoThrow = true;
       } else {
-        // Invalid unless we have C++26 or are in a std:: function.
-        if (!this->emitInvalidNewDeleteExpr(E, E))
-          return false;
-
-        // If we have a placement-new destination, we'll later use that instead
-        // of allocating.
-        if (OperatorNew->isReservedGlobalPlacementOperator())
-          PlacementDest = Arg1;
+        // Any other placement list is invalid. This includes a user-declared
+        // allocation function taking std::nothrow_t, e.g. by value.
+        return this->emitInvalidNewDeleteExpr(E, E);
       }
     } else {
       // Always invalid.
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 4bc1d012f71b7..35a5eaa9abb67 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -2884,9 +2884,6 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
   if (!S.inConstantContext() && isConstexprUnknown(Ptr))
     return false;
 
-  if (!InvalidNewDeleteExpr(S, OpPC, E))
-    return false;
-
   const auto *NewExpr = cast<CXXNewExpr>(E);
   const ASTContext &ASTCtx = S.getASTContext();
   QualType StorageType = Ptr.getType();
@@ -2930,58 +2927,46 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
 
 bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E) {
   assert(E);
+  const SourceInfo &Loc = S.Current->getSource(OpPC);
 
   if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {
     const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();
 
-    if (NewExpr->getNumPlacementArgs() > 0) {
-      if (NewExpr->getNumPlacementArgs() == 1 &&
-          NewExpr->getPlacementArg(0)->getType()->isNothrowT() &&
-          !OperatorNew
-               ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
-        S.FFDiag(S.Current->getSource(OpPC),
-                 diag::note_constexpr_new_non_replaceable)
-            << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
-        return false;
-      }
-
-      // This is allowed pre-C++26, but only an std function or if
-      // [[msvc::constexpr]] was used.
-      if (S.getLangOpts().CPlusPlus26 || S.Current->isStdFunction() ||
-          S.Current->MSVCConstexprAllowed)
-        return true;
-
-      S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement)
-          << /*C++26 feature*/ 1 << E->getSourceRange();
-    } else if (
-        !OperatorNew
-             ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
-      S.FFDiag(S.Current->getSource(OpPC),
-               diag::note_constexpr_new_non_replaceable)
-          << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
-      return false;
-    } else if (!S.getLangOpts().CPlusPlus26 &&
-               NewExpr->getNumPlacementArgs() == 1 &&
-               !OperatorNew->isReservedGlobalPlacementOperator()) {
-      if (!S.getLangOpts().CPlusPlus26) {
-        S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement)
-            << /*Unsupported*/ 0 << E->getSourceRange();
-        return false;
-      }
-      return true;
-    }
-  } else {
-    const auto *DeleteExpr = cast<CXXDeleteExpr>(E);
-    const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();
-    if (!OperatorDelete
-             ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
-      S.FFDiag(S.Current->getSource(OpPC),
-               diag::note_constexpr_new_non_replaceable)
-          << isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;
+    // The only new-placement list we support is (std::nothrow), and only for
+    // the replaceable global allocation functions.
+    bool IsNothrowForm = NewExpr->getNumPlacementArgs() == 1 &&
+                         NewExpr->getPlacementArg(0)->getType()->isNothrowT();
+    if (NewExpr->getNumPlacementArgs() > 0 && !IsNothrowForm) {
+      S.FFDiag(Loc, diag::note_constexpr_new_placement)
+          << /*Unsupported*/ 0 << E->getSourceRange();
       return false;
     }
+
+    assert(
+        !OperatorNew->isUsableAsGlobalAllocationFunctionInConstantEvaluation());
+    S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable)
+        << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
+    return false;
   }
 
+  const auto *DeleteExpr = cast<CXXDeleteExpr>(E);
+  const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();
+  assert(!OperatorDelete
+              ->isUsableAsGlobalAllocationFunctionInConstantEvaluation());
+  S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable)
+      << isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;
+  return false;
+}
+
+bool CheckPlacementNew(InterpState &S, CodePtr OpPC, const Expr *E) {
+  // Placement new is allowed in C++26. Before that, it is only allowed in a
+  // std:: function or if [[msvc::constexpr]] was used.
+  if (S.getLangOpts().CPlusPlus26 || S.Current->isStdFunction() ||
+      S.Current->MSVCConstexprAllowed)
+    return true;
+
+  S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement)
+      << /*C++26 feature*/ 1 << E->getSourceRange();
   return false;
 }
 
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index a106295022f9b..aed1e17a97479 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -4079,6 +4079,7 @@ bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) {
   return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size));
 }
 bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
+bool CheckPlacementNew(InterpState &S, CodePtr OpPC, const Expr *E);
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index fcbd7461b6b5b..8b92654adfd6f 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -1025,6 +1025,7 @@ def CheckNewTypeMismatchArray : Opcode {
   let HasGroup = 1;
 }
 def InvalidNewDeleteExpr : Opcode { let Args = [ArgExpr]; }
+def CheckPlacementNew : Opcode { let Args = [ArgExpr]; }
 
 def IsConstantContext: SuccessOpcode;
 def CheckAllocations : Opcode {



More information about the cfe-commits mailing list