zinovy.nis updated this revision to Diff 247982.
zinovy.nis added a comment.
1. Special handling for captured variables in lambdas,
2. messages texts were changed.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D74692/new/
https://reviews.llvm.org/D74692
Files:
clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
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
@@ -129,6 +129,16 @@
// CHECK-NOTES: [[@LINE-3]]:15: note: move occurred here
}
+void simpleConst() {
+ const A a;
+ a.foo();
+ A other_a = std::move(a);
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: 'a' used after it was moved; move of a 'const' argument has no effect
+ // CHECK-NOTES: [[@LINE-3]]:15: note: move occurred here
+ // CHECK-NOTES: [[@LINE-6]]:11: note: variable 'a' declared as const here
+}
+
// A warning should only be emitted for one use-after-move.
void onlyFlagOneUseAfterMove() {
A a;
@@ -314,8 +324,21 @@
auto lambda = [a] {
std::move(a);
a.foo();
- // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved; move of a 'const' argument has no effect
// CHECK-NOTES: [[@LINE-3]]:7: note: move occurred here
+ // CHECK-NOTES: [[@LINE-5]]:20: note: variable 'a' captured as const here
+ };
+ }
+ // Use-after-moves inside a lambda should be detected.
+ {
+ A a;
+ // Implicit capture
+ auto lambda = [=] {
+ std::move(a);
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved; move of a 'const' argument has no effect
+ // CHECK-NOTES: [[@LINE-3]]:7: note: move occurred here
+ // CHECK-NOTES: [[@LINE-5]]:20: note: variable 'a' implicitly captured as const here
};
}
// This is just as true if the variable was declared inside the lambda.
@@ -721,14 +744,16 @@
const A a;
std::move(a);
passByConstPointer(&a);
- // CHECK-NOTES: [[@LINE-1]]:25: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-1]]:25: warning: 'a' used after it was moved; move of a 'const' argument has no effect
// CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ // CHECK-NOTES: [[@LINE-5]]:13: note: variable 'a' declared as const here
}
const A a;
std::move(a);
passByConstReference(a);
- // CHECK-NOTES: [[@LINE-1]]:24: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-1]]:24: warning: 'a' used after it was moved; move of a 'const' argument has no effect
// CHECK-NOTES: [[@LINE-3]]:3: note: move occurred here
+ // CHECK-NOTES: [[@LINE-5]]:11: note: variable 'a' declared as const here
}
// Clearing a standard container using clear() is treated as a
Index: clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -375,14 +375,38 @@
}
static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
- const UseAfterMove &Use, ClangTidyCheck *Check,
+ const UseAfterMove &Use,
+ const LambdaExpr *Lambda, ClangTidyCheck *Check,
ASTContext *Context) {
SourceLocation UseLoc = Use.DeclRef->getExprLoc();
SourceLocation MoveLoc = MovingCall->getExprLoc();
+ const bool MoveArgIsConst = MoveArg->getType().isConstQualified();
- Check->diag(UseLoc, "'%0' used after it was moved")
- << MoveArg->getDecl()->getName();
+ Check->diag(UseLoc, "'%0' used after it was moved%select{|; move of a 'const' argument has no effect}1")
+ << MoveArg->getDecl()->getName()
+ << (MoveArgIsConst ? 1 : 0);
Check->diag(MoveLoc, "move occurred here", DiagnosticIDs::Note);
+ if (MoveArgIsConst) {
+ if (Lambda) {
+ for (auto Capture = Lambda->capture_begin(), End = Lambda->capture_end();
+ Capture != End; ++Capture) {
+ if (MoveArg->getDecl() == Capture->getCapturedVar()) {
+ const bool IsExplicitCapture = Capture->isExplicit();
+ Check->diag(
+ IsExplicitCapture ? Capture->getLocation()
+ : Lambda->getCaptureDefaultLoc(),
+ "variable %0 %select{|implicitly}1 captured as const here",
+ DiagnosticIDs::Note)
+ << Capture->getCapturedVar() << (IsExplicitCapture ? 0 : 1);
+ break;
+ }
+ }
+ } else {
+ Check->diag(MoveArg->getDecl()->getLocation(),
+ "variable '%0' declared as const here", DiagnosticIDs::Note);
+ }
+ }
+
if (Use.EvaluationOrderUndefined) {
Check->diag(UseLoc,
"the use and move are unsequenced, i.e. there is no guarantee "
@@ -452,7 +476,7 @@
UseAfterMoveFinder finder(Result.Context);
UseAfterMove Use;
if (finder.find(FunctionBody, MovingCall, Arg->getDecl(), &Use))
- emitDiagnostic(MovingCall, Arg, Use, this, Result.Context);
+ emitDiagnostic(MovingCall, Arg, Use, ContainingLambda, this, Result.Context);
}
} // namespace bugprone
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits