[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