diff --git a/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp b/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp --- a/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp +++ b/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp @@ -82,9 +82,29 @@ return true; } + SmallVector 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(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; } diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp @@ -1293,6 +1293,18 @@ } } +// In a function call, the expression that determines the callee is sequenced +// before the arguments. +namespace CalleeSequencedBeforeArguments { +struct A { + void foo(std::unique_ptr) {} +}; +void calleeSequencedBeforeArguments() { + std::unique_ptr a; + a->foo(std::move(a)); +} +} // 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 @@ -1363,4 +1375,4 @@ private: std::string val_; -}; +}; \ No newline at end of file