1.. title:: clang-tidy - bugprone-use-after-move
2
3bugprone-use-after-move
4=======================
5
6Warns if an object is used after it has been moved, for example:
7
8.. code-block:: c++
9
10    std::string str = "Hello, world!\n";
11    std::vector<std::string> messages;
12    messages.emplace_back(std::move(str));
13    std::cout << str;
14
15The last line will trigger a warning that ``str`` is used after it has been
16moved.
17
18The check does not trigger a warning if the object is reinitialized after the
19move and before the use. For example, no warning will be output for this code:
20
21.. code-block:: c++
22
23    messages.emplace_back(std::move(str));
24    str = "Greetings, stranger!\n";
25    std::cout << str;
26
27The check takes control flow into account. A warning is only emitted if the use
28can be reached from the move. This means that the following code does not
29produce a warning:
30
31.. code-block:: c++
32
33    if (condition) {
34      messages.emplace_back(std::move(str));
35    } else {
36      std::cout << str;
37    }
38
39On the other hand, the following code does produce a warning:
40
41.. code-block:: c++
42
43    for (int i = 0; i < 10; ++i) {
44      std::cout << str;
45      messages.emplace_back(std::move(str));
46    }
47
48(The use-after-move happens on the second iteration of the loop.)
49
50In some cases, the check may not be able to detect that two branches are
51mutually exclusive. For example (assuming that ``i`` is an int):
52
53.. code-block:: c++
54
55    if (i == 1) {
56      messages.emplace_back(std::move(str));
57    }
58    if (i == 2) {
59      std::cout << str;
60    }
61
62In this case, the check will erroneously produce a warning, even though it is
63not possible for both the move and the use to be executed.
64
65An erroneous warning can be silenced by reinitializing the object after the
66move:
67
68.. code-block:: c++
69
70    if (i == 1) {
71      messages.emplace_back(std::move(str));
72      str = "";
73    }
74    if (i == 2) {
75      std::cout << str;
76    }
77
78Subsections below explain more precisely what exactly the check considers to be
79a move, use, and reinitialization.
80
81Unsequenced moves, uses, and reinitializations
82----------------------------------------------
83
84In many cases, C++ does not make any guarantees about the order in which
85sub-expressions of a statement are evaluated. This means that in code like the
86following, it is not guaranteed whether the use will happen before or after the
87move:
88
89.. code-block:: c++
90
91    void f(int i, std::vector<int> v);
92    std::vector<int> v = { 1, 2, 3 };
93    f(v[1], std::move(v));
94
95In this kind of situation, the check will note that the use and move are
96unsequenced.
97
98The check will also take sequencing rules into account when reinitializations
99occur in the same statement as moves or uses. A reinitialization is only
100considered to reinitialize a variable if it is guaranteed to be evaluated after
101the move and before the use.
102
103Move
104----
105
106The check currently only considers calls of ``std::move`` on local variables or
107function parameters. It does not check moves of member variables or global
108variables.
109
110Any call of ``std::move`` on a variable is considered to cause a move of that
111variable, even if the result of ``std::move`` is not passed to an rvalue
112reference parameter.
113
114This means that the check will flag a use-after-move even on a type that does
115not define a move constructor or move assignment operator. This is intentional.
116Developers may use ``std::move`` on such a type in the expectation that the type
117will add move semantics in the future. If such a ``std::move`` has the potential
118to cause a use-after-move, we want to warn about it even if the type does not
119implement move semantics yet.
120
121Furthermore, if the result of ``std::move`` *is* passed to an rvalue reference
122parameter, this will always be considered to cause a move, even if the function
123that consumes this parameter does not move from it, or if it does so only
124conditionally. For example, in the following situation, the check will assume
125that a move always takes place:
126
127.. code-block:: c++
128
129    std::vector<std::string> messages;
130    void f(std::string &&str) {
131      // Only remember the message if it isn't empty.
132      if (!str.empty()) {
133        messages.emplace_back(std::move(str));
134      }
135    }
136    std::string str = "";
137    f(std::move(str));
138
139The check will assume that the last line causes a move, even though, in this
140particular case, it does not. Again, this is intentional.
141
142When analyzing the order in which moves, uses and reinitializations happen (see
143section `Unsequenced moves, uses, and reinitializations`_), the move is assumed
144to occur in whichever function the result of the ``std::move`` is passed to.
145
146Use
147---
148
149Any occurrence of the moved variable that is not a reinitialization (see below)
150is considered to be a use.
151
152An exception to this are objects of type ``std::unique_ptr``,
153``std::shared_ptr`` and ``std::weak_ptr``, which have defined move behavior
154(objects of these classes are guaranteed to be empty after they have been moved
155from). Therefore, an object of these classes will only be considered to be used
156if it is dereferenced, i.e. if ``operator*``, ``operator->`` or ``operator[]``
157(in the case of ``std::unique_ptr<T []>``) is called on it.
158
159If multiple uses occur after a move, only the first of these is flagged.
160
161Reinitialization
162----------------
163
164The check considers a variable to be reinitialized in the following cases:
165
166  - The variable occurs on the left-hand side of an assignment.
167
168  - The variable is passed to a function as a non-const pointer or non-const
169    lvalue reference. (It is assumed that the variable may be an out-parameter
170    for the function.)
171
172  - ``clear()`` or ``assign()`` is called on the variable and the variable is of
173    one of the standard container types ``basic_string``, ``vector``, ``deque``,
174    ``forward_list``, ``list``, ``set``, ``map``, ``multiset``, ``multimap``,
175    ``unordered_set``, ``unordered_map``, ``unordered_multiset``,
176    ``unordered_multimap``.
177
178  - ``reset()`` is called on the variable and the variable is of type
179    ``std::unique_ptr``, ``std::shared_ptr`` or ``std::weak_ptr``.
180
181  - A member function marked with the ``[[clang::reinitializes]]`` attribute is
182    called on the variable.
183
184If the variable in question is a struct and an individual member variable of
185that struct is written to, the check does not consider this to be a
186reinitialization -- even if, eventually, all member variables of the struct are
187written to. For example:
188
189.. code-block:: c++
190
191    struct S {
192      std::string str;
193      int i;
194    };
195    S s = { "Hello, world!\n", 42 };
196    S s_other = std::move(s);
197    s.str = "Lorem ipsum";
198    s.i = 99;
199
200The check will not consider ``s`` to be reinitialized after the last line;
201instead, the line that assigns to ``s.str`` will be flagged as a use-after-move.
202This is intentional as this pattern of reinitializing a struct is error-prone.
203For example, if an additional member variable is added to ``S``, it is easy to
204forget to add the reinitialization for this additional member. Instead, it is
205safer to assign to the entire struct in one go, and this will also avoid the
206use-after-move warning.
207