// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=constructors -verify %s \ // RUN: 2>&1 | FileCheck %s void clang_analyzer_printState(); template void clang_analyzer_dump_lref(T& param); template void clang_analyzer_dump_val(T param); template void clang_analyzer_denote(T param, const char *name); template void clang_analyzer_express(T param); template T conjure(); template void nop(const Ts &... args) {} struct aggr { int x; int y; }; struct empty { }; void test_copy_return() { aggr s1 = {1, 2}; aggr const& cr1 = aggr(s1); clang_analyzer_dump_lref(cr1); // expected-warning-re {{&lifetime_extended_object{aggr, cr1, S{{[0-9]+}}} }} empty s2; empty const& cr2 = empty{s2}; clang_analyzer_dump_lref(cr2); // expected-warning-re {{&lifetime_extended_object{empty, cr2, S{{[0-9]+}}} }} } void test_assign_return() { aggr s1 = {1, 2}; aggr d1; clang_analyzer_dump_lref(d1 = s1); // expected-warning {{&d1 }} empty s2; empty d2; clang_analyzer_dump_lref(d2 = s2); // expected-warning {{&d2 }} was Unknown } namespace trivial_struct_copy { void _01_empty_structs() { clang_analyzer_dump_val(conjure()); // expected-warning {{conj_$}} empty Empty = conjure(); empty Empty2 = Empty; empty Empty3 = Empty2; // All of these should refer to the exact same symbol, because all of // these trivial copies refer to the original conjured value. // There were Unknown before: clang_analyzer_denote(Empty, "$Empty"); clang_analyzer_express(Empty); // expected-warning {{$Empty}} clang_analyzer_express(Empty2); // expected-warning {{$Empty}} clang_analyzer_express(Empty3); // expected-warning {{$Empty}} // We should have the same Conjured symbol for "Empty", "Empty2" and "Empty3". clang_analyzer_printState(); // CHECK: "store": { "pointer": "0x{{[0-9a-f]+}}", "items": [ // CHECK-NEXT: { "cluster": "GlobalInternalSpaceRegion", "pointer": "0x{{[0-9a-f]+}}", "items": [ // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "conj_$ // CHECK-NEXT: ]}, // CHECK-NEXT: { "cluster": "GlobalSystemSpaceRegion", "pointer": "0x{{[0-9a-f]+}}", "items": [ // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "conj_$ // CHECK-NEXT: ]}, // CHECK-NEXT: { "cluster": "Empty", "pointer": "0x{{[0-9a-f]+}}", "items": [ // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[EMPTY_CONJ:conj_\$[0-9]+{int, LC[0-9]+, S[0-9]+, #[0-9]+}]]" } // CHECK-NEXT: ]}, // CHECK-NEXT: { "cluster": "Empty2", "pointer": "0x{{[0-9a-f]+}}", "items": [ // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[EMPTY_CONJ]]" } // CHECK-NEXT: ]}, // CHECK-NEXT: { "cluster": "Empty3", "pointer": "0x{{[0-9a-f]+}}", "items": [ // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[EMPTY_CONJ]]" } // CHECK-NEXT: ]} // CHECK-NEXT: ]}, nop(Empty, Empty2, Empty3); } void _02_structs_with_members() { clang_analyzer_dump_val(conjure()); // expected-warning {{conj_$}} aggr Aggr = conjure(); aggr Aggr2 = Aggr; aggr Aggr3 = Aggr2; // All of these should refer to the exact same symbol, because all of // these trivial copies refer to the original conjured value. clang_analyzer_denote(Aggr, "$Aggr"); clang_analyzer_express(Aggr); // expected-warning {{$Aggr}} clang_analyzer_express(Aggr2); // expected-warning {{$Aggr}} clang_analyzer_express(Aggr3); // expected-warning {{$Aggr}} // We should have the same Conjured symbol for "Aggr", "Aggr2" and "Aggr3". // We used to have Derived symbols for the individual fields that were // copied as part of copying the whole struct. clang_analyzer_printState(); // CHECK: "store": { "pointer": "0x{{[0-9a-f]+}}", "items": [ // CHECK-NEXT: { "cluster": "GlobalInternalSpaceRegion", "pointer": "0x{{[0-9a-f]+}}", "items": [ // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "conj_$ // CHECK-NEXT: ]}, // CHECK-NEXT: { "cluster": "GlobalSystemSpaceRegion", "pointer": "0x{{[0-9a-f]+}}", "items": [ // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "conj_$ // CHECK-NEXT: ]}, // CHECK-NEXT: { "cluster": "Aggr", "pointer": "0x{{[0-9a-f]+}}", "items": [ // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[AGGR_CONJ:conj_\$[0-9]+{int, LC[0-9]+, S[0-9]+, #[0-9]+}]]" } // CHECK-NEXT: ]}, // CHECK-NEXT: { "cluster": "Aggr2", "pointer": "0x{{[0-9a-f]+}}", "items": [ // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[AGGR_CONJ]]" } // CHECK-NEXT: ]}, // CHECK-NEXT: { "cluster": "Aggr3", "pointer": "0x{{[0-9a-f]+}}", "items": [ // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[AGGR_CONJ]]" } // CHECK-NEXT: ]} // CHECK-NEXT: ]}, nop(Aggr, Aggr2, Aggr3); } // Tests that use `clang_analyzer_printState()` must share the analysis entry // point, and have a strict ordering between. This is to meet the different // `clang_analyzer_printState()` calls in a fixed relative ordering, thus // FileCheck could check the stdouts. void entrypoint() { _01_empty_structs(); _02_structs_with_members(); } } // namespace trivial_struct_copy