Skip to content

Commit d73c58a

Browse files
Extend bugprone-use-after-move check to handle std::optional::reset() and std::any::reset() similarly to smart pointers
1 parent 87605b1 commit d73c58a

File tree

4 files changed

+52
-12
lines changed

4 files changed

+52
-12
lines changed

clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -315,9 +315,10 @@ void UseAfterMoveFinder::getReinits(
315315
"::std::unordered_map", "::std::unordered_multiset",
316316
"::std::unordered_multimap"))))));
317317

318-
auto StandardSmartPointerTypeMatcher = hasType(hasUnqualifiedDesugaredType(
319-
recordType(hasDeclaration(cxxRecordDecl(hasAnyName(
320-
"::std::unique_ptr", "::std::shared_ptr", "::std::weak_ptr"))))));
318+
auto StandardResettableOwnerTypeMatcher = hasType(
319+
hasUnqualifiedDesugaredType(recordType(hasDeclaration(cxxRecordDecl(
320+
hasAnyName("::std::unique_ptr", "::std::shared_ptr",
321+
"::std::weak_ptr", "::std::optional", "::std::any"))))));
321322

322323
// Matches different types of reinitialization.
323324
auto ReinitMatcher =
@@ -340,7 +341,7 @@ void UseAfterMoveFinder::getReinits(
340341
callee(cxxMethodDecl(hasAnyName("clear", "assign")))),
341342
// reset() on standard smart pointers.
342343
cxxMemberCallExpr(
343-
on(expr(DeclRefMatcher, StandardSmartPointerTypeMatcher)),
344+
on(expr(DeclRefMatcher, StandardResettableOwnerTypeMatcher)),
344345
callee(cxxMethodDecl(hasName("reset")))),
345346
// Methods that have the [[clang::reinitializes]] attribute.
346347
cxxMemberCallExpr(

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,11 @@ Changes in existing checks
190190
<clang-tidy/checks/bugprone/unsafe-functions>` check to allow specifying
191191
additional functions to match.
192192

193+
- Improved :doc:`bugprone-use-after-move
194+
<clang-tidy/checks/bugprone/use-after-move>` to avoid triggering on
195+
``reset()`` calls on moved-from ``std::optional`` and ``std::any`` objects,
196+
similarly to smart pointers.
197+
193198
- Improved :doc:`cert-flp30-c <clang-tidy/checks/cert/flp30-c>` check to
194199
fix false positive that floating point variable is only used in increment
195200
expression.

clang-tools-extra/docs/clang-tidy/checks/bugprone/use-after-move.rst

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,13 @@ Any occurrence of the moved variable that is not a reinitialization (see below)
196196
is considered to be a use.
197197

198198
An exception to this are objects of type ``std::unique_ptr``,
199-
``std::shared_ptr`` and ``std::weak_ptr``, which have defined move behavior
200-
(objects of these classes are guaranteed to be empty after they have been moved
201-
from). Therefore, an object of these classes will only be considered to be used
202-
if it is dereferenced, i.e. if ``operator*``, ``operator->`` or ``operator[]``
203-
(in the case of ``std::unique_ptr<T []>``) is called on it.
199+
``std::shared_ptr``, ``std::weak_ptr``, ``std::optional``, and ``std::any``.
200+
An exception to this are objects of type `std::unique_ptr`,
201+
`std::shared_ptr`, `std::weak_ptr`, `std::optional`, and `std::any`, which
202+
can be reinitialized via `reset`. For smart pointers specifically, the
203+
moved-from objects have a well-defined state of being `nullptr`s, and only
204+
`operator*`, `operator->` and `operator[]` are considered bad accesses as
205+
they would be dereferencing a `nullptr`.
204206

205207
If multiple uses occur after a move, only the first of these is flagged.
206208

@@ -222,7 +224,8 @@ The check considers a variable to be reinitialized in the following cases:
222224
``unordered_multimap``.
223225

224226
- ``reset()`` is called on the variable and the variable is of type
225-
``std::unique_ptr``, ``std::shared_ptr`` or ``std::weak_ptr``.
227+
``std::unique_ptr``, ``std::shared_ptr``, ``std::weak_ptr``,
228+
``std::optional``, or ``std::any``.
226229

227230
- A member function marked with the ``[[clang::reinitializes]]`` attribute is
228231
called on the variable.

clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ struct weak_ptr {
3333
bool expired() const;
3434
};
3535

36+
template <typename T>
37+
struct optional {
38+
optional();
39+
void reset();
40+
};
41+
42+
struct any {
43+
any();
44+
void reset();
45+
};
46+
3647
template <typename T1, typename T2>
3748
struct pair {};
3849

@@ -994,10 +1005,10 @@ void standardContainerAssignIsReinit() {
9941005
}
9951006
}
9961007

997-
// Resetting the standard smart pointer types using reset() is treated as a
1008+
// Resetting the standard smart owning types using reset() is treated as a
9981009
// re-initialization. (We don't test std::weak_ptr<> because it can't be
9991010
// dereferenced directly.)
1000-
void standardSmartPointerResetIsReinit() {
1011+
void resetIsReinit() {
10011012
{
10021013
std::unique_ptr<A> ptr;
10031014
std::move(ptr);
@@ -1010,6 +1021,26 @@ void standardSmartPointerResetIsReinit() {
10101021
ptr.reset(new A);
10111022
*ptr;
10121023
}
1024+
{
1025+
std::optional<A> opt;
1026+
std::move(opt);
1027+
opt.reset();
1028+
std::optional<A> opt2 = opt;
1029+
(void)opt2;
1030+
}
1031+
{
1032+
std::optional<A> opt;
1033+
std::move(opt);
1034+
A val = *opt;
1035+
(void)val;
1036+
}
1037+
{
1038+
std::any a;
1039+
std::move(a);
1040+
a.reset();
1041+
std::any a2 = a;
1042+
(void)a2;
1043+
}
10131044
}
10141045

10151046
void reinitAnnotation() {

0 commit comments

Comments
 (0)