aboutsummaryrefslogtreecommitdiff
path: root/clang/test/Analysis/ctor-trivial-copy.cpp
blob: 45c8ca4c517762c64e7eb50f7ed1e418d2656952 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// 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 <typename T> void clang_analyzer_dump_lref(T& param);
template <typename T> void clang_analyzer_dump_val(T param);
template <typename T> void clang_analyzer_denote(T param, const char *name);
template <typename T> void clang_analyzer_express(T param);
template <typename T> T conjure();
template <typename... Ts> 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<empty>()); // expected-warning {{conj_$}}
  empty Empty = conjure<empty>();
  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<aggr>()); // expected-warning {{conj_$}}
  aggr Aggr = conjure<aggr>();
  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