diff options
Diffstat (limited to 'test/Analysis')
-rw-r--r-- | test/Analysis/Checkers/RunLoopAutoreleaseLeakChecker.m | 22 | ||||
-rw-r--r-- | test/Analysis/casts.c | 7 | ||||
-rw-r--r-- | test/Analysis/cfg-rich-constructors.cpp | 75 | ||||
-rw-r--r-- | test/Analysis/cfg-rich-constructors.mm | 66 | ||||
-rw-r--r-- | test/Analysis/copy-elision.cpp (renamed from test/Analysis/cxx17-mandatory-elision.cpp) | 0 | ||||
-rw-r--r-- | test/Analysis/cstring-ranges.c | 15 | ||||
-rw-r--r-- | test/Analysis/inner-pointer.cpp | 94 | ||||
-rw-r--r-- | test/Analysis/lifetime-extension.mm | 64 | ||||
-rw-r--r-- | test/Analysis/temporaries.cpp | 49 | ||||
-rw-r--r-- | test/Analysis/temporaries.mm | 23 |
10 files changed, 391 insertions, 24 deletions
diff --git a/test/Analysis/Checkers/RunLoopAutoreleaseLeakChecker.m b/test/Analysis/Checkers/RunLoopAutoreleaseLeakChecker.m index 4dde40e210a07..b00d71b1a4d09 100644 --- a/test/Analysis/Checkers/RunLoopAutoreleaseLeakChecker.m +++ b/test/Analysis/Checkers/RunLoopAutoreleaseLeakChecker.m @@ -29,6 +29,17 @@ void runloop_init_before() { // Warning: object created before the loop. } } +void runloop_init_before_separate_pool() { // No warning: separate autorelease pool. + @autoreleasepool { + NSObject *object; + @autoreleasepool { + object = [[NSObject alloc] init]; // no-warning + } + (void) object; + [[NSRunLoop mainRunLoop] run]; + } +} + void xpcmain_init_before() { // Warning: object created before the loop. @autoreleasepool { NSObject *object = [[NSObject alloc] init]; // expected-warning{{Temporary objects allocated in the autorelease pool followed by the launch of xpc_main may never get released; consider moving them to a separate autorelease pool}} @@ -43,7 +54,7 @@ void runloop_init_before_two_objects() { // Warning: object created before the l NSObject *object2 = [[NSObject alloc] init]; // no-warning, warning on the first one is enough. (void) object; (void) object2; - [[NSRunLoop mainRunLoop] run]; + [[NSRunLoop mainRunLoop] run]; } } @@ -61,6 +72,15 @@ void runloop_init_after() { // No warning: objects created after the loop } } +void no_crash_on_empty_children() { + @autoreleasepool { + for (;;) {} + NSObject *object = [[NSObject alloc] init]; // expected-warning{{Temporary objects allocated in the autorelease pool followed by the launch of main run loop may never get released; consider moving them to a separate autorelease pool}} + [[NSRunLoop mainRunLoop] run]; + (void) object; + } +} + #endif #ifdef AP1 diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c index eccb67812a022..86fb7da58ec22 100644 --- a/test/Analysis/casts.c +++ b/test/Analysis/casts.c @@ -175,3 +175,10 @@ void testCastVoidPtrToIntPtrThroughUIntTypedAssignment() { void testLocNonLocSymbolAssume(int a, int *b) { if ((int)b < a) {} // no-crash } + +void testLocNonLocSymbolRemainder(int a, int *b) { + int c = ((int)b) % a; + if (a == 1) { + c += 1; + } +} diff --git a/test/Analysis/cfg-rich-constructors.cpp b/test/Analysis/cfg-rich-constructors.cpp index 6780cf1a7be9d..88b03788da439 100644 --- a/test/Analysis/cfg-rich-constructors.cpp +++ b/test/Analysis/cfg-rich-constructors.cpp @@ -817,25 +817,58 @@ public: ~D(); }; +class E { +public: + E(D d); +}; + void useC(C c); void useCByReference(const C &c); void useD(D d); void useDByReference(const D &d); +void useCAndD(C c, D d); -// FIXME: Find construction context for the argument. // CHECK: void passArgument() // CHECK: 1: useC // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(class C)) -// CXX11-NEXT: 3: C() (CXXConstructExpr, [B1.4], class C) +// CXX11-ELIDE-NEXT: 3: C() (CXXConstructExpr, [B1.4], [B1.5], class C) +// CXX11-NOELIDE-NEXT: 3: C() (CXXConstructExpr, [B1.4], class C) // CXX11-NEXT: 4: [B1.3] -// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, class C) +// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6]+0, class C) // CXX11-NEXT: 6: [B1.2]([B1.5]) -// CXX17-NEXT: 3: C() (CXXConstructExpr, class C) +// CXX17-NEXT: 3: C() (CXXConstructExpr, [B1.4]+0, class C) // CXX17-NEXT: 4: [B1.2]([B1.3]) void passArgument() { useC(C()); } +// CHECK: void passTwoArguments() +// CHECK: [B1] +// CHECK-NEXT: 1: useCAndD +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(class C, class argument_constructors::D)) +// CXX11-ELIDE-NEXT: 3: C() (CXXConstructExpr, [B1.4], [B1.5], class C) +// CXX11-NOELIDE-NEXT: 3: C() (CXXConstructExpr, [B1.4], class C) +// CXX11-NEXT: 4: [B1.3] +// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.12]+0, class C) +// CXX11-ELIDE-NEXT: 6: argument_constructors::D() (CXXConstructExpr, [B1.7], [B1.9], [B1.10], class argument_constructors::D) +// CXX11-NOELIDE-NEXT: 6: argument_constructors::D() (CXXConstructExpr, [B1.7], [B1.9], class argument_constructors::D) +// CXX11-NEXT: 7: [B1.6] (BindTemporary) +// CXX11-NEXT: 8: [B1.7] (ImplicitCastExpr, NoOp, const class argument_constructors::D) +// CXX11-NEXT: 9: [B1.8] +// CXX11-NEXT: 10: [B1.9] (CXXConstructExpr, [B1.11], [B1.12]+1, class argument_constructors::D) +// CXX11-NEXT: 11: [B1.10] (BindTemporary) +// CXX11-NEXT: 12: [B1.2]([B1.5], [B1.11]) +// CXX11-NEXT: 13: ~argument_constructors::D() (Temporary object destructor) +// CXX11-NEXT: 14: ~argument_constructors::D() (Temporary object destructor) +// CXX17-NEXT: 3: C() (CXXConstructExpr, [B1.6]+0, class C) +// CXX17-NEXT: 4: argument_constructors::D() (CXXConstructExpr, [B1.5], [B1.6]+1, class argument_co +// CXX17-NEXT: 5: [B1.4] (BindTemporary) +// CXX17-NEXT: 6: [B1.2]([B1.3], [B1.5]) +// CXX17-NEXT: 7: ~argument_constructors::D() (Temporary object destructor) +void passTwoArguments() { + useCAndD(C(), D()); +} + // CHECK: void passArgumentByReference() // CHECK: 1: useCByReference // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class C &)) @@ -847,20 +880,20 @@ void passArgumentByReference() { useCByReference(C()); } -// FIXME: Find construction context for the argument. // CHECK: void passArgumentWithDestructor() // CHECK: 1: useD // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(class argument_constructors::D)) -// CXX11-NEXT: 3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.6], class argument_constructors::D) +// CXX11-ELIDE-NEXT: 3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.6], [B1.7], class argument_constructors::D) +// CXX11-NOELIDE-NEXT: 3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.6], class argument_constructors::D) // CXX11-NEXT: 4: [B1.3] (BindTemporary) // CXX11-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class argument_constructors::D) // CXX11-NEXT: 6: [B1.5] -// CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, class argument_constructors::D) +// CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.8], [B1.9]+0, class argument_constructors::D) // CXX11-NEXT: 8: [B1.7] (BindTemporary) // CXX11-NEXT: 9: [B1.2]([B1.8]) // CXX11-NEXT: 10: ~argument_constructors::D() (Temporary object destructor) // CXX11-NEXT: 11: ~argument_constructors::D() (Temporary object destructor) -// CXX17-NEXT: 3: argument_constructors::D() (CXXConstructExpr, class argument_constructors::D) +// CXX17-NEXT: 3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.5]+0, class argument_constructors::D) // CXX17-NEXT: 4: [B1.3] (BindTemporary) // CXX17-NEXT: 5: [B1.2]([B1.4]) // CXX17-NEXT: 6: ~argument_constructors::D() (Temporary object destructor) @@ -880,6 +913,32 @@ void passArgumentWithDestructor() { void passArgumentWithDestructorByReference() { useDByReference(D()); } + +// CHECK: void passArgumentIntoAnotherConstructor() +// CXX11-ELIDE: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.4], [B1.5], class argument_constructors::D) +// CXX11-NOELIDE: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.4], class argument_constructors::D) +// CXX11-NEXT: 2: [B1.1] (BindTemporary) +// CXX11-NEXT: 3: [B1.2] (ImplicitCastExpr, NoOp, const class argument_constructors::D) +// CXX11-NEXT: 4: [B1.3] +// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], [B1.7]+0, class argument_constructors::D) +// CXX11-NEXT: 6: [B1.5] (BindTemporary) +// CXX11-ELIDE-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.9], [B1.10], class argument_constructors::E) +// CXX11-NOELIDE-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.9], class argument_constructors::E) +// CXX11-NEXT: 8: argument_constructors::E([B1.7]) (CXXFunctionalCastExpr, ConstructorConversion, class argument_constructors::E) +// CXX11-NEXT: 9: [B1.8] +// CXX11-NEXT: 10: [B1.9] (CXXConstructExpr, [B1.11], class argument_constructors::E) +// CXX11-NEXT: 11: argument_constructors::E e = argument_constructors::E(argument_constructors::D()); +// CXX11-NEXT: 12: ~argument_constructors::D() (Temporary object destructor) +// CXX11-NEXT: 13: ~argument_constructors::D() (Temporary object destructor) +// CXX17: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.3]+0, class argument_constructors::D) +// CXX17-NEXT: 2: [B1.1] (BindTemporary) +// CXX17-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], class argument_constructors::E) +// CXX17-NEXT: 4: argument_constructors::E([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class argument_constructors::E) +// CXX17-NEXT: 5: argument_constructors::E e = argument_constructors::E(argument_constructors::D()); +// CXX17-NEXT: 6: ~argument_constructors::D() (Temporary object destructor) +void passArgumentIntoAnotherConstructor() { + E e = E(D()); +} } // end namespace argument_constructors namespace copy_elision_with_extra_arguments { diff --git a/test/Analysis/cfg-rich-constructors.mm b/test/Analysis/cfg-rich-constructors.mm new file mode 100644 index 0000000000000..289094293eb5c --- /dev/null +++ b/test/Analysis/cfg-rich-constructors.mm @@ -0,0 +1,66 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -std=c++11 -w %s > %t 2>&1 +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX11,ELIDE,CXX11-ELIDE %s +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -std=c++17 -w %s > %t 2>&1 +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX17,ELIDE,CXX17-ELIDE %s +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -std=c++11 -w -analyzer-config elide-constructors=false %s > %t 2>&1 +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX11,NOELIDE,CXX11-NOELIDE %s +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -std=c++17 -w -analyzer-config elide-constructors=false %s > %t 2>&1 +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX17,NOELIDE,CXX17-NOELIDE %s + +class D { +public: + D(); + ~D(); +}; + +@interface E {} +-(void) foo: (D) d; +-(D) bar; +@end + +// CHECK: void passArgumentIntoMessage(E *e) +// CHECK: 1: e +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, E *) +// CXX11-ELIDE-NEXT: 3: D() (CXXConstructExpr, [B1.4], [B1.6], [B1.7], class D) +// CXX11-NOELIDE-NEXT: 3: D() (CXXConstructExpr, [B1.4], [B1.6], class D) +// CXX11-NEXT: 4: [B1.3] (BindTemporary) +// CXX11-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class D) +// CXX11-NEXT: 6: [B1.5] +// CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.8], [B1.9]+0, class D) +// CXX11-NEXT: 8: [B1.7] (BindTemporary) +// Double brackets trigger FileCheck variables, escape. +// CXX11-NEXT: 9: {{\[}}[B1.2] foo:[B1.8]] +// CXX11-NEXT: 10: ~D() (Temporary object destructor) +// CXX11-NEXT: 11: ~D() (Temporary object destructor) +// CXX17-NEXT: 3: D() (CXXConstructExpr, [B1.4], [B1.5]+0, class D) +// CXX17-NEXT: 4: [B1.3] (BindTemporary) +// Double brackets trigger FileCheck variables, escape. +// CXX17-NEXT: 5: {{\[}}[B1.2] foo:[B1.4]] +// CXX17-NEXT: 6: ~D() (Temporary object destructor) +void passArgumentIntoMessage(E *e) { + [e foo: D()]; +} + +// CHECK: void returnObjectFromMessage(E *e) +// CHECK: [B1] +// CHECK-NEXT: 1: e +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, E *) +// Double brackets trigger FileCheck variables, escape. +// CXX11-ELIDE-NEXT: 3: {{\[}}[B1.2] bar] (CXXRecordTypedCall, [B1.4], [B1.6], [B1.7]) +// CXX11-NOELIDE-NEXT: 3: {{\[}}[B1.2] bar] (CXXRecordTypedCall, [B1.4], [B1.6]) +// CXX11-NEXT: 4: [B1.3] (BindTemporary) +// CXX11-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class D) +// CXX11-NEXT: 6: [B1.5] +// CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.8], class D) +// CXX11-NEXT: 8: D d = [e bar]; +// CXX11-NEXT: 9: ~D() (Temporary object destructor) +// CXX11-NEXT: 10: [B1.8].~D() (Implicit destructor) +// Double brackets trigger FileCheck variables, escape. +// CXX17-NEXT: 3: {{\[}}[B1.2] bar] (CXXRecordTypedCall, [B1.5], [B1.4]) +// CXX17-NEXT: 4: [B1.3] (BindTemporary) +// CXX17-NEXT: 5: D d = [e bar]; +// CXX17-NEXT: 6: ~D() (Temporary object destructor) +// CXX17-NEXT: 7: [B1.5].~D() (Implicit destructor) +void returnObjectFromMessage(E *e) { + D d = [e bar]; +} diff --git a/test/Analysis/cxx17-mandatory-elision.cpp b/test/Analysis/copy-elision.cpp index cf77912ea6c4f..cf77912ea6c4f 100644 --- a/test/Analysis/cxx17-mandatory-elision.cpp +++ b/test/Analysis/copy-elision.cpp diff --git a/test/Analysis/cstring-ranges.c b/test/Analysis/cstring-ranges.c new file mode 100644 index 0000000000000..4fcd7eaa8bee2 --- /dev/null +++ b/test/Analysis/cstring-ranges.c @@ -0,0 +1,15 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=unix.cstring -analyzer-output=text %s 2>&1 | FileCheck %s + +// This test verifies argument source range highlighting. +// Otherwise we've no idea which of the arguments is null. + +char *strcpy(char *, const char *); + +void foo() { + char *a = 0, *b = 0; + strcpy(a, b); +} + +// CHECK: warning: Null pointer argument in call to string copy function +// CHECK-NEXT: strcpy(a, b); +// CHECK-NEXT: ^ ~ diff --git a/test/Analysis/inner-pointer.cpp b/test/Analysis/inner-pointer.cpp index db9bf43109b2f..230e3396c59ea 100644 --- a/test/Analysis/inner-pointer.cpp +++ b/test/Analysis/inner-pointer.cpp @@ -1,4 +1,4 @@ -//RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.InnerPointer %s -analyzer-output=text -verify +//RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.InnerPointer %s -analyzer-output=text -verify namespace std { @@ -38,6 +38,18 @@ typedef basic_string<wchar_t> wstring; typedef basic_string<char16_t> u16string; typedef basic_string<char32_t> u32string; +template <typename T> +void func_ref(T &a); + +template <typename T> +void func_const_ref(const T &a); + +template <typename T> +void func_value(T a); + +string my_string = "default"; +void default_arg(int a = 42, string &b = my_string); + } // end namespace std void consume(const char *) {} @@ -45,6 +57,10 @@ void consume(const wchar_t *) {} void consume(const char16_t *) {} void consume(const char32_t *) {} +//=--------------------------------------=// +// `std::string` member functions // +//=--------------------------------------=// + void deref_after_scope_char(bool cond) { const char *c, *d; { @@ -151,6 +167,19 @@ void multiple_symbols(bool cond) { } // expected-note@-1 {{Use of memory after it is freed}} } +void deref_after_scope_ok(bool cond) { + const char *c, *d; + std::string s; + { + c = s.c_str(); + d = s.data(); + } + if (cond) + consume(c); // no-warning + else + consume(d); // no-warning +} + void deref_after_equals() { const char *c; std::string s = "hello"; @@ -277,15 +306,58 @@ void deref_after_swap() { // expected-note@-1 {{Use of memory after it is freed}} } -void deref_after_scope_ok(bool cond) { - const char *c, *d; +//=---------------------------=// +// Other STL functions // +//=---------------------------=// + +void STL_func_ref() { + const char *c; std::string s; - { - c = s.c_str(); - d = s.data(); - } - if (cond) - consume(c); // no-warning - else - consume(d); // no-warning + c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} + std::func_ref(s); // expected-note {{Inner pointer invalidated by call to 'func_ref'}} + consume(c); // expected-warning {{Use of memory after it is freed}} + // expected-note@-1 {{Use of memory after it is freed}} +} + +void STL_func_const_ref() { + const char *c; + std::string s; + c = s.c_str(); + std::func_const_ref(s); + consume(c); // no-warning +} + +void STL_func_value() { + const char *c; + std::string s; + c = s.c_str(); + std::func_value(s); + consume(c); // no-warning +} + +void func_ptr_known() { + const char *c; + std::string s; + void (*func_ptr)(std::string &) = std::func_ref<std::string>; + c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} + func_ptr(s); // expected-note {{Inner pointer invalidated by call to 'func_ref'}} + consume(c); // expected-warning {{Use of memory after it is freed}} + // expected-note@-1 {{Use of memory after it is freed}} +} + +void func_ptr_unknown(void (*func_ptr)(std::string &)) { + const char *c; + std::string s; + c = s.c_str(); + func_ptr(s); + consume(c); // no-warning +} + +void func_default_arg() { + const char *c; + std::string s; + c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} + default_arg(3, s); // expected-note {{Inner pointer invalidated by call to 'default_arg'}} + consume(c); // expected-warning {{Use of memory after it is freed}} + // expected-note@-1 {{Use of memory after it is freed}} } diff --git a/test/Analysis/lifetime-extension.mm b/test/Analysis/lifetime-extension.mm new file mode 100644 index 0000000000000..6fb2e04f10183 --- /dev/null +++ b/test/Analysis/lifetime-extension.mm @@ -0,0 +1,64 @@ +// RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -verify %s +// RUN: %clang_analyze_cc1 -Wno-unused -std=c++17 -analyzer-checker=core,debug.ExprInspection -verify %s +// RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -DMOVES -verify %s +// RUN: %clang_analyze_cc1 -Wno-unused -std=c++17 -analyzer-checker=core,debug.ExprInspection -DMOVES -verify %s + +void clang_analyzer_eval(bool); +void clang_analyzer_checkInlined(bool); + +template <typename T> struct AddressVector { + T *buf[10]; + int len; + + AddressVector() : len(0) {} + + void push(T *t) { + buf[len] = t; + ++len; + } +}; + +class C { + AddressVector<C> &v; + +public: + C(AddressVector<C> &v) : v(v) { v.push(this); } + ~C() { v.push(this); } + +#ifdef MOVES + C(C &&c) : v(c.v) { v.push(this); } +#endif + + // Note how return-statements prefer move-constructors when available. + C(const C &c) : v(c.v) { +#ifdef MOVES + clang_analyzer_checkInlined(false); // no-warning +#else + v.push(this); +#endif + } // no-warning +}; + +@interface NSObject {} +@end; +@interface Foo: NSObject {} + -(C) make: (AddressVector<C> &)v; +@end + +@implementation Foo +-(C) make: (AddressVector<C> &)v { + return C(v); +} +@end + +void testReturnByValueFromMessage(Foo *foo) { + AddressVector<C> v; + { + const C &c = [foo make: v]; + } + // 0. Construct the return value of -make (copy/move elided) and + // lifetime-extend it directly via reference 'c', + // 1. Destroy the temporary lifetime-extended by 'c'. + clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}} +} diff --git a/test/Analysis/temporaries.cpp b/test/Analysis/temporaries.cpp index de3420e70891c..e760d7ea283ad 100644 --- a/test/Analysis/temporaries.cpp +++ b/test/Analysis/temporaries.cpp @@ -1,7 +1,7 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -verify -w -std=c++03 %s -// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -verify -w -std=c++11 %s -// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true %s -std=c++11 -// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -w -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true %s -std=c++17 +// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -verify -w -std=c++03 %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -verify -w -std=c++11 %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true %s -std=c++11 +// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus,debug.ExprInspection -DTEMPORARY_DTORS -w -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true %s -std=c++17 // Note: The C++17 run-line doesn't -verify yet - it is a no-crash test. @@ -458,6 +458,21 @@ namespace destructors { #endif // TEMPORARY_DTORS } +namespace default_param_elided_destructors { +struct a { + ~a(); +}; +struct F { + a d; + F(char *, a = a()); +}; +void g() { + char h[1]; + for (int i = 0;;) + F j(i ? j : h); +} +} // namespace default_param_elided_destructors + void testStaticMaterializeTemporaryExpr() { static const Trivial &ref = getTrivial(); clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} @@ -945,3 +960,29 @@ C &&foo2(); const C &bar1() { return foo1(); } // no-crash C &&bar2() { return foo2(); } // no-crash } // end namespace pass_references_through + + +namespace ctor_argument { +// Stripped down unique_ptr<int> +struct IntPtr { + IntPtr(): i(new int) {} + IntPtr(IntPtr &&o): i(o.i) { o.i = 0; } + ~IntPtr() { delete i; } + + int *i; +}; + +struct Foo { + Foo(IntPtr); + void bar(); + + IntPtr i; +}; + +void bar() { + IntPtr ptr; + int *i = ptr.i; + Foo f(static_cast<IntPtr &&>(ptr)); + *i = 99; // no-warning +} +} // namespace ctor_argument diff --git a/test/Analysis/temporaries.mm b/test/Analysis/temporaries.mm new file mode 100644 index 0000000000000..3b6166db6e303 --- /dev/null +++ b/test/Analysis/temporaries.mm @@ -0,0 +1,23 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker core,cplusplus -verify %s + +// expected-no-diagnostics + +// Stripped down unique_ptr<int> +struct IntPtr { + IntPtr(): i(new int) {} + IntPtr(IntPtr &&o): i(o.i) { o.i = nullptr; } + ~IntPtr() { delete i; } + + int *i; +}; + +@interface Foo {} + -(void) foo: (IntPtr)arg; +@end + +void bar(Foo *f) { + IntPtr ptr; + int *i = ptr.i; + [f foo: static_cast<IntPtr &&>(ptr)]; + *i = 99; // no-warning +} |