[PATCH] D78223: [clang-tidy] performance-range-for-copy only for copy.
Eric Fiselier via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 15 11:30:34 PDT 2020
EricWF created this revision.
EricWF added reviewers: fowles, shuaiwang.
EricWF added a project: clang-tools-extra.
Herald added subscribers: mgehre, xazax.hun.
Currently the range-for-copy incorrectly suggests changing a
by-value loop var to a reference to avoid copies even when:
(1) A converting constructor was used. Or,
(2) The argument to the copy constructor is not an lvalue.
For example:
for (const std::string sv : std::vector<const char*>{}) {
// warning:
// the loop variable's type is not a reference type;
// this creates a copy in each iteration;
// consider making this a reference
}
In these cases we can't actually avoid the copy, and reference
binding + lifetime extending a temporary is not a "fix" we should
be suggesting.
Admittedly, cases like the example should be fixed by the clang-tidy
user, but at minimum we need to be clearer about when a copy is made
and when a user defined conversion occurs (and that conversion may
be semantically important).
Repository:
rCTE Clang Tools Extra
https://reviews.llvm.org/D78223
Files:
clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -1,4 +1,5 @@
// RUN: %check_clang_tidy %s performance-for-range-copy %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s -std=c++17 performance-for-range-copy %t -- -- -fno-delayed-template-parsing
namespace std {
@@ -46,6 +47,7 @@
S &operator=(const S &);
};
+
struct Convertible {
operator S() const {
return S();
@@ -61,12 +63,16 @@
Convertible C[0];
for (const S &S1 : C) {
}
+ for (const S S2 : C) {
+ }
}
void negativeImplicitConstructorConversion() {
ConstructorConvertible C[0];
for (const S &S1 : C) {
}
+ for (const S S2 : C) {
+ }
}
template <typename T>
Index: clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -60,6 +60,18 @@
handleCopyIsOnlyConstReferenced(*Var, *ForRange, *Result.Context);
}
+// Returns true iff the specified variable is initialized via copy construction
+// and the argument to the copy constructor is an lvalue.
+//
+// Note: We don't want to suggest reference binding + lifetime extending a
+// loop index because it's less clear than copying the temporary.
+static bool isCopyConstructedFromLValueArg(const VarDecl &LoopVar, ASTContext& Ctx) {
+ const auto *Init = dyn_cast_or_null<CXXConstructExpr>(LoopVar.getInit());
+ if (!Init || !Init->getConstructor()->isCopyConstructor() || Init->getNumArgs() < 1)
+ return false;
+ return Init->getArg(0)->isLValue();
+}
+
bool ForRangeCopyCheck::handleConstValueCopy(const VarDecl &LoopVar,
ASTContext &Context) {
if (WarnOnAllAutoCopies) {
@@ -73,6 +85,8 @@
utils::type_traits::isExpensiveToCopy(LoopVar.getType(), Context);
if (!Expensive || !*Expensive)
return false;
+ if (!isCopyConstructedFromLValueArg(LoopVar, Context))
+ return false;
auto Diagnostic =
diag(LoopVar.getLocation(),
"the loop variable's type is not a reference type; this creates a "
@@ -93,6 +107,8 @@
utils::type_traits::isExpensiveToCopy(LoopVar.getType(), Context);
if (LoopVar.getType().isConstQualified() || !Expensive || !*Expensive)
return false;
+ if (!isCopyConstructedFromLValueArg(LoopVar, Context))
+ return false;
// We omit the case where the loop variable is not used in the loop body. E.g.
//
// for (auto _ : benchmark_state) {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D78223.257769.patch
Type: text/x-patch
Size: 2827 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200415/f5bfd033/attachment-0001.bin>
More information about the cfe-commits
mailing list