Author: Kirstóf Umann Date: 2020-04-09T16:41:07+02:00 New Revision: 023c4d400ef5acf3a7339dc8452ce552b15a9ae4
URL: https://github.com/llvm/llvm-project/commit/023c4d400ef5acf3a7339dc8452ce552b15a9ae4 DIFF: https://github.com/llvm/llvm-project/commit/023c4d400ef5acf3a7339dc8452ce552b15a9ae4.diff LOG: [analyzer][AnalysisOrderChecker] Display the CallEvent type in preCall/postCall Exactly what it says on the tin! The included testfile demonstrates why this is important -- for C++ dynamic memory operators, we don't always recognize custom, or even standard-specified new/delete operators as CXXAllocatorCall or CXXDeallocatorCall. Differential Revision: https://reviews.llvm.org/D77391 Added: clang/test/Analysis/cxx-dynamic-memory-analysis-order.cpp Modified: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp clang/lib/StaticAnalyzer/Core/CallEvent.cpp clang/test/Analysis/Inputs/system-header-simulator-cxx.h clang/test/Analysis/analyzer-config.c clang/test/Analysis/diagnostics/explicit-suppression.cpp Removed: ################################################################################ diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 31e7e02c192b..4315b0984abc 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -1275,6 +1275,30 @@ def AnalysisOrderChecker : Checker<"AnalysisOrder">, "false", Released, Hide>, + CmdLineOption<Boolean, + "PreStmtCXXDeleteExpr", + "", + "false", + Released, + Hide>, + CmdLineOption<Boolean, + "PostStmtCXXDeleteExpr", + "", + "false", + Released, + Hide>, + CmdLineOption<Boolean, + "PreStmtCXXConstructExpr", + "", + "false", + Released, + Hide>, + CmdLineOption<Boolean, + "PostStmtCXXConstructExpr", + "", + "false", + Released, + Hide>, CmdLineOption<Boolean, "PreStmtOffsetOfExpr", "", @@ -1305,6 +1329,12 @@ def AnalysisOrderChecker : Checker<"AnalysisOrder">, "false", Released, Hide>, + CmdLineOption<Boolean, + "EndAnalysis", + "", + "false", + Released, + Hide>, CmdLineOption<Boolean, "NewAllocator", "", diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index 402acf667d53..8b4be2784f38 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -199,6 +199,7 @@ class CallEvent { /// Returns the kind of call this is. virtual Kind getKind() const = 0; + virtual StringRef getKindAsString() const = 0; /// Returns the declaration of the function or method that will be /// called. May be null. @@ -530,6 +531,9 @@ class SimpleFunctionCall : public AnyFunctionCall { } Kind getKind() const override { return CE_Function; } + virtual StringRef getKindAsString() const override { + return "SimpleFunctionCall"; + } static bool classof(const CallEvent *CA) { return CA->getKind() == CE_Function; @@ -634,13 +638,12 @@ class BlockCall : public CallEvent { void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, BindingsTy &Bindings) const override; - ArrayRef<ParmVarDecl*> parameters() const override; + ArrayRef<ParmVarDecl *> parameters() const override; Kind getKind() const override { return CE_Block; } + virtual StringRef getKindAsString() const override { return "BlockCall"; } - static bool classof(const CallEvent *CA) { - return CA->getKind() == CE_Block; - } + static bool classof(const CallEvent *CA) { return CA->getKind() == CE_Block; } }; /// Represents a non-static C++ member function call, no matter how @@ -712,6 +715,7 @@ class CXXMemberCall : public CXXInstanceCall { RuntimeDefinition getRuntimeDefinition() const override; Kind getKind() const override { return CE_CXXMember; } + virtual StringRef getKindAsString() const override { return "CXXMemberCall"; } static bool classof(const CallEvent *CA) { return CA->getKind() == CE_CXXMember; @@ -751,6 +755,9 @@ class CXXMemberOperatorCall : public CXXInstanceCall { const Expr *getCXXThisExpr() const override; Kind getKind() const override { return CE_CXXMemberOperator; } + virtual StringRef getKindAsString() const override { + return "CXXMemberOperatorCall"; + } static bool classof(const CallEvent *CA) { return CA->getKind() == CE_CXXMemberOperator; @@ -815,6 +822,9 @@ class CXXDestructorCall : public CXXInstanceCall { } Kind getKind() const override { return CE_CXXDestructor; } + virtual StringRef getKindAsString() const override { + return "CXXDestructorCall"; + } static bool classof(const CallEvent *CA) { return CA->getKind() == CE_CXXDestructor; @@ -887,6 +897,9 @@ class CXXConstructorCall : public AnyCXXConstructorCall { } Kind getKind() const override { return CE_CXXConstructor; } + virtual StringRef getKindAsString() const override { + return "CXXConstructorCall"; + } static bool classof(const CallEvent *CA) { return CA->getKind() == CE_CXXConstructor; @@ -964,6 +977,9 @@ class CXXInheritedConstructorCall : public AnyCXXConstructorCall { } Kind getKind() const override { return CE_CXXInheritedConstructor; } + virtual StringRef getKindAsString() const override { + return "CXXInheritedConstructorCall"; + } static bool classof(const CallEvent *CA) { return CA->getKind() == CE_CXXInheritedConstructor; @@ -1020,6 +1036,9 @@ class CXXAllocatorCall : public AnyFunctionCall { } Kind getKind() const override { return CE_CXXAllocator; } + virtual StringRef getKindAsString() const override { + return "CXXAllocatorCall"; + } static bool classof(const CallEvent *CE) { return CE->getKind() == CE_CXXAllocator; @@ -1143,6 +1162,9 @@ class ObjCMethodCall : public CallEvent { ArrayRef<ParmVarDecl*> parameters() const override; Kind getKind() const override { return CE_ObjCMessage; } + virtual StringRef getKindAsString() const override { + return "ObjCMethodCall"; + } static bool classof(const CallEvent *CA) { return CA->getKind() == CE_ObjCMessage; diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp index fb1a407dbdf7..f44a40d8bd15 100644 --- a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp @@ -13,13 +13,14 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/AST/ExprCXX.h" #include "clang/Analysis/CFGStmtMap.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace ento; @@ -27,24 +28,20 @@ using namespace ento; namespace { class AnalysisOrderChecker - : public Checker<check::PreStmt<CastExpr>, - check::PostStmt<CastExpr>, - check::PreStmt<ArraySubscriptExpr>, - check::PostStmt<ArraySubscriptExpr>, - check::PreStmt<CXXNewExpr>, - check::PostStmt<CXXNewExpr>, - check::PreStmt<OffsetOfExpr>, - check::PostStmt<OffsetOfExpr>, - check::PreCall, - check::PostCall, - check::EndFunction, - check::NewAllocator, - check::Bind, - check::PointerEscape, - check::RegionChanges, - check::LiveSymbols> { - - bool isCallbackEnabled(AnalyzerOptions &Opts, StringRef CallbackName) const { + : public Checker< + check::PreStmt<CastExpr>, check::PostStmt<CastExpr>, + check::PreStmt<ArraySubscriptExpr>, + check::PostStmt<ArraySubscriptExpr>, check::PreStmt<CXXNewExpr>, + check::PostStmt<CXXNewExpr>, check::PreStmt<CXXDeleteExpr>, + check::PostStmt<CXXDeleteExpr>, check::PreStmt<CXXConstructExpr>, + check::PostStmt<CXXConstructExpr>, check::PreStmt<OffsetOfExpr>, + check::PostStmt<OffsetOfExpr>, check::PreCall, check::PostCall, + check::EndFunction, check::EndAnalysis, check::NewAllocator, + check::Bind, check::PointerEscape, check::RegionChanges, + check::LiveSymbols> { + + bool isCallbackEnabled(const AnalyzerOptions &Opts, + StringRef CallbackName) const { return Opts.getCheckerBooleanOption(this, "*") || Opts.getCheckerBooleanOption(this, CallbackName); } @@ -95,6 +92,26 @@ class AnalysisOrderChecker llvm::errs() << "PostStmt<CXXNewExpr>\n"; } + void checkPreStmt(const CXXDeleteExpr *NE, CheckerContext &C) const { + if (isCallbackEnabled(C, "PreStmtCXXDeleteExpr")) + llvm::errs() << "PreStmt<CXXDeleteExpr>\n"; + } + + void checkPostStmt(const CXXDeleteExpr *NE, CheckerContext &C) const { + if (isCallbackEnabled(C, "PostStmtCXXDeleteExpr")) + llvm::errs() << "PostStmt<CXXDeleteExpr>\n"; + } + + void checkPreStmt(const CXXConstructExpr *NE, CheckerContext &C) const { + if (isCallbackEnabled(C, "PreStmtCXXConstructExpr")) + llvm::errs() << "PreStmt<CXXConstructExpr>\n"; + } + + void checkPostStmt(const CXXConstructExpr *NE, CheckerContext &C) const { + if (isCallbackEnabled(C, "PostStmtCXXConstructExpr")) + llvm::errs() << "PostStmt<CXXConstructExpr>\n"; + } + void checkPreStmt(const OffsetOfExpr *OOE, CheckerContext &C) const { if (isCallbackEnabled(C, "PreStmtOffsetOfExpr")) llvm::errs() << "PreStmt<OffsetOfExpr>\n"; @@ -110,6 +127,7 @@ class AnalysisOrderChecker llvm::errs() << "PreCall"; if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')'; + llvm::errs() << " [" << Call.getKindAsString() << ']'; llvm::errs() << '\n'; } } @@ -119,6 +137,7 @@ class AnalysisOrderChecker llvm::errs() << "PostCall"; if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')'; + llvm::errs() << " [" << Call.getKindAsString() << ']'; llvm::errs() << '\n'; } } @@ -140,6 +159,12 @@ class AnalysisOrderChecker } } + void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR, + ExprEngine &Eng) const { + if (isCallbackEnabled(BR.getAnalyzerOptions(), "EndAnalysis")) + llvm::errs() << "EndAnalysis\n"; + } + void checkNewAllocator(const CXXNewExpr *CNE, SVal Target, CheckerContext &C) const { if (isCallbackEnabled(C, "NewAllocator")) diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 4fc23d8ac941..ea366d0994b5 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -450,8 +450,7 @@ void CallEvent::dump(raw_ostream &Out) const { return; } - // FIXME: a string representation of the kind would be nice. - Out << "Unknown call (type " << getKind() << ")"; + Out << "Unknown call (type " << getKindAsString() << ")"; } bool CallEvent::isCallStmt(const Stmt *S) { diff --git a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h index 25a705bb9358..4729b0439ad0 100644 --- a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h +++ b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h @@ -608,9 +608,10 @@ namespace std { }; struct nothrow_t {}; - extern const nothrow_t nothrow; + enum class align_val_t : size_t {}; + // libc++'s implementation template <class _E> class initializer_list @@ -967,10 +968,33 @@ void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return s void operator delete(void* ptr, const std::nothrow_t&) throw() { std::free(ptr); } void operator delete[](void* ptr, const std::nothrow_t&) throw() { std::free(ptr); } #else -void* operator new(std::size_t, const std::nothrow_t&) throw(); -void* operator new[](std::size_t, const std::nothrow_t&) throw(); -void operator delete(void*, const std::nothrow_t&) throw(); -void operator delete[](void*, const std::nothrow_t&) throw(); +// C++20 standard draft 17.6.1, from "Header <new> synopsis", but with throw() +// instead of noexcept: + +void *operator new(std::size_t size); +void *operator new(std::size_t size, std::align_val_t alignment); +void *operator new(std::size_t size, const std::nothrow_t &) throw(); +void *operator new(std::size_t size, std::align_val_t alignment, + const std::nothrow_t &) throw(); +void operator delete(void *ptr) throw(); +void operator delete(void *ptr, std::size_t size) throw(); +void operator delete(void *ptr, std::align_val_t alignment) throw(); +void operator delete(void *ptr, std::size_t size, std::align_val_t alignment) throw(); +void operator delete(void *ptr, const std::nothrow_t &)throw(); +void operator delete(void *ptr, std::align_val_t alignment, + const std::nothrow_t &)throw(); +void *operator new[](std::size_t size); +void *operator new[](std::size_t size, std::align_val_t alignment); +void *operator new[](std::size_t size, const std::nothrow_t &) throw(); +void *operator new[](std::size_t size, std::align_val_t alignment, + const std::nothrow_t &) throw(); +void operator delete[](void *ptr) throw(); +void operator delete[](void *ptr, std::size_t size) throw(); +void operator delete[](void *ptr, std::align_val_t alignment) throw(); +void operator delete[](void *ptr, std::size_t size, std::align_val_t alignment) throw(); +void operator delete[](void *ptr, const std::nothrow_t &) throw(); +void operator delete[](void *ptr, std::align_val_t alignment, + const std::nothrow_t &) throw(); #endif void* operator new (std::size_t size, void* ptr) throw() { return ptr; }; diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c index 7069ee4a938d..226c02012c59 100644 --- a/clang/test/Analysis/analyzer-config.c +++ b/clang/test/Analysis/analyzer-config.c @@ -37,17 +37,22 @@ // CHECK-NEXT: deadcode.DeadStores:WarnForDeadNestedAssignments = true // CHECK-NEXT: debug.AnalysisOrder:* = false // CHECK-NEXT: debug.AnalysisOrder:Bind = false +// CHECK-NEXT: debug.AnalysisOrder:EndAnalysis = false // CHECK-NEXT: debug.AnalysisOrder:EndFunction = false // CHECK-NEXT: debug.AnalysisOrder:LiveSymbols = false // CHECK-NEXT: debug.AnalysisOrder:NewAllocator = false // CHECK-NEXT: debug.AnalysisOrder:PointerEscape = false // CHECK-NEXT: debug.AnalysisOrder:PostCall = false // CHECK-NEXT: debug.AnalysisOrder:PostStmtArraySubscriptExpr = false +// CHECK-NEXT: debug.AnalysisOrder:PostStmtCXXConstructExpr = false +// CHECK-NEXT: debug.AnalysisOrder:PostStmtCXXDeleteExpr = false // CHECK-NEXT: debug.AnalysisOrder:PostStmtCXXNewExpr = false // CHECK-NEXT: debug.AnalysisOrder:PostStmtCastExpr = false // CHECK-NEXT: debug.AnalysisOrder:PostStmtOffsetOfExpr = false // CHECK-NEXT: debug.AnalysisOrder:PreCall = false // CHECK-NEXT: debug.AnalysisOrder:PreStmtArraySubscriptExpr = false +// CHECK-NEXT: debug.AnalysisOrder:PreStmtCXXConstructExpr = false +// CHECK-NEXT: debug.AnalysisOrder:PreStmtCXXDeleteExpr = false // CHECK-NEXT: debug.AnalysisOrder:PreStmtCXXNewExpr = false // CHECK-NEXT: debug.AnalysisOrder:PreStmtCastExpr = false // CHECK-NEXT: debug.AnalysisOrder:PreStmtOffsetOfExpr = false @@ -101,4 +106,4 @@ // CHECK-NEXT: unroll-loops = false // CHECK-NEXT: widen-loops = false // CHECK-NEXT: [stats] -// CHECK-NEXT: num-entries = 98 +// CHECK-NEXT: num-entries = 103 diff --git a/clang/test/Analysis/cxx-dynamic-memory-analysis-order.cpp b/clang/test/Analysis/cxx-dynamic-memory-analysis-order.cpp new file mode 100644 index 000000000000..dfb3bbfe1bc0 --- /dev/null +++ b/clang/test/Analysis/cxx-dynamic-memory-analysis-order.cpp @@ -0,0 +1,130 @@ +// RUN: %clang_analyze_cc1 -std=c++20 -fblocks -verify %s \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-checker=debug.AnalysisOrder \ +// RUN: -analyzer-config debug.AnalysisOrder:PreStmtCXXNewExpr=true \ +// RUN: -analyzer-config debug.AnalysisOrder:PostStmtCXXNewExpr=true \ +// RUN: -analyzer-config debug.AnalysisOrder:PreStmtCXXDeleteExpr=true \ +// RUN: -analyzer-config debug.AnalysisOrder:PostStmtCXXDeleteExpr=true \ +// RUN: -analyzer-config debug.AnalysisOrder:PreCall=true \ +// RUN: -analyzer-config debug.AnalysisOrder:PostCall=true \ +// RUN: 2>&1 | FileCheck %s + +// expected-no-diagnostics + +#include "Inputs/system-header-simulator-cxx.h" + +void f() { + // C++20 standard draft 17.6.1.15: + // Required behavior: A call to an operator delete with a size parameter may + // be changed to a call to the corresponding operator delete without a size + // parameter, without affecting memory allocation. [ Note: A conforming + // implementation is for operator delete(void* ptr, size_t size) to simply + // call operator delete(ptr). — end note ] + // + // C++20 standard draft 17.6.1.24, about nothrow operator delete: + // void operator delete(void* ptr, const std::nothrow_t&) noexcept; + // void operator delete(void* ptr, std::align_val_t alignment, + // const std::nothrow_t&) noexcept; + // Default behavior: Calls operator delete(ptr), or operator delete(ptr, + // alignment), respectively. + + // FIXME: All calls to operator new should be CXXAllocatorCall. + // FIXME: PostStmt<CXXDeleteExpr> should be present. + { + int *p = new int; + delete p; + // CHECK: PreCall (operator new) [CXXAllocatorCall] + // CHECK-NEXT: PostCall (operator new) [CXXAllocatorCall] + // CHECK-NEXT: PreStmt<CXXNewExpr> + // CHECK-NEXT: PostStmt<CXXNewExpr> + // CHECK-NEXT: PreStmt<CXXDeleteExpr> + + p = new int; + operator delete(p, 23542368); + // CHECK-NEXT: PreCall (operator new) [CXXAllocatorCall] + // CHECK-NEXT: PostCall (operator new) [CXXAllocatorCall] + // CHECK-NEXT: PreStmt<CXXNewExpr> + // CHECK-NEXT: PostStmt<CXXNewExpr> + // CHECK-NEXT: PreCall (operator delete) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator delete) [SimpleFunctionCall] + + void *v = operator new(sizeof(int[2]), std::align_val_t(2)); + operator delete(v, std::align_val_t(2)); + // CHECK-NEXT: PreCall (operator new) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator new) [SimpleFunctionCall] + // CHECK-NEXT: PreCall (operator delete) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator delete) [SimpleFunctionCall] + + v = operator new(sizeof(int[2]), std::align_val_t(2)); + operator delete(v, 345345, std::align_val_t(2)); + // CHECK-NEXT: PreCall (operator new) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator new) [SimpleFunctionCall] + // CHECK-NEXT: PreCall (operator delete) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator delete) [SimpleFunctionCall] + + p = new (std::nothrow) int; + operator delete(p, std::nothrow); + // CHECK-NEXT: PreCall (operator new) [CXXAllocatorCall] + // CHECK-NEXT: PostCall (operator new) [CXXAllocatorCall] + // CHECK-NEXT: PreStmt<CXXNewExpr> + // CHECK-NEXT: PostStmt<CXXNewExpr> + // CHECK-NEXT: PreCall (operator delete) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator delete) [SimpleFunctionCall] + + v = operator new(sizeof(int[2]), std::align_val_t(2), std::nothrow); + operator delete(v, std::align_val_t(2), std::nothrow); + // CHECK-NEXT: PreCall (operator new) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator new) [SimpleFunctionCall] + // CHECK-NEXT: PreCall (operator delete) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator delete) [SimpleFunctionCall] + } + + { + int *p = new int[2]; + delete[] p; + // CHECK-NEXT: PreCall (operator new[]) [CXXAllocatorCall] + // CHECK-NEXT: PostCall (operator new[]) [CXXAllocatorCall] + // CHECK-NEXT: PreStmt<CXXNewExpr> + // CHECK-NEXT: PostStmt<CXXNewExpr> + // CHECK-NEXT: PreStmt<CXXDeleteExpr> + + p = new int[2]; + operator delete[](p, 23542368); + // CHECK-NEXT: PreCall (operator new[]) [CXXAllocatorCall] + // CHECK-NEXT: PostCall (operator new[]) [CXXAllocatorCall] + // CHECK-NEXT: PreStmt<CXXNewExpr> + // CHECK-NEXT: PostStmt<CXXNewExpr> + // CHECK-NEXT: PreCall (operator delete[]) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator delete[]) [SimpleFunctionCall] + + void *v = operator new[](sizeof(int[2]), std::align_val_t(2)); + operator delete[](v, std::align_val_t(2)); + // CHECK-NEXT: PreCall (operator new[]) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator new[]) [SimpleFunctionCall] + // CHECK-NEXT: PreCall (operator delete[]) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator delete[]) [SimpleFunctionCall] + + v = operator new[](sizeof(int[2]), std::align_val_t(2)); + operator delete[](v, 345345, std::align_val_t(2)); + // CHECK-NEXT: PreCall (operator new[]) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator new[]) [SimpleFunctionCall] + // CHECK-NEXT: PreCall (operator delete[]) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator delete[]) [SimpleFunctionCall] + + p = new (std::nothrow) int[2]; + operator delete[](p, std::nothrow); + // CHECK-NEXT: PreCall (operator new[]) [CXXAllocatorCall] + // CHECK-NEXT: PostCall (operator new[]) [CXXAllocatorCall] + // CHECK-NEXT: PreStmt<CXXNewExpr> + // CHECK-NEXT: PostStmt<CXXNewExpr> + // CHECK-NEXT: PreCall (operator delete[]) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator delete[]) [SimpleFunctionCall] + + v = operator new[](sizeof(int[2]), std::align_val_t(2), std::nothrow); + operator delete[](v, std::align_val_t(2), std::nothrow); + // CHECK-NEXT: PreCall (operator new[]) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator new[]) [SimpleFunctionCall] + // CHECK-NEXT: PreCall (operator delete[]) [SimpleFunctionCall] + // CHECK-NEXT: PostCall (operator delete[]) [SimpleFunctionCall] + } +} diff --git a/clang/test/Analysis/diagnostics/explicit-suppression.cpp b/clang/test/Analysis/diagnostics/explicit-suppression.cpp index f7db7a280545..2b586add19ee 100644 --- a/clang/test/Analysis/diagnostics/explicit-suppression.cpp +++ b/clang/test/Analysis/diagnostics/explicit-suppression.cpp @@ -19,6 +19,6 @@ class C { void testCopyNull(C *I, C *E) { std::copy(I, E, (C *)0); #ifndef SUPPRESSED - // expected-warning@../Inputs/system-header-simulator-cxx.h:698 {{Called C++ object pointer is null}} + // expected-warning@../Inputs/system-header-simulator-cxx.h:699 {{Called C++ object pointer is null}} #endif } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits