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
