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 'allocIntArray'</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling 'allocIntArray'</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 'test'</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from 'test'</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