1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=constructors -verify %s \ 2 // RUN: 2>&1 | FileCheck %s 3 4 5 void clang_analyzer_printState(); 6 template <typename T> void clang_analyzer_dump_lref(T& param); 7 template <typename T> void clang_analyzer_dump_val(T param); 8 template <typename T> void clang_analyzer_denote(T param, const char *name); 9 template <typename T> void clang_analyzer_express(T param); 10 template <typename T> T conjure(); 11 template <typename... Ts> void nop(const Ts &... args) {} 12 13 struct aggr { 14 int x; 15 int y; 16 }; 17 18 struct empty { 19 }; 20 21 void test_copy_return() { 22 aggr s1 = {1, 2}; 23 aggr const& cr1 = aggr(s1); 24 clang_analyzer_dump_lref(cr1); // expected-warning-re {{&lifetime_extended_object{aggr, cr1, S{{[0-9]+}}} }} 25 26 empty s2; 27 empty const& cr2 = empty{s2}; 28 clang_analyzer_dump_lref(cr2); // expected-warning-re {{&lifetime_extended_object{empty, cr2, S{{[0-9]+}}} }} 29 } 30 31 void test_assign_return() { 32 aggr s1 = {1, 2}; 33 aggr d1; 34 clang_analyzer_dump_lref(d1 = s1); // expected-warning {{&d1 }} 35 36 empty s2; 37 empty d2; 38 clang_analyzer_dump_lref(d2 = s2); // expected-warning {{&d2 }} was Unknown 39 } 40 41 42 namespace trivial_struct_copy { 43 44 void _01_empty_structs() { 45 clang_analyzer_dump_val(conjure<empty>()); // expected-warning {{conj_$}} 46 empty Empty = conjure<empty>(); 47 empty Empty2 = Empty; 48 empty Empty3 = Empty2; 49 // All of these should refer to the exact same symbol, because all of 50 // these trivial copies refer to the original conjured value. 51 // There were Unknown before: 52 clang_analyzer_denote(Empty, "$Empty"); 53 clang_analyzer_express(Empty); // expected-warning {{$Empty}} 54 clang_analyzer_express(Empty2); // expected-warning {{$Empty}} 55 clang_analyzer_express(Empty3); // expected-warning {{$Empty}} 56 57 // We should have the same Conjured symbol for "Empty", "Empty2" and "Empty3". 58 clang_analyzer_printState(); 59 // CHECK: "store": { "pointer": "0x{{[0-9a-f]+}}", "items": [ 60 // CHECK-NEXT: { "cluster": "GlobalInternalSpaceRegion", "pointer": "0x{{[0-9a-f]+}}", "items": [ 61 // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "conj_$ 62 // CHECK-NEXT: ]}, 63 // CHECK-NEXT: { "cluster": "GlobalSystemSpaceRegion", "pointer": "0x{{[0-9a-f]+}}", "items": [ 64 // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "conj_$ 65 // CHECK-NEXT: ]}, 66 // CHECK-NEXT: { "cluster": "Empty", "pointer": "0x{{[0-9a-f]+}}", "items": [ 67 // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[EMPTY_CONJ:conj_\$[0-9]+{int, LC[0-9]+, S[0-9]+, #[0-9]+}]]" } 68 // CHECK-NEXT: ]}, 69 // CHECK-NEXT: { "cluster": "Empty2", "pointer": "0x{{[0-9a-f]+}}", "items": [ 70 // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[EMPTY_CONJ]]" } 71 // CHECK-NEXT: ]}, 72 // CHECK-NEXT: { "cluster": "Empty3", "pointer": "0x{{[0-9a-f]+}}", "items": [ 73 // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[EMPTY_CONJ]]" } 74 // CHECK-NEXT: ]} 75 // CHECK-NEXT: ]}, 76 77 nop(Empty, Empty2, Empty3); 78 } 79 80 void _02_structs_with_members() { 81 clang_analyzer_dump_val(conjure<aggr>()); // expected-warning {{conj_$}} 82 aggr Aggr = conjure<aggr>(); 83 aggr Aggr2 = Aggr; 84 aggr Aggr3 = Aggr2; 85 // All of these should refer to the exact same symbol, because all of 86 // these trivial copies refer to the original conjured value. 87 clang_analyzer_denote(Aggr, "$Aggr"); 88 clang_analyzer_express(Aggr); // expected-warning {{$Aggr}} 89 clang_analyzer_express(Aggr2); // expected-warning {{$Aggr}} 90 clang_analyzer_express(Aggr3); // expected-warning {{$Aggr}} 91 92 // We should have the same Conjured symbol for "Aggr", "Aggr2" and "Aggr3". 93 // We used to have Derived symbols for the individual fields that were 94 // copied as part of copying the whole struct. 95 clang_analyzer_printState(); 96 // CHECK: "store": { "pointer": "0x{{[0-9a-f]+}}", "items": [ 97 // CHECK-NEXT: { "cluster": "GlobalInternalSpaceRegion", "pointer": "0x{{[0-9a-f]+}}", "items": [ 98 // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "conj_$ 99 // CHECK-NEXT: ]}, 100 // CHECK-NEXT: { "cluster": "GlobalSystemSpaceRegion", "pointer": "0x{{[0-9a-f]+}}", "items": [ 101 // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "conj_$ 102 // CHECK-NEXT: ]}, 103 // CHECK-NEXT: { "cluster": "Aggr", "pointer": "0x{{[0-9a-f]+}}", "items": [ 104 // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[AGGR_CONJ:conj_\$[0-9]+{int, LC[0-9]+, S[0-9]+, #[0-9]+}]]" } 105 // CHECK-NEXT: ]}, 106 // CHECK-NEXT: { "cluster": "Aggr2", "pointer": "0x{{[0-9a-f]+}}", "items": [ 107 // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[AGGR_CONJ]]" } 108 // CHECK-NEXT: ]}, 109 // CHECK-NEXT: { "cluster": "Aggr3", "pointer": "0x{{[0-9a-f]+}}", "items": [ 110 // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[AGGR_CONJ]]" } 111 // CHECK-NEXT: ]} 112 // CHECK-NEXT: ]}, 113 114 nop(Aggr, Aggr2, Aggr3); 115 } 116 117 // Tests that use `clang_analyzer_printState()` must share the analysis entry 118 // point, and have a strict ordering between. This is to meet the different 119 // `clang_analyzer_printState()` calls in a fixed relative ordering, thus 120 // FileCheck could check the stdouts. 121 void entrypoint() { 122 _01_empty_structs(); 123 _02_structs_with_members(); 124 } 125 126 } // namespace trivial_struct_copy 127