Edwin Vane fa58b26a50 Stop LoopConvert removing DeclStmts from selection/iteration condition clauses
If the LoopConvert Transform detects an alias for the loop variable, it
attempts to use that name in the resulting range-based for loop while removing
the original DeclStmt for the variable. That removal produced bad code when the
declaration was in the condition of an if, switch, while, or for stmt. This
revision fixes the problem by simply replacing the declaration with a use of
the alias variable.

llvm-svn: 181242
2013-05-06 20:01:43 +00:00

140 lines
3.7 KiB
C++

// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
// RUN: cpp11-migrate -loop-convert %t.cpp -- -I %S/Inputs
// RUN: FileCheck -input-file=%t.cpp %s
#include "structures.h"
const int N = 10;
Val Arr[N];
Val &func(Val &);
void sideEffect(int);
void aliasing() {
// If the loop container is only used for a declaration of a temporary
// variable to hold each element, we can name the new variable for the
// converted range-based loop as the temporary variable's name.
// In the following case, "t" is used as a temporary variable to hold each
// element, and thus we consider the name "t" aliased to the loop.
// The extra blank braces are left as a placeholder for after the variable
// declaration is deleted.
for (int i = 0; i < N; ++i) {
Val &t = Arr[i]; { }
int y = t.x;
}
// CHECK: for (auto & t : Arr)
// CHECK-NOT: Val &{{[a-z_]+}} =
// CHECK-NEXT: { }
// CHECK-NEXT: int y = t.x;
// The container was not only used to initialize a temporary loop variable for
// the container's elements, so we do not alias the new loop variable.
for (int i = 0; i < N; ++i) {
Val &t = Arr[i];
int y = t.x;
int z = Arr[i].x + t.x;
}
// CHECK: for (auto & elem : Arr)
// CHECK-NEXT: Val &t = elem;
// CHECK-NEXT: int y = t.x;
// CHECK-NEXT: int z = elem.x + t.x;
for (int i = 0; i < N; ++i) {
Val t = Arr[i];
int y = t.x;
int z = Arr[i].x + t.x;
}
// CHECK: for (auto & elem : Arr)
// CHECK-NEXT: Val t = elem;
// CHECK-NEXT: int y = t.x;
// CHECK-NEXT: int z = elem.x + t.x;
for (int i = 0; i < N; ++i) {
Val &t = func(Arr[i]);
int y = t.x;
}
// CHECK: for (auto & elem : Arr)
// CHECK-NEXT: Val &t = func(elem);
// CHECK-NEXT: int y = t.x;
int IntArr[N];
for (unsigned i = 0; i < N; ++i) {
if (int alias = IntArr[i]) {
sideEffect(alias);
}
}
// CHECK: for (auto alias : IntArr)
// CHECK-NEXT: if (alias) {
for (unsigned i = 0; i < N; ++i) {
while (int alias = IntArr[i]) {
sideEffect(alias);
}
}
// CHECK: for (auto alias : IntArr)
// CHECK-NEXT: while (alias) {
for (unsigned i = 0; i < N; ++i) {
switch (int alias = IntArr[i]) {
default:
sideEffect(alias);
}
}
// CHECK: for (auto alias : IntArr)
// CHECK-NEXT: switch (alias) {
for (unsigned i = 0; i < N; ++i) {
for (int alias = IntArr[i]; alias < N; ++alias) {
sideEffect(alias);
}
}
// CHECK: for (auto alias : IntArr)
// CHECK-NEXT: for (; alias < N; ++alias) {
for (unsigned i = 0; i < N; ++i) {
for (unsigned j = 0; int alias = IntArr[i]; ++j) {
sideEffect(alias);
}
}
// CHECK: for (auto alias : IntArr)
// CHECK-NEXT: for (unsigned j = 0; alias; ++j) {
}
void refs_and_vals() {
// The following tests check that the transform correctly preserves the
// reference or value qualifiers of the aliased variable. That is, if the
// variable was declared as a value, the loop variable will be declared as a
// value and vice versa for references.
S s;
const S s_const = s;
for (S::const_iterator it = s_const.begin(); it != s_const.end(); ++it) {
MutableVal alias = *it; { }
alias.x = 0;
}
// CHECK: for (auto alias : s_const)
// CHECK-NOT: MutableVal {{[a-z_]+}} =
// CHECK-NEXT: { }
// CHECK-NEXT: alias.x = 0;
for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) {
MutableVal alias = *it; { }
alias.x = 0;
}
// CHECK: for (auto alias : s)
// CHECK-NOT: MutableVal {{[a-z_]+}} =
// CHECK-NEXT: { }
// CHECK-NEXT: alias.x = 0;
for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) {
MutableVal &alias = *it; { }
alias.x = 0;
}
// CHECK: for (auto & alias : s)
// CHECK-NOT: MutableVal &{{[a-z_]+}} =
// CHECK-NEXT: { }
// CHECK-NEXT: alias.x = 0;
}