// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp // RUN: clang-modernize -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; }