xref: /llvm-project/clang/test/Analysis/ctor-trivial-copy.cpp (revision 9b2ec87f5bce57cc900cf52a99f805d999716053)
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