[clang] 023c4d4 - [analyzer][AnalysisOrderChecker] Display the CallEvent type in preCall/postCall
Kirstóf Umann via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 9 07:41:22 PDT 2020
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 at ../Inputs/system-header-simulator-cxx.h:698 {{Called C++ object pointer is null}}
+ // expected-warning at ../Inputs/system-header-simulator-cxx.h:699 {{Called C++ object pointer is null}}
#endif
}
More information about the cfe-commits
mailing list