Skip to content

Commit 199e523

Browse files
committed
Document a bug in loop-convert and fix one of its subcases.
Summary: Now that we prioritize copying trivial types over using const-references where possible, I found some cases where, after the transformation, the loop was using the address of the local copy instead of the original object. Reviewers: klimek Subscribers: alexfh, cfe-commits Differential Revision: http://reviews.llvm.org/D13431 llvm-svn: 249300
1 parent 72207b1 commit 199e523

File tree

2 files changed

+26
-3
lines changed

2 files changed

+26
-3
lines changed

clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ void LoopConvertCheck::doConversion(
477477
std::string VarName;
478478
bool VarNameFromAlias = (Usages.size() == 1) && AliasDecl;
479479
bool AliasVarIsRef = false;
480+
bool CanCopy = true;
480481

481482
if (VarNameFromAlias) {
482483
const auto *AliasVar = cast<VarDecl>(AliasDecl->getSingleDecl());
@@ -525,6 +526,16 @@ void LoopConvertCheck::doConversion(
525526
// and parenthesis around a simple DeclRefExpr can always be
526527
// removed.
527528
Range = Paren->getSourceRange();
529+
} else if (const auto *UOP = Parents[0].get<UnaryOperator>()) {
530+
// If we are taking the address of the loop variable, then we must
531+
// not use a copy, as it would mean taking the address of the loop's
532+
// local index instead.
533+
// FIXME: This won't catch cases where the address is taken outside
534+
// of the loop's body (for instance, in a function that got the
535+
// loop's index as a const reference parameter), or where we take
536+
// the address of a member (like "&Arr[i].A.B.C").
537+
if (UOP->getOpcode() == UO_AddrOf)
538+
CanCopy = false;
528539
}
529540
}
530541
} else {
@@ -548,8 +559,10 @@ void LoopConvertCheck::doConversion(
548559
// If the new variable name is from the aliased variable, then the reference
549560
// type for the new variable should only be used if the aliased variable was
550561
// declared as a reference.
551-
bool UseCopy = (VarNameFromAlias && !AliasVarIsRef) ||
552-
(Descriptor.DerefByConstRef && Descriptor.IsTriviallyCopyable);
562+
bool UseCopy =
563+
CanCopy &&
564+
((VarNameFromAlias && !AliasVarIsRef) ||
565+
(Descriptor.DerefByConstRef && Descriptor.IsTriviallyCopyable));
553566

554567
if (!UseCopy) {
555568
if (Descriptor.DerefByConstRef) {

clang-tools-extra/test/clang-tidy/modernize-loop-convert-basic.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ void f() {
9797
// CHECK-FIXES-NEXT: Tea.g();
9898
}
9999

100-
void constArray() {
100+
const int *constArray() {
101101
for (int I = 0; I < N; ++I) {
102102
printf("2 * %d = %d\n", ConstArr[I], ConstArr[I] + ConstArr[I]);
103103
}
@@ -112,6 +112,16 @@ void constArray() {
112112
// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
113113
// CHECK-FIXES: for (const auto & Elem : NonCopy)
114114
// CHECK-FIXES-NEXT: printf("2 * %d = %d\n", Elem.X, Elem.X + Elem.X);
115+
116+
bool Something = false;
117+
for (int I = 0; I < N; ++I) {
118+
if (Something)
119+
return &ConstArr[I];
120+
}
121+
// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
122+
// CHECK-FIXES: for (const auto & Elem : ConstArr)
123+
// CHECK-FIXES-NEXT: if (Something)
124+
// CHECK-FIXES-NEXT: return &Elem;
115125
}
116126

117127
struct HasArr {

0 commit comments

Comments
 (0)