mboehme updated this revision to Diff 506510. mboehme added a comment. Added entry to release notes.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D145581/new/ https://reviews.llvm.org/D145581 Files: clang-tools-extra/clang-tidy/utils/ExprSequence.cpp clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
Index: clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp +++ clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp @@ -1,3 +1,4 @@ +// RUN: %check_clang_tidy -std=c++11 -check-suffixes=,CXX11 %s bugprone-use-after-move %t -- -- -fno-delayed-template-parsing // RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-use-after-move %t -- -- -fno-delayed-template-parsing typedef decltype(nullptr) nullptr_t; @@ -123,6 +124,7 @@ A &operator=(A &&); void foo() const; + void bar(int i) const; int getInt() const; operator bool() const; @@ -1307,6 +1309,30 @@ } } +// In a function call, the expression that determines the callee is sequenced +// before the arguments -- but only in C++17 and later. +namespace CalleeSequencedBeforeArguments { +int consumeA(std::unique_ptr<A> a); + +void calleeSequencedBeforeArguments() { + { + std::unique_ptr<A> a; + a->bar(consumeA(std::move(a))); + // CHECK-NOTES-CXX11: [[@LINE-1]]:5: warning: 'a' used after it was moved + // CHECK-NOTES-CXX11: [[@LINE-2]]:21: note: move occurred here + // CHECK-NOTES-CXX11: [[@LINE-3]]:5: note: the use and move are unsequenced + } + { + std::unique_ptr<A> a; + std::unique_ptr<A> getArg(std::unique_ptr<A> a); + getArg(std::move(a))->bar(a->getInt()); + // CHECK-NOTES: [[@LINE-1]]:31: warning: 'a' used after it was moved + // CHECK-NOTES: [[@LINE-2]]:12: note: move occurred here + // CHECK-NOTES-CXX11: [[@LINE-3]]:31: note: the use and move are unsequenced + } +} +} // namespace CalleeSequencedBeforeArguments + // Some statements in templates (e.g. null, break and continue statements) may // be shared between the uninstantiated and instantiated versions of the // template and therefore have multiple parents. Make sure the sequencing code Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -219,9 +219,12 @@ <clang-tidy/checks/cppcoreguidelines/slicing>` check when warning would be emitted in constructor for virtual base class initialization. -- Improved :doc:`bugprone-use-after-move - <clang-tidy/checks/bugprone/use-after-move>` to understand that there is a - sequence point between designated initializers. +- In :doc:`bugprone-use-after-move + <clang-tidy/checks/bugprone/use-after-move>`: + - Fixed handling for designated initializers. + - Fix: In C++17 and later, the callee of a function is guaranteed to be + sequenced before the arguments, so don't warn if the use happens in the + callee and the move happens in one of the arguments. Removed checks ^^^^^^^^^^^^^^ Index: clang-tools-extra/clang-tidy/utils/ExprSequence.cpp =================================================================== --- clang-tools-extra/clang-tidy/utils/ExprSequence.cpp +++ clang-tools-extra/clang-tidy/utils/ExprSequence.cpp @@ -95,9 +95,29 @@ return true; } + SmallVector<const Stmt *, 1> BeforeParents = getParentStmts(Before, Context); + + // Since C++17, the callee of a call expression is guaranteed to be sequenced + // before all of the arguments. + // We handle this as a special case rather than using the general + // `getSequenceSuccessor` logic above because the callee expression doesn't + // have an unambiguous successor; the order in which arguments are evaluated + // is indeterminate. + if (Context->getLangOpts().CPlusPlus17) { + for (const Stmt *Parent : BeforeParents) { + if (const auto *call = dyn_cast<CallExpr>(Parent); + call && call->getCallee() == Before) { + for (const Expr *arg : call->arguments()) { + if (isDescendantOrEqual(After, arg, Context)) + return true; + } + } + } + } + // If 'After' is a parent of 'Before' or is sequenced after one of these // parents, we know that it is sequenced after 'Before'. - for (const Stmt *Parent : getParentStmts(Before, Context)) { + for (const Stmt *Parent : BeforeParents) { if (Parent == After || inSequence(Parent, After)) return true; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits