diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index 5e9c7d0add4f8..60666287cf307 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -36,7 +36,6 @@ #include "MisplacedPointerArithmeticInAllocCheck.h" #include "MisplacedWideningCastCheck.h" #include "MoveForwardingReferenceCheck.h" -#include "MultipleNewInOneExpressionCheck.h" #include "MultipleStatementMacroCheck.h" #include "NoEscapeCheck.h" #include "NonZeroEnumToBoolConversionCheck.h" @@ -134,8 +133,6 @@ class BugproneModule : public ClangTidyModule { "bugprone-misplaced-widening-cast"); CheckFactories.registerCheck( "bugprone-move-forwarding-reference"); - CheckFactories.registerCheck( - "bugprone-multiple-new-in-one-expression"); CheckFactories.registerCheck( "bugprone-multiple-statement-macro"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index e70d1b426a1c6..5af5a59e5340f 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -31,7 +31,6 @@ add_clang_library(clangTidyBugproneModule MisplacedPointerArithmeticInAllocCheck.cpp MisplacedWideningCastCheck.cpp MoveForwardingReferenceCheck.cpp - MultipleNewInOneExpressionCheck.cpp MultipleStatementMacroCheck.cpp NoEscapeCheck.cpp NonZeroEnumToBoolConversionCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/MultipleNewInOneExpressionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/MultipleNewInOneExpressionCheck.cpp deleted file mode 100644 index 47b9667859903..0000000000000 --- a/clang-tools-extra/clang-tidy/bugprone/MultipleNewInOneExpressionCheck.cpp +++ /dev/null @@ -1,162 +0,0 @@ -//===--- MultipleNewInOneExpressionCheck.cpp - clang-tidy------------------===// -// -// 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 "MultipleNewInOneExpressionCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Lex/Lexer.h" - -using namespace clang::ast_matchers; -using namespace clang; - -namespace { - -// Determine if the result of an expression is "stored" in some way. -// It is true if the value is stored into a variable or used as initialization -// or passed to a function or constructor. -// For this use case compound assignments are not counted as a "store" (the 'E' -// expression should have pointer type). -bool isExprValueStored(const Expr *E, ASTContext &C) { - E = E->IgnoreParenCasts(); - // Get first non-paren, non-cast parent. - ParentMapContext &PMap = C.getParentMapContext(); - DynTypedNodeList P = PMap.getParents(*E); - if (P.size() != 1) - return false; - const Expr *ParentE; - while ((ParentE = P[0].get()) && ParentE->IgnoreParenCasts() == E) { - P = PMap.getParents(P[0]); - if (P.size() != 1) - return false; - } - - if (const auto *ParentVarD = P[0].get()) - return ParentVarD->getInit()->IgnoreParenCasts() == E; - - if (!ParentE) - return false; - - if (const auto *BinOp = dyn_cast(ParentE)) - return BinOp->getOpcode() == BO_Assign && - BinOp->getRHS()->IgnoreParenCasts() == E; - - return isa(ParentE); -} - -} // namespace - -namespace clang { -namespace tidy { -namespace bugprone { - -AST_MATCHER_P(CXXTryStmt, hasHandlerFor, - ast_matchers::internal::Matcher, InnerMatcher) { - for (unsigned NH = Node.getNumHandlers(), I = 0; I < NH; ++I) { - const CXXCatchStmt *CatchS = Node.getHandler(I); - // Check for generic catch handler (match anything). - if (CatchS->getCaughtType().isNull()) - return true; - ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder); - if (InnerMatcher.matches(CatchS->getCaughtType(), Finder, &Result)) { - *Builder = std::move(Result); - return true; - } - } - return false; -} - -AST_MATCHER(CXXNewExpr, mayThrow) { - FunctionDecl *OperatorNew = Node.getOperatorNew(); - if (!OperatorNew) - return false; - return !OperatorNew->getType()->castAs()->isNothrow(); -} - -void MultipleNewInOneExpressionCheck::registerMatchers(MatchFinder *Finder) { - auto BadAllocType = - recordType(hasDeclaration(cxxRecordDecl(hasName("::std::bad_alloc")))); - auto ExceptionType = - recordType(hasDeclaration(cxxRecordDecl(hasName("::std::exception")))); - auto BadAllocReferenceType = referenceType(pointee(BadAllocType)); - auto ExceptionReferenceType = referenceType(pointee(ExceptionType)); - - auto CatchBadAllocType = - qualType(hasCanonicalType(anyOf(BadAllocType, BadAllocReferenceType, - ExceptionType, ExceptionReferenceType))); - auto BadAllocCatchingTryBlock = cxxTryStmt(hasHandlerFor(CatchBadAllocType)); - - auto NewExprMayThrow = cxxNewExpr(mayThrow()); - auto HasNewExpr1 = expr(anyOf(NewExprMayThrow.bind("new1"), - hasDescendant(NewExprMayThrow.bind("new1")))); - auto HasNewExpr2 = expr(anyOf(NewExprMayThrow.bind("new2"), - hasDescendant(NewExprMayThrow.bind("new2")))); - - Finder->addMatcher( - callExpr( - hasAnyArgument( - expr(HasNewExpr1).bind("arg1")), - hasAnyArgument( - expr(HasNewExpr2, unless(equalsBoundNode("arg1"))).bind("arg2")), - hasAncestor(BadAllocCatchingTryBlock)), - this); - Finder->addMatcher( - cxxConstructExpr( - hasAnyArgument( - expr(HasNewExpr1).bind("arg1")), - hasAnyArgument( - expr(HasNewExpr2, unless(equalsBoundNode("arg1"))).bind("arg2")), - unless(isListInitialization()), - hasAncestor(BadAllocCatchingTryBlock)), - this); - Finder->addMatcher(binaryOperator(hasLHS(HasNewExpr1), hasRHS(HasNewExpr2), - unless(hasAnyOperatorName("&&", "||", ",")), - hasAncestor(BadAllocCatchingTryBlock)), - this); - Finder->addMatcher( - cxxNewExpr(mayThrow(), - hasDescendant(NewExprMayThrow.bind("new2_in_new1")), - hasAncestor(BadAllocCatchingTryBlock)) - .bind("new1"), - this); -} - -void MultipleNewInOneExpressionCheck::check( - const MatchFinder::MatchResult &Result) { - const auto *NewExpr1 = Result.Nodes.getNodeAs("new1"); - const auto *NewExpr2 = Result.Nodes.getNodeAs("new2"); - const auto *NewExpr2InNewExpr1 = - Result.Nodes.getNodeAs("new2_in_new1"); - if (!NewExpr2) - NewExpr2 = NewExpr2InNewExpr1; - assert(NewExpr1 && NewExpr2 && "Bound nodes not found."); - - // No warning if both allocations are not stored. - // The value may be intentionally not stored (no deallocations needed or - // self-destructing object). - if (!isExprValueStored(NewExpr1, *Result.Context) && - !isExprValueStored(NewExpr2, *Result.Context)) - return; - - // In C++17 sequencing of a 'new' inside constructor arguments of another - // 'new' is fixed. Still a leak can happen if the returned value from the - // first 'new' is not saved (yet) and the second fails. - if (getLangOpts().CPlusPlus17 && NewExpr2InNewExpr1) - diag(NewExpr1->getBeginLoc(), - "memory allocation may leak if an other allocation is sequenced after " - "it and throws an exception") - << NewExpr1->getSourceRange() << NewExpr2->getSourceRange(); - else - diag(NewExpr1->getBeginLoc(), - "memory allocation may leak if an other allocation is sequenced after " - "it and throws an exception; order of these allocations is undefined") - << NewExpr1->getSourceRange() << NewExpr2->getSourceRange(); -} - -} // namespace bugprone -} // namespace tidy -} // namespace clang diff --git a/clang-tools-extra/clang-tidy/bugprone/MultipleNewInOneExpressionCheck.h b/clang-tools-extra/clang-tidy/bugprone/MultipleNewInOneExpressionCheck.h deleted file mode 100644 index eba6c84d818ca..0000000000000 --- a/clang-tools-extra/clang-tidy/bugprone/MultipleNewInOneExpressionCheck.h +++ /dev/null @@ -1,35 +0,0 @@ -//===--- MultipleNewInOneExpressionCheck.h - clang-tidy----------*- 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_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MULTIPLENEWINONEEXPRESSIONCHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MULTIPLENEWINONEEXPRESSIONCHECK_H - -#include "../ClangTidyCheck.h" - -namespace clang { -namespace tidy { -namespace bugprone { - -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/multiple-new-in-one-expression.html -class MultipleNewInOneExpressionCheck : public ClangTidyCheck { -public: - MultipleNewInOneExpressionCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { - return LangOpts.CPlusPlus; - } - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace bugprone -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MULTIPLENEWINONEEXPRESSIONCHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index e4220b3134714..5695d59e89153 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -106,12 +106,6 @@ Improvements to clang-tidy New checks ^^^^^^^^^^ -- New :doc:`bugprone-multiple-new-in-one-expression - ` check. - - Finds multiple ``new`` operator calls in a single expression, where the allocated - memory by the first ``new`` may leak if the second allocation fails and throws exception. - - New :doc:`bugprone-non-zero-enum-to-bool-conversion ` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/multiple-new-in-one-expression.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/multiple-new-in-one-expression.rst deleted file mode 100644 index b9b8984ef6584..0000000000000 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/multiple-new-in-one-expression.rst +++ /dev/null @@ -1,99 +0,0 @@ -.. title:: clang-tidy - bugprone-multiple-new-in-one-expression - -bugprone-multiple-new-in-one-expression -======================================= - -Finds multiple ``new`` operator calls in a single expression, where the -allocated memory by the first ``new`` may leak if the second allocation fails -and throws exception. - -C++ does often not specify the exact order of evaluation of the operands of an -operator or arguments of a function. Therefore if a first allocation succeeds -and a second fails, in an exception handler it is not possible to tell which -allocation has failed and free the memory. Even if the order is fixed the result -of a first ``new`` may be stored in a temporary location that is not reachable -at the time when a second allocation fails. It is best to avoid any expression -that contains more than one ``operator new`` call, if exception handling is -used to check for allocation errors. - -Different rules apply for are the short-circuit operators ``||`` and ``&&`` and -the ``,`` operator, where evaluation of one side must be completed before the -other starts. Expressions of a list-initialization (initialization or -construction using ``{`` and ``}`` characters) are evaluated in fixed order. -Similarly, condition of a ``?`` operator is evaluated before the branches are -evaluated. - -The check reports warning if two ``new`` calls appear in one expression at -different sides of an operator, or if ``new`` calls appear in different -arguments of a function call (that can be an object construction with ``()`` -syntax). These ``new`` calls can be nested at any level. -For any warning to be emitted the ``new`` calls should be in a code block where -exception handling is used with catch for ``std::bad_alloc`` or -``std::exception``. At ``||``, ``&&``, ``,``, ``?`` (condition and one branch) -operators no warning is emitted. No warning is emitted if both of the memory -allocations are not assigned to a variable or not passed directly to a function. -The reason is that in this case the memory may be intentionally not freed or the -allocated objects can be self-destructing objects. - -Examples: - -.. code-block:: c++ - - struct A { - int Var; - }; - struct B { - B(); - B(A *); - int Var; - }; - struct C { - int *X1; - int *X2; - }; - - void f(A *, B *); - int f1(A *); - int f1(B *); - bool f2(A *); - - void foo() { - A *PtrA; - B *PtrB; - try { - // Allocation of 'B'/'A' may fail after memory for 'A'/'B' was allocated. - f(new A, new B); // warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; order of these allocations is undefined - - // List (aggregate) initialization is used. - C C1{new int, new int}; // no warning - - // Allocation of 'B'/'A' may fail after memory for 'A'/'B' was allocated but not yet passed to function 'f1'. - int X = f1(new A) + f1(new B); // warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; order of these allocations is undefined - - // Allocation of 'B' may fail after memory for 'A' was allocated. - // From C++17 on memory for 'B' is allocated first but still may leak if allocation of 'A' fails. - PtrB = new B(new A); // warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception - - // 'new A' and 'new B' may be performed in any order. - // 'new B'/'new A' may fail after memory for 'A'/'B' was allocated but not assigned to 'PtrA'/'PtrB'. - (PtrA = new A)->Var = (PtrB = new B)->Var; // warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; order of these allocations is undefined - - // Evaluation of 'f2(new A)' must be finished before 'f1(new B)' starts. - // If 'new B' fails the allocated memory for 'A' is supposedly handled correctly because function 'f2' could take the ownership. - bool Z = f2(new A) || f1(new B); // no warning - - X = (f2(new A) ? f1(new A) : f1(new B)); // no warning - - // No warning if the result of both allocations is not passed to a function - // or stored in a variable. - (new A)->Var = (new B)->Var; // no warning - - // No warning if at least one non-throwing allocation is used. - f(new(std::nothrow) A, new B); // no warning - } catch(std::bad_alloc) { - } - - // No warning if the allocation is outside a try block (or no catch handler exists for std::bad_alloc). - // (The fact if exceptions can escape from 'foo' is not taken into account.) - f(new A, new B); // no warning - } diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 6a58bb932e9ec..3ddd257e70de6 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -102,7 +102,6 @@ Clang-Tidy Checks `bugprone-misplaced-pointer-arithmetic-in-alloc `_, "Yes" `bugprone-misplaced-widening-cast `_, `bugprone-move-forwarding-reference `_, "Yes" - `bugprone-multiple-new-in-one-expression `_, `bugprone-multiple-statement-macro `_, `bugprone-no-escape `_, `bugprone-non-zero-enum-to-bool-conversion `_, diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/multiple-new-in-one-expression.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/multiple-new-in-one-expression.cpp deleted file mode 100644 index 8ac77af328f21..0000000000000 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/multiple-new-in-one-expression.cpp +++ /dev/null @@ -1,197 +0,0 @@ -// RUN: %check_clang_tidy -std=c++11 -check-suffixes=ALL,CPP11 %s bugprone-multiple-new-in-one-expression %t -// RUN: %check_clang_tidy -std=c++17 -check-suffixes=ALL,CPP17 %s bugprone-multiple-new-in-one-expression %t - -namespace std { -typedef __typeof__(sizeof(0)) size_t; -enum class align_val_t : std::size_t {}; -class exception {}; -class bad_alloc : public exception {}; -struct nothrow_t {}; -extern const nothrow_t nothrow; -} // namespace std - -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; -void *operator new(std::size_t, void *) noexcept; -void *operator new(std::size_t, char); - -struct B; - -struct A { int VarI; int *PtrI; B *PtrB; }; - -struct B { int VarI; }; - -struct G { - G(A*, B*) {} - int operator+=(A *) { return 3; }; -}; - -struct H { - int *a; - int *b; -}; - -int f(int); -int f(A*); -int f(A*, B*); -int f(int, B*); -int f(G, G); -int f(B*); -int f(const H &); -void f1(void *, void *); -A *g(A *); - -G operator+(const G&, const G&); - -void test_function_parameter(A *XA, B *XB) { - (void)f(new A, new B); - try { - (void)f(new A, new B); - } - catch (A) {}; - try { - (void)f(new A, new B); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; order of these allocations is undefined [ - (void)f(f(new A, new B)); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - int X = f(new A, new B); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - X = f(new A, new B); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:11: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - X = 1 + f(new A, new B); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - - (void)f(g(new A), new B); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - - (void)f(1 + f(new A), new B); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:19: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - (void)f(XA = new A, new B); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:18: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - (void)f(1 + f(new A), XB = new B); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:19: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - } - catch (std::exception) {} -} - -void test_operator(G *G1) { - (void)(f(new A) + f(new B)); - try { - (void)(f(new A) + f(new B)); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:14: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - (void)f(f(new A) + f(new B)); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - int X = f(new A) + f(new B); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - X = f(new A) + f(new B); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:11: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - X = 1 + f(new A) + 1 + f(new B); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:15: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - - (void)(f(g(new A)) + f(new B)); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:16: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - - (void)(f(1 + f(new A)) + f(new B)); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:20: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - (void)(f(1 + f(new A)) + f(1 + f(new B))); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:20: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - - (void)((new A)->VarI + (new A)->VarI); - - (void)(f(new A) + ((*G1) += new A)); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:14: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - } - catch (std::bad_alloc) {} -} - -void test_construct() { - (void)(G(new A, new B)); - try { - (void)(G(new A, new B)); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:14: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - (void)(G(new A, nullptr) + G(nullptr, new B)); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:14: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - f(G(new A, nullptr), G(new A, nullptr)); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:9: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - - (void)new G(new A, nullptr); - // CHECK-MESSAGES-CPP11: :[[@LINE-1]]:11: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - // CHECK-MESSAGES-CPP17: :[[@LINE-2]]:11: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception [ - (void)new G(nullptr, (new A)->PtrB); - G *Z = new G(new A, nullptr); - // CHECK-MESSAGES-CPP11: :[[@LINE-1]]:12: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - // CHECK-MESSAGES-CPP17: :[[@LINE-2]]:12: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception [ - Z = new G(g(new A), nullptr); - // CHECK-MESSAGES-CPP11: :[[@LINE-1]]:9: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - // CHECK-MESSAGES-CPP17: :[[@LINE-2]]:9: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception [ - G *Z1, *Z2 = new G(nullptr, (new A)->PtrB), *Z3; - // CHECK-MESSAGES-CPP11: :[[@LINE-1]]:18: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - // CHECK-MESSAGES-CPP17: :[[@LINE-2]]:18: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception [ - } - catch (const std::bad_alloc &) {} -} - -void test_new_assign() { - A *X, *Y; - (X = new A)->VarI = (Y = new A)->VarI; - try { - (X = new A)->VarI = (Y = new A)->VarI; - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - (new A)->VarI = (Y = new A)->VarI; - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:6: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - (X = new A)->VarI = (new A)->VarI; - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - (new A)->VarI = (new A)->VarI; - (new A)->PtrI = new int; - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:6: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - (X = new A)->VarI += (new A)->VarI; - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:10: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - } - catch (...) {} -} - -void test_operator_fixed_order(unsigned int L) { - (void)(f((f(new A) || f(0)) + f(new B[L]))); - try { - (void)(f(new A) || f(new B)); - (void)(f(new A) && f(new B)); - (void)(f(new A) || f(new B) || f(new A)); - - (void)(f(new A), f(new B)); - - int Y = f(0, new B) ? f(new A) : f(new B); - Y = f(new A) ? 1 : f(new B); - Y = f(new A) ? f(new B) : 1; - - G g{new A, new B}; - H h{new int, new int}; - f({new int, new int}); - (void)f({new A, new B}, {nullptr, nullptr}); - (void)f({new A, new B}, {new A, nullptr}); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:14: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - - (void)(f((f(new A) || f(0)) + f(new B[L]))); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:17: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - } - catch (std::bad_alloc) {} -} - -void test_cast() { - try { - f1(static_cast(new A), new B); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:28: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - } - catch (std::bad_alloc &) {} -} - -void test_nothrow(void *P) { - try { - (void)f(new(std::nothrow) A, new B); - (void)f(new A, new(std::nothrow) B); - (void)f(new(static_cast(8), std::nothrow) A, new B); - (void)f(new(P) A, new B); - (void)f(new('a') A, new B); - // CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; - } - catch (std::exception) {} -}