summaryrefslogtreecommitdiff
path: root/test/Analysis
diff options
context:
space:
mode:
Diffstat (limited to 'test/Analysis')
-rw-r--r--test/Analysis/Checkers/RunLoopAutoreleaseLeakChecker.m22
-rw-r--r--test/Analysis/casts.c7
-rw-r--r--test/Analysis/cfg-rich-constructors.cpp75
-rw-r--r--test/Analysis/cfg-rich-constructors.mm66
-rw-r--r--test/Analysis/copy-elision.cpp (renamed from test/Analysis/cxx17-mandatory-elision.cpp)0
-rw-r--r--test/Analysis/cstring-ranges.c15
-rw-r--r--test/Analysis/inner-pointer.cpp94
-rw-r--r--test/Analysis/lifetime-extension.mm64
-rw-r--r--test/Analysis/temporaries.cpp49
-rw-r--r--test/Analysis/temporaries.mm23
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
+}