llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Zeyi Xu (zeyi2)

<details>
<summary>Changes</summary>

Closes https://github.com/llvm/llvm-project/issues/196208

---
Full diff: https://github.com/llvm/llvm-project/pull/202286.diff


4 Files Affected:

- (modified) 
clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h (+1-1) 
- (modified) clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp (+15-7) 
- (modified) clang/test/Sema/Inputs/lifetime-analysis.h (+6) 
- (modified) clang/test/Sema/warn-lifetime-safety.cpp (+45-1) 


``````````diff
diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
index 8f0670728bae9..2c961bd305fac 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
@@ -76,7 +76,7 @@ class FactsGenerator : public 
ConstStmtVisitor<FactsGenerator> {
 
   void handlePointerArithmetic(const BinaryOperator *BO);
 
-  void handlePlacementNew(const CXXNewExpr *NE, OriginList *NewList);
+  bool handlePlacementNew(const CXXNewExpr *NE, OriginList *NewList);
 
   void handleCXXCtorInitializer(const CXXCtorInitializer *CII);
 
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 633f9ae57930b..9fbfaf8ae606b 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -631,23 +631,23 @@ void FactsGenerator::VisitArraySubscriptExpr(const 
ArraySubscriptExpr *ASE) {
       Dst->getOuterOriginID(), Src->getOuterOriginID(), /*Kill=*/true));
 }
 
-void FactsGenerator::handlePlacementNew(const CXXNewExpr *NE,
+bool FactsGenerator::handlePlacementNew(const CXXNewExpr *NE,
                                         OriginList *NewList) {
   // Model only the standard single-argument placement new form, where the
   // placement argument corresponds to a void* allocation-function parameter.
   // Other placement forms, such as std::nothrow, are not modeled as providing
   // storage for the returned pointer.
   if (NE->getNumPlacementArgs() != 1)
-    return;
+    return false;
 
   const FunctionDecl *OperatorNew = NE->getOperatorNew();
   if (OperatorNew->getNumParams() <= 1)
-    return;
+    return false;
 
   const auto *Arg =
       OperatorNew->getParamDecl(1)->getType()->getAs<PointerType>();
   if (!Arg || !Arg->isVoidPointerType())
-    return;
+    return false;
 
   // Use the placement argument before the implicit conversion to void*, so
   // inner origins are still available.
@@ -665,15 +665,23 @@ void FactsGenerator::handlePlacementNew(const CXXNewExpr 
*NE,
   if (PlacementList)
     CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
         NewList->getOuterOriginID(), PlacementList->getOuterOriginID(), true));
+  return true;
 }
 
 void FactsGenerator::VisitCXXNewExpr(const CXXNewExpr *NE) {
   OriginList *NewList = getOriginsList(*NE);
   const Expr *Init = NE->getInitializer();
 
-  if (NE->getNumPlacementArgs() == 1) {
-    handlePlacementNew(NE, NewList);
-  } else {
+  bool HandledAsPlacementNew = false;
+  if (NE->getNumPlacementArgs() == 1)
+    HandledAsPlacementNew = handlePlacementNew(NE, NewList);
+
+  // Treat ordinary new and replaceable global allocation forms as heap
+  // allocations.
+  const FunctionDecl *OperatorNew = NE->getOperatorNew();
+  if (!HandledAsPlacementNew &&
+      (NE->getNumPlacementArgs() == 0 ||
+       (OperatorNew && OperatorNew->isReplaceableGlobalAllocationFunction()))) 
{
     const Loan *L = createLoan(FactMgr, NE);
     CurrentBlockFacts.push_back(
         FactMgr.createFact<IssueFact>(L->getID(), 
NewList->getOuterOriginID()));
diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h 
b/clang/test/Sema/Inputs/lifetime-analysis.h
index 4d727ae9499d6..024c3c2bc51b7 100644
--- a/clang/test/Sema/Inputs/lifetime-analysis.h
+++ b/clang/test/Sema/Inputs/lifetime-analysis.h
@@ -53,6 +53,9 @@ T *begin(T (&array)[N]);
 
 using size_t = decltype(sizeof(0));
 using nullptr_t = decltype(nullptr);
+enum class align_val_t : size_t {};
+struct nothrow_t {};
+extern const nothrow_t nothrow;
 
 template<typename T>
 struct initializer_list {
@@ -356,3 +359,6 @@ class function<R(Args...)> {
 
 void *operator new(std::size_t, void *) noexcept;
 void *operator new[](std::size_t, void *) noexcept;
+void *operator new(std::size_t, const std::nothrow_t &) noexcept;
+void *operator new(std::size_t, std::align_val_t,
+                   const std::nothrow_t &) noexcept;
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index 5aaa389b63ccd..efff00517fcaf 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -2751,6 +2751,24 @@ void new_int_braces() {
   (void)*p;           // expected-note {{later used here}}
 }
 
+void new_int_aligned() {
+  int *p = new (std::align_val_t(sizeof(int))) int{}; // expected-warning 
{{allocated object does not live long enough}}
+  delete p;                                           // expected-note {{freed 
here}}
+  (void)*p;                                           // expected-note {{later 
used here}}
+}
+
+void new_int_nothrow() {
+  int *p = new (std::nothrow) int{}; // expected-warning {{allocated object 
does not live long enough}}
+  delete p;                          // expected-note {{freed here}}
+  (void)*p;                          // expected-note {{later used here}}
+}
+
+void new_int_aligned_nothrow() {
+  int *p = new (std::align_val_t(sizeof(int)), std::nothrow) int{}; // 
expected-warning {{allocated object does not live long enough}}
+  delete p;                                                         // 
expected-note {{freed here}}
+  (void)*p;                                                         // 
expected-note {{later used here}}
+}
+
 void conditional_delete(bool cond) {
   int *p1 = new int;       // expected-warning {{allocated object does not 
live long enough}}
   int *p2 = new int;       // expected-warning {{allocated object does not 
live long enough}}
@@ -3009,6 +3027,32 @@ void variadic_placement_new() {
   (void)new (arg) VariadicPlacementNew;
 }
 
+struct Arena {};
+
+struct CustomPlacementNew {
+  int X;
+  void *operator new(std::size_t, Arena &, int);
+  void operator delete(void *);
+};
+
+struct SingleArgCustomPlacementNew {
+  int X;
+  void *operator new(std::size_t, Arena &);
+  void operator delete(void *);
+};
+
+void custom_placement_new_not_heap(Arena &A) {
+  CustomPlacementNew *p = new (A, 0) CustomPlacementNew;
+  delete p;
+  (void)p->X;
+}
+
+void single_arg_custom_placement_new_not_heap(Arena &A) {
+  SingleArgCustomPlacementNew *p = new (A) SingleArgCustomPlacementNew;
+  delete p;
+  (void)p->X;
+}
+
 int* foo(int* x [[clang::lifetimebound]], int* y [[clang::lifetimebound]]);
 
 void placement_new_delete_result_of_lifetimebound_call() {
@@ -3594,4 +3638,4 @@ void capturing_multiple_locals() {
         setCaptureBy(v, local2);    // expected-warning{{local variable 
'local2' does not live long enough}}
     }                               // expected-note 2 {{destroyed here}} 
     (void)v;                        // expected-note 2 {{later used here}}
-}
\ No newline at end of file
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/202286
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to