Hi rsmith, rtrieu, jordan_rose,

Frontend doesn't detect mismatching uses of 'new' and 'delete'. Analyzer 
catches this case.

Emit warning, and recover, when:
  int *p = new int[1];
  delete p; // treat as 'delete[]'
  int *l = new int(1);
  delete[] l; // treat as 'delete'

http://reviews.llvm.org/D4661

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaExprCXX.cpp
  test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
  test/Analysis/MismatchedDeallocator-checker-test.mm
  test/Analysis/MismatchedDeallocator-path-notes.cpp
  test/CodeGenCXX/new.cpp
  test/SemaCXX/delete.cpp
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -5224,7 +5224,12 @@
   "conversion function">;
 def note_delete_conversion : Note<"conversion to pointer type %0">;
 def warn_delete_array_type : Warning<
-  "'delete' applied to a pointer-to-array type %0 treated as delete[]">;
+  "'delete' applied to a pointer-to-array type %0 treated as 'delete[]'">;
+def warn_mismatched_delete_new : Warning<
+  "'delete%select{|[]}0' applied to a pointer that was allocated with "
+  "'new%select{[]|}0' treated as 'delete%select{[]|}0'">,
+  InGroup<DiagGroup<"mismatch-new-delete">>;
+def note_allocated_here : Note<"allocated with 'new%select{[]|}0' here">;
 def err_no_suitable_delete_member_function_found : Error<
   "no suitable member %0 in %1">;
 def err_ambiguous_suitable_delete_member_function_found : Error<
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -8397,6 +8397,8 @@
   /// \brief Check if the given expression contains 'break' or 'continue'
   /// statement that produces control flow different from GCC.
   void CheckBreakContinueBinding(Expr *E);
+  bool DiagnoseMismatchingDeleteArrayForm(QualType Pointee, bool ArrayForm,
+                                          Expr *E, SourceLocation &NewLoc);
 
 public:
   /// \brief Register a magic integral constant to be used as a type tag.
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -2236,6 +2236,39 @@
   return false;
 }
 
+bool Sema::DiagnoseMismatchingDeleteArrayForm(QualType Pointee, bool ArrayForm,
+                                              Expr *E, SourceLocation &NewLoc) {
+  if (Diags.isIgnored(diag::warn_mismatched_delete_new, SourceLocation()))
+    return false;
+
+  const CXXNewExpr *NE = nullptr;
+  if (const MemberExpr *ME = dyn_cast<const MemberExpr>(E)) {
+    if (const FieldDecl *FD = dyn_cast<const FieldDecl>(ME->getMemberDecl())) {
+      const CXXRecordDecl *RD = cast<const CXXRecordDecl>(FD->getParent());
+      for (const auto *CD : RD->ctors()) {
+        if (NE)
+          break;
+        for (const auto *CI : CD->inits()) {
+          if (FD == CI->getMember()) {
+            NE = dyn_cast<const CXXNewExpr>(CI->getInit());
+            break;
+          }
+        }
+      }
+      // No ctor-initializer initializes this field, check in-class initializer
+      if (!NE && FD->hasInClassInitializer())
+        NE = dyn_cast<const CXXNewExpr>(FD->getInClassInitializer());
+    }
+  } else if (const DeclRefExpr *D = dyn_cast<const DeclRefExpr>(E)) {
+    if (const VarDecl *VD = dyn_cast<const VarDecl>(D->getDecl()))
+      NE = dyn_cast_or_null<const CXXNewExpr>(VD->getInit());
+  }
+  if (NE && (NE->isArray() ^ ArrayForm)) {
+    NewLoc = NE->getLocStart();
+    return true;
+  }
+  return false;
+}
 /// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in:
 /// @code ::delete ptr; @endcode
 /// or
@@ -2351,18 +2384,26 @@
       }
     }
 
-    // C++ [expr.delete]p2:
-    //   [Note: a pointer to a const type can be the operand of a
-    //   delete-expression; it is not necessary to cast away the constness
-    //   (5.2.11) of the pointer expression before it is used as the operand
-    //   of the delete-expression. ]
-
     if (Pointee->isArrayType() && !ArrayForm) {
       Diag(StartLoc, diag::warn_delete_array_type)
           << Type << Ex.get()->getSourceRange()
           << FixItHint::CreateInsertion(PP.getLocForEndOfToken(StartLoc), "[]");
       ArrayForm = true;
     }
+    SourceLocation NewLoc;
+    if (DiagnoseMismatchingDeleteArrayForm(
+            Pointee, ArrayForm, Ex.get()->IgnoreImpCasts(), NewLoc)) {
+      PartialDiagnostic PD = PDiag(diag::warn_mismatched_delete_new)
+                             << ArrayForm << Ex.get()->getSourceRange();
+      if (!ArrayForm)
+        PD << FixItHint::CreateInsertion(PP.getLocForEndOfToken(StartLoc),
+                                         "[]");
+      // FIXME: Find a way to suggest fix-it for removal of '[]' without storing
+      // locations of [ and ].
+      Diag(StartLoc, PD);
+      Diag(NewLoc, diag::note_allocated_here) << ArrayForm;
+      ArrayForm = !ArrayForm;
+    }
 
     DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName(
                                       ArrayForm ? OO_Array_Delete : OO_Delete);
Index: test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
===================================================================
--- test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
+++ test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
@@ -97,9 +97,11 @@
   free(p);
   delete globalPtr; // expected-warning {{Attempt to free released memory}}
 }
-
+int *allocIntArray(unsigned c) {
+  return new int[c];
+}
 void testMismatchedChangePointeeThroughAssignment() {
-  int *arr = new int[4];
+  int *arr = allocIntArray(4);
   globalPtr = arr;
   delete arr; // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}}
-}
\ No newline at end of file
+}
Index: test/Analysis/MismatchedDeallocator-checker-test.mm
===================================================================
--- test/Analysis/MismatchedDeallocator-checker-test.mm
+++ test/Analysis/MismatchedDeallocator-checker-test.mm
@@ -90,18 +90,25 @@
   realloc(p, sizeof(long)); // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not realloc()}}
 }
 
+int *allocInt() {
+  return new int;
+}
 void testNew7() {
-  int *p = new int;
+  int *p = allocInt();
   delete[] p; // expected-warning{{Memory allocated by 'new' should be deallocated by 'delete', not 'delete[]'}}
 }
 
 void testNew8() {
   int *p = (int *)operator new(0);
   delete[] p; // expected-warning{{Memory allocated by operator new should be deallocated by 'delete', not 'delete[]'}}
 }
 
+int *allocIntArray(unsigned c) {
+  return new int[c];
+}
+
 void testNew9() {
-  int *p = new int[1];
+  int *p = allocIntArray(1);
   delete p; // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}}
 }
 
Index: test/Analysis/MismatchedDeallocator-path-notes.cpp
===================================================================
--- test/Analysis/MismatchedDeallocator-path-notes.cpp
+++ test/Analysis/MismatchedDeallocator-path-notes.cpp
@@ -3,9 +3,12 @@
 // RUN: FileCheck --input-file=%t.plist %s
 
 void changePointee(int *p);
+int *allocIntArray(unsigned c) {
+  return new int[c]; // expected-note {{Memory is allocated}}
+}
 void test() {
-  int *p = new int[1];
-  // expected-note@-1 {{Memory is allocated}}
+  int *p = allocIntArray(1); // expected-note {{Calling 'allocIntArray'}}
+  // expected-note@-1 {{Returned allocated memory}}
   changePointee(p);
   delete p; // expected-warning {{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}}
   // expected-note@-1 {{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}}
@@ -24,26 +27,137 @@
 // CHECK-NEXT:        <key>start</key>
 // CHECK-NEXT:         <array>
 // CHECK-NEXT:          <dict>
-// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>line</key><integer>10</integer>
 // CHECK-NEXT:           <key>col</key><integer>3</integer>
 // CHECK-NEXT:           <key>file</key><integer>0</integer>
 // CHECK-NEXT:          </dict>
 // CHECK-NEXT:          <dict>
-// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>line</key><integer>10</integer>
 // CHECK-NEXT:           <key>col</key><integer>5</integer>
 // CHECK-NEXT:           <key>file</key><integer>0</integer>
 // CHECK-NEXT:          </dict>
 // CHECK-NEXT:         </array>
 // CHECK-NEXT:        <key>end</key>
 // CHECK-NEXT:         <array>
 // CHECK-NEXT:          <dict>
-// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>line</key><integer>10</integer>
 // CHECK-NEXT:           <key>col</key><integer>12</integer>
 // CHECK-NEXT:           <key>file</key><integer>0</integer>
 // CHECK-NEXT:          </dict>
 // CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>10</integer>
+// CHECK-NEXT:           <key>col</key><integer>24</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:       </dict>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>event</string>
+// CHECK-NEXT:     <key>location</key>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>line</key><integer>10</integer>
+// CHECK-NEXT:      <key>col</key><integer>12</integer>
+// CHECK-NEXT:      <key>file</key><integer>0</integer>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <key>ranges</key>
+// CHECK-NEXT:     <array>
+// CHECK-NEXT:       <array>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>line</key><integer>10</integer>
+// CHECK-NEXT:         <key>col</key><integer>12</integer>
+// CHECK-NEXT:         <key>file</key><integer>0</integer>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>line</key><integer>10</integer>
+// CHECK-NEXT:         <key>col</key><integer>27</integer>
+// CHECK-NEXT:         <key>file</key><integer>0</integer>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:       </array>
+// CHECK-NEXT:     </array>
+// CHECK-NEXT:     <key>depth</key><integer>0</integer>
+// CHECK-NEXT:     <key>extended_message</key>
+// CHECK-NEXT:     <string>Calling &apos;allocIntArray&apos;</string>
+// CHECK-NEXT:     <key>message</key>
+// CHECK-NEXT:     <string>Calling &apos;allocIntArray&apos;</string>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>event</string>
+// CHECK-NEXT:     <key>location</key>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>line</key><integer>6</integer>
+// CHECK-NEXT:      <key>col</key><integer>1</integer>
+// CHECK-NEXT:      <key>file</key><integer>0</integer>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <key>depth</key><integer>1</integer>
+// CHECK-NEXT:     <key>extended_message</key>
+// CHECK-NEXT:     <string>Entered call from &apos;test&apos;</string>
+// CHECK-NEXT:     <key>message</key>
+// CHECK-NEXT:     <string>Entered call from &apos;test&apos;</string>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>control</string>
+// CHECK-NEXT:     <key>edges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:       <dict>
+// CHECK-NEXT:        <key>start</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>6</integer>
+// CHECK-NEXT:           <key>col</key><integer>1</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>6</integer>
+// CHECK-NEXT:           <key>col</key><integer>3</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:        <key>end</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>col</key><integer>3</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
 // CHECK-NEXT:           <key>line</key><integer>7</integer>
-// CHECK-NEXT:           <key>col</key><integer>14</integer>
+// CHECK-NEXT:           <key>col</key><integer>8</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:       </dict>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>control</string>
+// CHECK-NEXT:     <key>edges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:       <dict>
+// CHECK-NEXT:        <key>start</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>col</key><integer>3</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>col</key><integer>8</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:        <key>end</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>col</key><integer>10</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>col</key><integer>12</integer>
 // CHECK-NEXT:           <key>file</key><integer>0</integer>
 // CHECK-NEXT:          </dict>
 // CHECK-NEXT:         </array>
@@ -55,29 +169,58 @@
 // CHECK-NEXT:     <key>location</key>
 // CHECK-NEXT:     <dict>
 // CHECK-NEXT:      <key>line</key><integer>7</integer>
+// CHECK-NEXT:      <key>col</key><integer>10</integer>
+// CHECK-NEXT:      <key>file</key><integer>0</integer>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <key>ranges</key>
+// CHECK-NEXT:     <array>
+// CHECK-NEXT:       <array>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>line</key><integer>7</integer>
+// CHECK-NEXT:         <key>col</key><integer>10</integer>
+// CHECK-NEXT:         <key>file</key><integer>0</integer>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>line</key><integer>7</integer>
+// CHECK-NEXT:         <key>col</key><integer>19</integer>
+// CHECK-NEXT:         <key>file</key><integer>0</integer>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:       </array>
+// CHECK-NEXT:     </array>
+// CHECK-NEXT:     <key>depth</key><integer>1</integer>
+// CHECK-NEXT:     <key>extended_message</key>
+// CHECK-NEXT:     <string>Memory is allocated</string>
+// CHECK-NEXT:     <key>message</key>
+// CHECK-NEXT:     <string>Memory is allocated</string>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>event</string>
+// CHECK-NEXT:     <key>location</key>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>line</key><integer>10</integer>
 // CHECK-NEXT:      <key>col</key><integer>12</integer>
 // CHECK-NEXT:      <key>file</key><integer>0</integer>
 // CHECK-NEXT:     </dict>
 // CHECK-NEXT:     <key>ranges</key>
 // CHECK-NEXT:     <array>
 // CHECK-NEXT:       <array>
 // CHECK-NEXT:        <dict>
-// CHECK-NEXT:         <key>line</key><integer>7</integer>
+// CHECK-NEXT:         <key>line</key><integer>10</integer>
 // CHECK-NEXT:         <key>col</key><integer>12</integer>
 // CHECK-NEXT:         <key>file</key><integer>0</integer>
 // CHECK-NEXT:        </dict>
 // CHECK-NEXT:        <dict>
-// CHECK-NEXT:         <key>line</key><integer>7</integer>
-// CHECK-NEXT:         <key>col</key><integer>21</integer>
+// CHECK-NEXT:         <key>line</key><integer>10</integer>
+// CHECK-NEXT:         <key>col</key><integer>27</integer>
 // CHECK-NEXT:         <key>file</key><integer>0</integer>
 // CHECK-NEXT:        </dict>
 // CHECK-NEXT:       </array>
 // CHECK-NEXT:     </array>
 // CHECK-NEXT:     <key>depth</key><integer>0</integer>
 // CHECK-NEXT:     <key>extended_message</key>
-// CHECK-NEXT:     <string>Memory is allocated</string>
+// CHECK-NEXT:     <string>Returned allocated memory</string>
 // CHECK-NEXT:     <key>message</key>
-// CHECK-NEXT:     <string>Memory is allocated</string>
+// CHECK-NEXT:     <string>Returned allocated memory</string>
 // CHECK-NEXT:    </dict>
 // CHECK-NEXT:    <dict>
 // CHECK-NEXT:     <key>kind</key><string>control</string>
@@ -87,25 +230,25 @@
 // CHECK-NEXT:        <key>start</key>
 // CHECK-NEXT:         <array>
 // CHECK-NEXT:          <dict>
-// CHECK-NEXT:           <key>line</key><integer>7</integer>
+// CHECK-NEXT:           <key>line</key><integer>10</integer>
 // CHECK-NEXT:           <key>col</key><integer>12</integer>
 // CHECK-NEXT:           <key>file</key><integer>0</integer>
 // CHECK-NEXT:          </dict>
 // CHECK-NEXT:          <dict>
-// CHECK-NEXT:           <key>line</key><integer>7</integer>
-// CHECK-NEXT:           <key>col</key><integer>14</integer>
+// CHECK-NEXT:           <key>line</key><integer>10</integer>
+// CHECK-NEXT:           <key>col</key><integer>24</integer>
 // CHECK-NEXT:           <key>file</key><integer>0</integer>
 // CHECK-NEXT:          </dict>
 // CHECK-NEXT:         </array>
 // CHECK-NEXT:        <key>end</key>
 // CHECK-NEXT:         <array>
 // CHECK-NEXT:          <dict>
-// CHECK-NEXT:           <key>line</key><integer>10</integer>
+// CHECK-NEXT:           <key>line</key><integer>13</integer>
 // CHECK-NEXT:           <key>col</key><integer>3</integer>
 // CHECK-NEXT:           <key>file</key><integer>0</integer>
 // CHECK-NEXT:          </dict>
 // CHECK-NEXT:          <dict>
-// CHECK-NEXT:           <key>line</key><integer>10</integer>
+// CHECK-NEXT:           <key>line</key><integer>13</integer>
 // CHECK-NEXT:           <key>col</key><integer>8</integer>
 // CHECK-NEXT:           <key>file</key><integer>0</integer>
 // CHECK-NEXT:          </dict>
@@ -117,20 +260,20 @@
 // CHECK-NEXT:     <key>kind</key><string>event</string>
 // CHECK-NEXT:     <key>location</key>
 // CHECK-NEXT:     <dict>
-// CHECK-NEXT:      <key>line</key><integer>10</integer>
+// CHECK-NEXT:      <key>line</key><integer>13</integer>
 // CHECK-NEXT:      <key>col</key><integer>3</integer>
 // CHECK-NEXT:      <key>file</key><integer>0</integer>
 // CHECK-NEXT:     </dict>
 // CHECK-NEXT:     <key>ranges</key>
 // CHECK-NEXT:     <array>
 // CHECK-NEXT:       <array>
 // CHECK-NEXT:        <dict>
-// CHECK-NEXT:         <key>line</key><integer>10</integer>
+// CHECK-NEXT:         <key>line</key><integer>13</integer>
 // CHECK-NEXT:         <key>col</key><integer>10</integer>
 // CHECK-NEXT:         <key>file</key><integer>0</integer>
 // CHECK-NEXT:        </dict>
 // CHECK-NEXT:        <dict>
-// CHECK-NEXT:         <key>line</key><integer>10</integer>
+// CHECK-NEXT:         <key>line</key><integer>13</integer>
 // CHECK-NEXT:         <key>col</key><integer>10</integer>
 // CHECK-NEXT:         <key>file</key><integer>0</integer>
 // CHECK-NEXT:        </dict>
@@ -151,7 +294,7 @@
 // CHECK-NEXT:  <key>issue_hash</key><string>4</string>
 // CHECK-NEXT:  <key>location</key>
 // CHECK-NEXT:  <dict>
-// CHECK-NEXT:   <key>line</key><integer>10</integer>
+// CHECK-NEXT:   <key>line</key><integer>13</integer>
 // CHECK-NEXT:   <key>col</key><integer>3</integer>
 // CHECK-NEXT:   <key>file</key><integer>0</integer>
 // CHECK-NEXT:  </dict>
Index: test/CodeGenCXX/new.cpp
===================================================================
--- test/CodeGenCXX/new.cpp
+++ test/CodeGenCXX/new.cpp
@@ -290,14 +290,14 @@
   // CHECK-LABEL: define void @_ZN5N36641fEv
   void f() {
     // CHECK: call noalias i8* @_Znwm(i64 4) [[ATTR_BUILTIN_NEW:#[^ ]*]]
-    int *p = new int;
+    int *p = new int; // expected-note {{allocated with 'new' here}}
     // CHECK: call void @_ZdlPv({{.*}}) [[ATTR_BUILTIN_DELETE:#[^ ]*]]
     delete p;
 
     // CHECK: call noalias i8* @_Znam(i64 12) [[ATTR_BUILTIN_NEW]]
     int *q = new int[3];
-    // CHECK: call void @_ZdaPv({{.*}}) [[ATTR_BUILTIN_DELETE]]
-    delete [] p;
+    // CHECK: call void @_ZdlPv({{.*}}) [[ATTR_BUILTIN_DELETE]]
+    delete[] p; // expected-warning {{'delete[]' applied to a pointer that was allocated with 'new' treated as 'delete'}}
 
     // CHECK: call i8* @_ZnamRKSt9nothrow_t(i64 3, {{.*}}) [[ATTR_BUILTIN_NOTHROW_NEW:#[^ ]*]]
     (void) new (nothrow) S[3];
Index: test/SemaCXX/delete.cpp
===================================================================
--- test/SemaCXX/delete.cpp
+++ test/SemaCXX/delete.cpp
@@ -1,9 +1,52 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
 // RUN: cp %s %t
-// RUN: %clang_cc1 -fixit -x c++ %t
+// RUN: %clang_cc1 -fixit -x c++ -std=c++11 %t
 // RUN: %clang_cc1 -E -o - %t | FileCheck %s
 
 void f(int a[10][20]) {
   // CHECK: delete[] a;
   delete a; // expected-warning {{'delete' applied to a pointer-to-array type}}
 }
+namespace MemberCheck {
+struct S {
+  int *a = new int[5]; // expected-note {{allocated with 'new[]' here}}
+  // expected-note@-1 {{allocated with 'new[]' here}}
+  // expected-note@-2 {{allocated with 'new[]' here}}
+  int *b;
+  int *c;
+  static int *d;
+  S() : b(new int[5]), c(new int) {} // expected-note {{allocated with 'new[]' here}}
+  // expected-note@-1 {{allocated with 'new[]' here}}
+  // expected-note@-2 {{allocated with 'new' here}}
+  ~S() {
+    // CHECK: delete[] a;
+    delete a; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]' treated as 'delete[]'}}
+    // CHECK: delete[] b;
+    delete b; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]' treated as 'delete[]'}}
+    delete [] c; // expected-warning {{'delete[]' applied to a pointer that was allocated with 'new' treated as 'delete'}}
+  }
+};
+struct S2 : S {
+  ~S2() {
+    delete a; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]' treated as 'delete[]'}}
+  }
+};
+int *S::d = new int[42]; // expected-note {{allocated with 'new[]' here}}
+void f(S *s) {
+  int *a = new int[1]; // expected-note {{allocated with 'new[]' here}}
+  //CHECK: delete[] a;
+  delete a; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]' treated as 'delete[]'}}
+  // CHECK: delete[] s->a;
+  delete s->a; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]' treated as 'delete[]'}}
+  delete s->b; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]' treated as 'delete[]'}}
+  delete s->c;
+  delete s->d;
+  delete S::d; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]' treated as 'delete[]'}}
+}
+void f2() {
+  int *a = new int(5); // expected-note {{allocated with 'new' here}}
+  delete[] a;          // expected-warning {{'delete[]' applied to a pointer that was allocated with 'new' treated as 'delete'}}
+  int *b = new int;
+  delete b;
+}
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to