1// RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -verify %s 2// RUN: %clang_analyze_cc1 -Wno-unused -std=c++17 -analyzer-checker=core,debug.ExprInspection -verify %s 3// RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -DMOVES -verify %s 4// RUN: %clang_analyze_cc1 -Wno-unused -std=c++17 -analyzer-checker=core,debug.ExprInspection -DMOVES -verify %s 5 6void clang_analyzer_eval(bool); 7void clang_analyzer_checkInlined(bool); 8 9template <typename T> struct AddressVector { 10 T *buf[10]; 11 int len; 12 13 AddressVector() : len(0) {} 14 15 void push(T *t) { 16 buf[len] = t; 17 ++len; 18 } 19}; 20 21class C { 22 AddressVector<C> &v; 23 24public: 25 C(AddressVector<C> &v) : v(v) { v.push(this); } 26 ~C() { v.push(this); } 27 28#ifdef MOVES 29 C(C &&c) : v(c.v) { v.push(this); } 30#endif 31 32 // Note how return-statements prefer move-constructors when available. 33 C(const C &c) : v(c.v) { 34#ifdef MOVES 35 clang_analyzer_checkInlined(false); // no-warning 36#else 37 v.push(this); 38#endif 39 } // no-warning 40}; 41 42@interface NSObject {} 43@end; 44@interface Foo: NSObject {} 45 -(C) make: (AddressVector<C> &)v; 46@end 47 48@implementation Foo 49-(C) make: (AddressVector<C> &)v { 50 return C(v); 51} 52@end 53 54void testReturnByValueFromMessage(Foo *foo) { 55 AddressVector<C> v; 56 { 57 const C &c = [foo make: v]; 58 } 59 // 0. Construct the return value of -make (copy/move elided) and 60 // lifetime-extend it directly via reference 'c', 61 // 1. Destroy the temporary lifetime-extended by 'c'. 62 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}} 63 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}} 64} 65