Index: clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp @@ -384,6 +384,13 @@ // the direct ancestor of the std::move() that isn't one of the node // types ignored by ignoringParenImpCasts(). stmt(forEach(expr(ignoringParenImpCasts(CallMoveMatcher))), + // Don't allow an InitListExpr to be the moving call. An InitListExpr + // has both a syntactic and a semantic form, and the parent-child + // relationships are different between the two. This could cause an + // InitListExpr to be analyzed as the moving call in addition to the + // Expr that we actually want, resulting in two diagnostics with + // different code locations for the same move. + unless(initListExpr()), unless(expr(ignoringParenImpCasts(equalsBoundNode("call-move"))))) .bind("moving-call"), this); @@ -398,7 +405,7 @@ const auto *MovingCall = Result.Nodes.getNodeAs("moving-call"); const auto *Arg = Result.Nodes.getNodeAs("arg"); - if (!MovingCall) + if (!MovingCall || !MovingCall->getExprLoc().isValid()) MovingCall = CallMove; Stmt *FunctionBody = nullptr; Index: clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp +++ clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp @@ -282,7 +282,7 @@ S s{std::move(a)}; a.foo(); // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved - // CHECK-MESSAGES: [[@LINE-3]]:6: note: move occurred here + // CHECK-MESSAGES: [[@LINE-3]]:7: note: move occurred here } void lambdas() { @@ -397,6 +397,21 @@ } template void movedTypeIsDependentType(); +// We handle the case correctly where the move consists of an implicit call +// to a conversion operator. +void implicitConversionOperator() { + struct Convertible { + operator A() && { return A(); } + }; + void takeA(A a); + + Convertible convertible; + takeA(std::move(convertible)); + convertible; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'convertible' used after it was moved + // CHECK-MESSAGES: [[@LINE-3]]:9: note: move occurred here +} + // Using decltype on an expression is not a use. void decltypeIsNotUse() { A a;