@@ -330,7 +330,8 @@ void UseAfterMoveFinder::getReinits(
330
330
traverse (TK_AsIs, DeclRefMatcher),
331
331
unless (parmVarDecl (hasType (
332
332
references (qualType (isConstQualified ())))))),
333
- unless (callee (functionDecl (hasName (" ::std::move" )))))))
333
+ unless (callee (functionDecl (
334
+ hasAnyName (" ::std::move" , " ::std::forward" )))))))
334
335
.bind (" reinit" );
335
336
336
337
Stmts->clear ();
@@ -359,24 +360,46 @@ void UseAfterMoveFinder::getReinits(
359
360
}
360
361
}
361
362
363
+ enum class MoveType {
364
+ Move, // std::move
365
+ Forward, // std::forward
366
+ };
367
+
368
+ static MoveType determineMoveType (const FunctionDecl *FuncDecl) {
369
+ if (FuncDecl->getName () == " move" )
370
+ return MoveType::Move;
371
+ if (FuncDecl->getName () == " forward" )
372
+ return MoveType::Forward;
373
+
374
+ llvm_unreachable (" Invalid move type" );
375
+ }
376
+
362
377
static void emitDiagnostic (const Expr *MovingCall, const DeclRefExpr *MoveArg,
363
378
const UseAfterMove &Use, ClangTidyCheck *Check,
364
- ASTContext *Context) {
365
- SourceLocation UseLoc = Use.DeclRef ->getExprLoc ();
366
- SourceLocation MoveLoc = MovingCall->getExprLoc ();
379
+ ASTContext *Context, MoveType Type) {
380
+ const SourceLocation UseLoc = Use.DeclRef ->getExprLoc ();
381
+ const SourceLocation MoveLoc = MovingCall->getExprLoc ();
382
+
383
+ const bool IsMove = (Type == MoveType::Move);
367
384
368
- Check->diag (UseLoc, " '%0' used after it was moved" )
369
- << MoveArg->getDecl ()->getName ();
370
- Check->diag (MoveLoc, " move occurred here" , DiagnosticIDs::Note);
385
+ Check->diag (UseLoc, " '%0' used after it was %select{forwarded|moved}1" )
386
+ << MoveArg->getDecl ()->getName () << IsMove;
387
+ Check->diag (MoveLoc, " %select{forward|move}0 occurred here" ,
388
+ DiagnosticIDs::Note)
389
+ << IsMove;
371
390
if (Use.EvaluationOrderUndefined ) {
372
- Check->diag (UseLoc,
373
- " the use and move are unsequenced, i.e. there is no guarantee "
374
- " about the order in which they are evaluated" ,
375
- DiagnosticIDs::Note);
391
+ Check->diag (
392
+ UseLoc,
393
+ " the use and %select{forward|move}0 are unsequenced, i.e. "
394
+ " there is no guarantee about the order in which they are evaluated" ,
395
+ DiagnosticIDs::Note)
396
+ << IsMove;
376
397
} else if (UseLoc < MoveLoc || Use.DeclRef == MoveArg) {
377
398
Check->diag (UseLoc,
378
- " the use happens in a later loop iteration than the move" ,
379
- DiagnosticIDs::Note);
399
+ " the use happens in a later loop iteration than the "
400
+ " %select{forward|move}0" ,
401
+ DiagnosticIDs::Note)
402
+ << IsMove;
380
403
}
381
404
}
382
405
@@ -388,7 +411,9 @@ void UseAfterMoveCheck::registerMatchers(MatchFinder *Finder) {
388
411
auto TryEmplaceMatcher =
389
412
cxxMemberCallExpr (callee (cxxMethodDecl (hasName (" try_emplace" ))));
390
413
auto CallMoveMatcher =
391
- callExpr (argumentCountIs (1 ), callee (functionDecl (hasName (" ::std::move" ))),
414
+ callExpr (argumentCountIs (1 ),
415
+ callee (functionDecl (hasAnyName (" ::std::move" , " ::std::forward" ))
416
+ .bind (" move-decl" )),
392
417
hasArgument (0 , declRefExpr ().bind (" arg" )),
393
418
unless (inDecltypeOrTemplateArg ()),
394
419
unless (hasParent (TryEmplaceMatcher)), expr ().bind (" call-move" ),
@@ -436,6 +461,7 @@ void UseAfterMoveCheck::check(const MatchFinder::MatchResult &Result) {
436
461
const auto *CallMove = Result.Nodes .getNodeAs <CallExpr>(" call-move" );
437
462
const auto *MovingCall = Result.Nodes .getNodeAs <Expr>(" moving-call" );
438
463
const auto *Arg = Result.Nodes .getNodeAs <DeclRefExpr>(" arg" );
464
+ const auto *MoveDecl = Result.Nodes .getNodeAs <FunctionDecl>(" move-decl" );
439
465
440
466
if (!MovingCall || !MovingCall->getExprLoc ().isValid ())
441
467
MovingCall = CallMove;
@@ -470,7 +496,8 @@ void UseAfterMoveCheck::check(const MatchFinder::MatchResult &Result) {
470
496
UseAfterMoveFinder Finder (Result.Context );
471
497
UseAfterMove Use;
472
498
if (Finder.find (CodeBlock, MovingCall, Arg->getDecl (), &Use))
473
- emitDiagnostic (MovingCall, Arg, Use, this , Result.Context );
499
+ emitDiagnostic (MovingCall, Arg, Use, this , Result.Context ,
500
+ determineMoveType (MoveDecl));
474
501
}
475
502
}
476
503
0 commit comments