aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorSam Panzer <espanz@gmail.com>2012-08-24 22:10:10 +0000
committerSam Panzer <espanz@gmail.com>2012-08-24 22:10:10 +0000
commit1f4dc0491680daa06f93ef64e00e07c217a73609 (patch)
treee821bc88eb805000267fb7d925a290d4950d7790 /test
parent46499ecc44641e2437a723ab148f8749d3988e46 (diff)
For Loop Conversion
Loop Converter Skeleton - array-step-1 Added a check to loop increments - array-step-2b Added a check on the loop's condition expression - array-step-2c Finished array matcher - array-step-2 Retrieved matched nodes - array-step-3 Analysis for array loop indices - array-step-4 Added checking for naming and variable scope Added confidence level and count-only command line args Added aliased variable elision Added support for iterator-based loops Added support for single-iterator loops which call end() repeatedly Added support for converting array-like containers git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/trunk@162610 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt2
-rw-r--r--test/loop-convert/Inputs/negative-header.h14
-rw-r--r--test/loop-convert/Inputs/structures.h140
-rw-r--r--test/loop-convert/loop-convert-array.cpp135
-rw-r--r--test/loop-convert/loop-convert-confidence.cpp36
-rw-r--r--test/loop-convert/loop-convert-dependency.cpp27
-rw-r--r--test/loop-convert/loop-convert-iterator.cpp106
-rw-r--r--test/loop-convert/loop-convert-naming.cpp68
-rw-r--r--test/loop-convert/loop-convert-negative-iterator.cpp161
-rw-r--r--test/loop-convert/loop-convert-negative-multi-end-call.cpp65
-rw-r--r--test/loop-convert/loop-convert-negative-pseudoarray.cpp130
-rw-r--r--test/loop-convert/loop-convert-negative.cpp125
-rw-r--r--test/loop-convert/loop-convert-nesting.cpp58
-rw-r--r--test/loop-convert/loop-convert-nocompile.cpp23
-rw-r--r--test/loop-convert/loop-convert-pseudoarray.cpp68
-rw-r--r--test/loop-convert/loop-convert-single-iterator.cpp118
-rw-r--r--test/loop-convert/negative-pseudoarray-extra.cpp30
17 files changed, 1305 insertions, 1 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index b93f9514..9c0d1824 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -22,7 +22,7 @@ set(CLANG_TOOLS_TEST_DEPS
clang clang-headers FileCheck count not
# Individual tools we test.
- remove-cstr-calls
+ remove-cstr-calls loop-convert
)
add_lit_testsuite(check-clang-tools "Running the Clang extra tools' regression tests"
diff --git a/test/loop-convert/Inputs/negative-header.h b/test/loop-convert/Inputs/negative-header.h
new file mode 100644
index 00000000..aaa1c9e3
--- /dev/null
+++ b/test/loop-convert/Inputs/negative-header.h
@@ -0,0 +1,14 @@
+#ifndef _CLANG_TOOLS_EXTRA_H_
+#define _CLANG_TOOLS_EXTRA_H_
+
+// Single FileCheck line to make sure that no loops are converted.
+// CHECK-NOT: for ({{.*[^:]:[^:].*}})
+static void loopInHeader() {
+ const int N = 10;
+ int arr[N];
+ int sum = 0;
+ for (int i = 0; i < N; ++i)
+ sum += arr[i];
+}
+
+#endif //_CLANG_TOOLS_EXTRA_H_
diff --git a/test/loop-convert/Inputs/structures.h b/test/loop-convert/Inputs/structures.h
new file mode 100644
index 00000000..412f97ee
--- /dev/null
+++ b/test/loop-convert/Inputs/structures.h
@@ -0,0 +1,140 @@
+#ifndef _LLVM_TOOLS_CLANG_TOOLS_TESTS_TOOLING_STRUCTURES_H_
+#define _LLVM_TOOLS_CLANG_TOOLS_TESTS_TOOLING_STRUCTURES_H_
+
+extern "C" {
+extern int printf(const char *restrict, ...);
+}
+
+struct Val {int x; void g(); };
+
+struct MutableVal {
+ void constFun(int) const;
+ void nonConstFun(int, int);
+ void constFun(MutableVal &) const;
+ void constParamFun(const MutableVal &) const;
+ void nonConstParamFun(const MutableVal &);
+ int x;
+};
+
+struct S {
+ typedef MutableVal *iterator;
+ typedef const MutableVal *const_iterator;
+ const_iterator begin() const;
+ const_iterator end() const;
+ iterator begin();
+ iterator end();
+};
+
+struct T {
+ struct iterator {
+ int& operator*();
+ const int& operator*()const;
+ iterator& operator ++();
+ bool operator!=(const iterator &other);
+ void insert(int);
+ int x;
+ };
+ iterator begin();
+ iterator end();
+};
+
+struct U {
+ struct iterator {
+ Val& operator*();
+ const Val& operator*()const;
+ iterator& operator ++();
+ bool operator!=(const iterator &other);
+ Val *operator->();
+ };
+ iterator begin();
+ iterator end();
+ int x;
+};
+
+struct X {
+ S s;
+ T t;
+ U u;
+ S getS();
+};
+
+template<typename ElemType>
+class dependent{
+ public:
+ struct iterator_base {
+ const ElemType& operator*()const;
+ iterator_base& operator ++();
+ bool operator!=(const iterator_base &other) const;
+ const ElemType *operator->() const;
+ };
+
+ struct iterator : iterator_base {
+ ElemType& operator*();
+ iterator& operator ++();
+ ElemType *operator->();
+ };
+
+ typedef iterator_base const_iterator;
+ const_iterator begin() const;
+ const_iterator end() const;
+ iterator begin();
+ iterator end();
+ unsigned size() const;
+ ElemType & operator[](unsigned);
+ const ElemType & operator[](unsigned) const;
+ ElemType & at(unsigned);
+ const ElemType & at(unsigned) const;
+
+ // Intentionally evil.
+ dependent<ElemType> operator*();
+
+ void foo();
+ void constFoo() const;
+};
+
+template<typename First, typename Second>
+class doublyDependent{
+ public:
+ struct Value {
+ First first;
+ Second second;
+ };
+
+ struct iterator_base {
+ const Value& operator*()const;
+ iterator_base& operator ++();
+ bool operator!=(const iterator_base &other) const;
+ const Value *operator->() const;
+ };
+
+ struct iterator : iterator_base {
+ Value& operator*();
+ Value& operator ++();
+ Value *operator->();
+ };
+
+ typedef iterator_base const_iterator;
+ const_iterator begin() const;
+ const_iterator end() const;
+ iterator begin();
+ iterator end();
+};
+
+template<typename Contained>
+class transparent {
+ public:
+ Contained *at();
+ Contained *operator->();
+ Contained operator*();
+};
+
+template<typename IteratorType>
+struct Nested {
+ typedef IteratorType* iterator;
+ IteratorType *operator->();
+ IteratorType operator*();
+ iterator begin();
+ iterator end();
+};
+
+#endif // _LLVM_TOOLS_CLANG_TOOLS_TESTS_TOOLING_STRUCTURES_H_
diff --git a/test/loop-convert/loop-convert-array.cpp b/test/loop-convert/loop-convert-array.cpp
new file mode 100644
index 00000000..8ba05d01
--- /dev/null
+++ b/test/loop-convert/loop-convert-array.cpp
@@ -0,0 +1,135 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: cp %t.cpp %t.base
+// RUN: loop-convert -count-only . %t.cpp -- -I %S/Inputs > %T/out \
+// RUN: && FileCheck -check-prefix=COUNTONLY -input-file=%T/out %s \
+// RUN: && diff %t.cpp %t.base
+
+const int N = 6;
+const int NMinusOne = N - 1;
+int arr[N] = {1, 2, 3, 4, 5, 6};
+int (*pArr)[N] = &arr;
+#include "structures.h"
+void f() {
+ int sum = 0;
+ // Update the number of correctly converted loops as this test changes:
+ // COUNTONLY: 14 converted
+ // COUNTONLY-NEXT: 0 potentially conflicting
+ // COUNTONLY-NEXT: 0 change(s) rejected
+
+ for (int i = 0; i < N; ++i) {
+ sum += arr[i];
+ int k;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr) {
+ // CHECK-NEXT: sum += [[VAR]];
+ // CHECK-NEXT: int k;
+ // CHECK-NEXT: }
+
+ for (int i = 0; i < N; ++i) {
+ printf("Fibonacci number is %d\n", arr[i]);
+ sum += arr[i] + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+
+ for (int i = 0; i < N; ++i) {
+ int x = arr[i];
+ int y = arr[i] + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr)
+ // CHECK-NEXT: int x = [[VAR]];
+ // CHECK-NEXT: int y = [[VAR]] + 2;
+
+ for (int i = 0; i < N; ++i) {
+ int x = N;
+ x = arr[i];
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr)
+ // CHECK-NEXT: int x = N;
+ // CHECK-NEXT: x = [[VAR]];
+
+ for (int i = 0; i < N; ++i) {
+ arr[i] += 1;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr) {
+ // CHECK-NEXT: [[VAR]] += 1;
+ // CHECK-NEXT: }
+
+ for (int i = 0; i < N; ++i) {
+ int x = arr[i] + 2;
+ arr[i] ++;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr)
+ // CHECK-NEXT: int x = [[VAR]] + 2;
+ // CHECK-NEXT: [[VAR]] ++;
+
+ for (int i = 0; i < N; ++i) {
+ arr[i] = 4 + arr[i];
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr)
+ // CHECK-NEXT: [[VAR]] = 4 + [[VAR]];
+
+ for (int i = 0; i < NMinusOne + 1; ++i) {
+ sum += arr[i];
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr) {
+ // CHECK-NEXT: sum += [[VAR]];
+ // CHECK-NEXT: }
+
+ for (int i = 0; i < N; ++i) {
+ printf("Fibonacci number %d has address %p\n", arr[i], &arr[i]);
+ sum += arr[i] + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr)
+ // CHECK-NEXT: printf("Fibonacci number %d has address %p\n", [[VAR]], &[[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+
+ Val teas[N];
+ for (int i = 0; i < N; ++i) {
+ teas[i].g();
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : teas) {
+ // CHECK-NEXT: [[VAR]].g();
+ // CHECK-NEXT: }
+}
+
+struct HasArr {
+ int Arr[N];
+ Val ValArr[N];
+ void implicitThis() {
+ for (int i = 0; i < N; ++i) {
+ printf("%d", Arr[i]);
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : Arr) {
+ // CHECK-NEXT: printf("%d", [[VAR]]);
+ // CHECK-NEXT: }
+
+ for (int i = 0; i < N; ++i) {
+ printf("%d", ValArr[i].x);
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : ValArr) {
+ // CHECK-NEXT: printf("%d", [[VAR]].x);
+ // CHECK-NEXT: }
+ }
+
+ void explicitThis() {
+ for (int i = 0; i < N; ++i) {
+ printf("%d", this->Arr[i]);
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : this->Arr) {
+ // CHECK-NEXT: printf("%d", [[VAR]]);
+ // CHECK-NEXT: }
+
+ for (int i = 0; i < N; ++i) {
+ printf("%d", this->ValArr[i].x);
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : this->ValArr) {
+ // CHECK-NEXT: printf("%d", [[VAR]].x);
+ // CHECK-NEXT: }
+ }
+};
diff --git a/test/loop-convert/loop-convert-confidence.cpp b/test/loop-convert/loop-convert-confidence.cpp
new file mode 100644
index 00000000..61f6ebe0
--- /dev/null
+++ b/test/loop-convert/loop-convert-confidence.cpp
@@ -0,0 +1,36 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+// RUN: loop-convert . %t.cpp -A2 -- -I %S/Inputs \
+// RUN: && FileCheck -check-prefix=RISKY -input-file=%t.cpp %s
+
+#include "structures.h"
+
+void f() {
+ const int N = 5;
+ const int M = 7;
+ int (*pArr)[N];
+ int Arr[N][M];
+ int sum = 0;
+
+ for (int i = 0; i < M; ++i) {
+ sum += Arr[0][i];
+ }
+ // CHECK: for (int i = 0; i < M; ++i) {
+ // CHECK-NEXT: sum += Arr[0][i];
+ // CHECK-NEXT: }
+ // RISKY: for (auto & [[VAR:[a-z_]+]] : Arr[0]) {
+ // RISKY-NEXT: sum += [[VAR]];
+ // RISKY-NEXT: }
+
+ for (int i = 0; i < N; ++i) {
+ sum += (*pArr)[i];
+ }
+ // RISKY: for (auto & [[VAR:[a-z_]+]] : *pArr) {
+ // RISKY-NEXT: sum += [[VAR]];
+ // RISKY-NEXT: }
+ // CHECK: for (int i = 0; i < N; ++i) {
+ // CHECK-NEXT: sum += (*pArr)[i];
+ // CHECK-NEXT: }
+}
diff --git a/test/loop-convert/loop-convert-dependency.cpp b/test/loop-convert/loop-convert-dependency.cpp
new file mode 100644
index 00000000..2f960052
--- /dev/null
+++ b/test/loop-convert/loop-convert-dependency.cpp
@@ -0,0 +1,27 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- && FileCheck -input-file=%t.cpp %s
+
+void f() {
+ const int N = 6;
+ const int M = 8;
+ int arr[N][M];
+
+ for (int i = 0; i < N; ++i) {
+ int a = 0;
+ int b = arr[i][a];
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr) {
+ // CHECK-NEXT: int a = 0;
+ // CHECK-NEXT: int b = [[VAR]][a];
+ // CHECK-NEXT: }
+
+ for (int j = 0; j < M; ++j) {
+ int a = 0;
+ int b = arr[a][j];
+ }
+ // CHECK: for (int j = 0; j < M; ++j) {
+ // CHECK-NEXT: int a = 0;
+ // CHECK-NEXT: int b = arr[a][j];
+ // CHECK-NEXT: }
+}
diff --git a/test/loop-convert/loop-convert-iterator.cpp b/test/loop-convert/loop-convert-iterator.cpp
new file mode 100644
index 00000000..8f410200
--- /dev/null
+++ b/test/loop-convert/loop-convert-iterator.cpp
@@ -0,0 +1,106 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: rm -rf %t.cpp
+
+#include "structures.h"
+
+void f() {
+ /// begin()/end() - based for loops here:
+ T t;
+ for (T::iterator it = t.begin(), e = t.end(); it != e; ++it) {
+ printf("I found %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]+&? ?}}[[VAR:[a-z_]+]] : t)
+ // CHECK-NEXT: printf("I found %d\n", [[VAR]]);
+
+ T *pt;
+ for (T::iterator it = pt->begin(), e = pt->end(); it != e; ++it) {
+ printf("I found %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]+&? ?}}[[VAR:[a-z_]+]] : *pt)
+ // CHECK-NEXT: printf("I found %d\n", [[VAR]]);
+
+ S s;
+ for (S::const_iterator it = s.begin(), e = s.end(); it != e; ++it) {
+ printf("s has value %d\n", (*it).x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: printf("s has value %d\n", ([[VAR]]).x);
+
+ S *ps;
+ for (S::const_iterator it = ps->begin(), e = ps->end(); it != e; ++it) {
+ printf("s has value %d\n", (*it).x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : *ps)
+ // CHECK-NEXT: printf("s has value %d\n", ([[VAR]]).x);
+
+ for (S::const_iterator it = s.begin(), e = s.end(); it != e; ++it) {
+ printf("s has value %d\n", it->x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: printf("s has value %d\n", [[VAR]].x);
+
+ for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) {
+ it->x = 3;
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: [[VAR]].x = 3;
+
+ for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) {
+ (*it).x = 3;
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: ([[VAR]]).x = 3;
+
+ for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) {
+ it->nonConstFun(4, 5);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: [[VAR]].nonConstFun(4, 5);
+
+ U u;
+ for (U::iterator it = u.begin(), e = u.end(); it != e; ++it) {
+ printf("s has value %d\n", it->x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : u)
+ // CHECK-NEXT: printf("s has value %d\n", [[VAR]].x);
+
+ for (U::iterator it = u.begin(), e = u.end(); it != e; ++it) {
+ printf("s has value %d\n", (*it).x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : u)
+ // CHECK-NEXT: printf("s has value %d\n", ([[VAR]]).x);
+
+ U::iterator A;
+ for (U::iterator i = u.begin(), e = u.end(); i != e; ++i)
+ int k = A->x + i->x;
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : u)
+ // CHECK-NEXT: int k = A->x + [[VAR]].x;
+
+ dependent<int> v;
+ for (dependent<int>::const_iterator it = v.begin(), e = v.end();
+ it != e; ++it) {
+ printf("Fibonacci number is %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : v)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+
+ for (dependent<int>::const_iterator it(v.begin()), e = v.end();
+ it != e; ++it) {
+ printf("Fibonacci number is %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : v)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+
+ doublyDependent<int,int> intmap;
+ for (doublyDependent<int,int>::iterator it = intmap.begin(), e = intmap.end();
+ it != e; ++it) {
+ printf("intmap[%d] = %d", it->first, it->second);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : intmap)
+ // CHECK-NEXT: printf("intmap[%d] = %d", [[VAR]].first, [[VAR]].second);
+
+}
diff --git a/test/loop-convert/loop-convert-naming.cpp b/test/loop-convert/loop-convert-naming.cpp
new file mode 100644
index 00000000..0bfef339
--- /dev/null
+++ b/test/loop-convert/loop-convert-naming.cpp
@@ -0,0 +1,68 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+
+#include "structures.h"
+
+const int N = 10;
+int nums[N];
+int sum = 0;
+
+Val Arr[N];
+Val &func(Val &);
+
+void aliasing() {
+ // 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-NEXT: { }
+ // CHECK-NEXT: int y = 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 & [[VAR:[a-z_]+]] : Arr)
+ // CHECK-NEXT: Val &t = [[VAR]];
+ // CHECK-NEXT: int y = t.x;
+ // CHECK-NEXT: int z = [[VAR]].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 & [[VAR:[a-z_]+]] : Arr)
+ // CHECK-NEXT: Val t = [[VAR]];
+ // CHECK-NEXT: int y = t.x;
+ // CHECK-NEXT: int z = [[VAR]].x + t.x;
+
+ for (int i = 0; i < N; ++i) {
+ Val &t = func(Arr[i]);
+ int y = t.x;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : Arr)
+ // CHECK-NEXT: Val &t = func([[VAR]]);
+ // CHECK-NEXT: int y = t.x;
+}
+
+void sameNames() {
+ int num = 0;
+ for (int i = 0; i < N; ++i) {
+ printf("Fibonacci number is %d\n", nums[i]);
+ sum += nums[i] + 2 + num;
+ (void) nums[i];
+ }
+ // CHECK: int num = 0;
+ // CHECK-NEXT: for (auto & [[VAR:[a-z_]+]] : nums)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2 + num;
+ // CHECK-NOT: (void) num;
+ // CHECK: }
+}
diff --git a/test/loop-convert/loop-convert-negative-iterator.cpp b/test/loop-convert/loop-convert-negative-iterator.cpp
new file mode 100644
index 00000000..041bbee4
--- /dev/null
+++ b/test/loop-convert/loop-convert-negative-iterator.cpp
@@ -0,0 +1,161 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+
+#include "structures.h"
+
+// Single FileCheck line to make sure that no loops are converted.
+// CHECK-NOT: for ({{.*[^:]:[^:].*}})
+
+S s;
+T t;
+U u;
+
+struct BadBeginEnd : T {
+ iterator notBegin();
+ iterator notEnd();
+};
+
+void notBeginOrEnd() {
+ BadBeginEnd Bad;
+ for (T::iterator i = Bad.notBegin(), e = Bad.end(); i != e; ++i)
+ int k = *i;
+
+ for (T::iterator i = Bad.begin(), e = Bad.notEnd(); i != e; ++i)
+ int k = *i;
+}
+
+void badLoopShapes() {
+ for (T::iterator i = t.begin(), e = t.end(), f = e; i != e; ++i)
+ int k = *i;
+
+ for (T::iterator i = t.begin(), e = t.end(); i != e; )
+ int k = *i;
+
+ for (T::iterator i = t.begin(), e = t.end(); ; ++i)
+ int k = *i;
+
+ T::iterator outsideI;
+ T::iterator outsideE;
+
+ for (; outsideI != outsideE ; ++outsideI)
+ int k = *outsideI;
+}
+
+void iteratorArrayMix() {
+ int lower;
+ const int N = 6;
+ for (T::iterator i = t.begin(), e = t.end(); lower < N; ++i)
+ int k = *i;
+
+ for (T::iterator i = t.begin(), e = t.end(); lower < N; ++lower)
+ int k = *i;
+}
+
+struct ExtraConstructor : T::iterator {
+ ExtraConstructor(T::iterator, int);
+ explicit ExtraConstructor(T::iterator);
+};
+
+void badConstructor() {
+ for (T::iterator i = ExtraConstructor(t.begin(), 0), e = t.end();
+ i != e; ++i)
+ int k = *i;
+ for (T::iterator i = ExtraConstructor(t.begin()), e = t.end(); i != e; ++i)
+ int k = *i;
+}
+
+void iteratorMemberUsed() {
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ i.x = *i;
+
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ int k = i.x + *i;
+
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ int k = e.x + *i;
+}
+
+void iteratorMethodCalled() {
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ i.insert(3);
+
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ if (i != i)
+ int k = 3;
+}
+
+void iteratorOperatorCalled() {
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ int k = *(++i);
+
+ for (S::iterator i = s.begin(), e = s.end(); i != e; ++i)
+ MutableVal k = *(++i);
+}
+
+void differentContainers() {
+ T other;
+ for (T::iterator i = t.begin(), e = other.end(); i != e; ++i)
+ int k = *i;
+
+ for (T::iterator i = other.begin(), e = t.end(); i != e; ++i)
+ int k = *i;
+
+ S otherS;
+ for (S::iterator i = s.begin(), e = otherS.end(); i != e; ++i)
+ MutableVal k = *i;
+
+ for (S::iterator i = otherS.begin(), e = s.end(); i != e; ++i)
+ MutableVal k = *i;
+}
+
+void wrongIterators() {
+ T::iterator other;
+ for (T::iterator i = t.begin(), e = t.end(); i != other; ++i)
+ int k = *i;
+}
+
+struct EvilArrow : U {
+ // Please, no one ever write code like this.
+ U* operator->();
+};
+
+void differentMemberAccessTypes() {
+ EvilArrow A;
+ for (EvilArrow::iterator i = A.begin(), e = A->end(); i != e; ++i)
+ Val k = *i;
+ for (EvilArrow::iterator i = A->begin(), e = A.end(); i != e; ++i)
+ Val k = *i;
+}
+
+void f(const T::iterator &it, int);
+void f(const T &it, int);
+void g(T &it, int);
+
+void iteratorPassedToFunction() {
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ f(i, *i);
+}
+
+// FIXME: Disallow this except for containers passed by value and/or const
+// reference. Or maybe this is correct enough for any container?
+void containerPassedToFunction() {
+// for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+// f(t, *i);
+// for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+// g(t, *i);
+}
+
+// FIXME: These tests can be removed if this tool ever does enough analysis to
+// decide that this is a safe transformation.
+// Until then, we don't want it applied.
+void iteratorDefinedOutside() {
+ T::iterator theEnd = t.end();
+ for (T::iterator i = t.begin(); i != theEnd; ++i)
+ int k = *i;
+
+ T::iterator theBegin = t.begin();
+ for (T::iterator e = t.end(); theBegin != e; ++theBegin)
+ int k = *theBegin;
+}
diff --git a/test/loop-convert/loop-convert-negative-multi-end-call.cpp b/test/loop-convert/loop-convert-negative-multi-end-call.cpp
new file mode 100644
index 00000000..cc15ce56
--- /dev/null
+++ b/test/loop-convert/loop-convert-negative-multi-end-call.cpp
@@ -0,0 +1,65 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert -A0 . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+
+#include "structures.h"
+
+// Single FileCheck line to make sure that no loops are converted.
+// CHECK-NOT: for ({{.*[^:]:[^:].*}})
+
+S s;
+T t;
+U u;
+
+void multipleEnd() {
+ for (S::iterator i = s.begin(); i != s.end(); ++i)
+ MutableVal k = *i;
+
+ for (T::iterator i = t.begin(); i != t.end(); ++i)
+ int k = *i;
+
+ for (U::iterator i = u.begin(); i != u.end(); ++i)
+ Val k = *i;
+}
+
+void f(X);
+void f(S);
+void f(T);
+
+void complexContainer() {
+ X x;
+ for (S::iterator i = x.s.begin(), e = x.s.end(); i != e; ++i) {
+ f(x);
+ MutableVal k = *i;
+ }
+
+ for (T::iterator i = x.t.begin(), e = x.t.end(); i != e; ++i) {
+ f(x);
+ int k = *i;
+ }
+
+ for (S::iterator i = x.s.begin(), e = x.s.end(); i != e; ++i) {
+ f(x.s);
+ MutableVal k = *i;
+ }
+
+ for (T::iterator i = x.t.begin(), e = x.t.end(); i != e; ++i) {
+ f(x.t);
+ int k = *i;
+ }
+
+ for (S::iterator i = x.getS().begin(), e = x.getS().end(); i != e; ++i) {
+ f(x.getS());
+ MutableVal k = *i;
+ }
+
+ X exes[5];
+ int index = 0;
+
+ for (S::iterator i = exes[index].getS().begin(),
+ e = exes[index].getS().end(); i != e; ++i) {
+ index++;
+ MutableVal k = *i;
+ }
+}
diff --git a/test/loop-convert/loop-convert-negative-pseudoarray.cpp b/test/loop-convert/loop-convert-negative-pseudoarray.cpp
new file mode 100644
index 00000000..e5b3a1d4
--- /dev/null
+++ b/test/loop-convert/loop-convert-negative-pseudoarray.cpp
@@ -0,0 +1,130 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert -A1 . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+
+#include "structures.h"
+
+// Single FileCheck line to make sure that no loops are converted.
+// CHECK-NOT: for ({{.*[^:]:[^:].*}})
+
+const int N = 6;
+dependent<int> v;
+dependent<int> *pv;
+
+transparent<dependent<int> > cv;
+int sum = 0;
+
+// Checks for the index start and end:
+void indexStartAndEnd() {
+ for (int i = 0; i < v.size() + 1; ++i)
+ sum += v[i];
+
+ for (int i = 0; i < v.size() - 1; ++i)
+ sum += v[i];
+
+ for (int i = 1; i < v.size(); ++i)
+ sum += v[i];
+
+ for (int i = 1; i < v.size(); ++i)
+ sum += v[i];
+
+ for (int i = 0; ; ++i)
+ sum += (*pv)[i];
+}
+
+// Checks for invalid increment steps:
+void increment() {
+ for (int i = 0; i < v.size(); --i)
+ sum += v[i];
+
+ for (int i = 0; i < v.size(); i)
+ sum += v[i];
+
+ for (int i = 0; i < v.size();)
+ sum += v[i];
+
+ for (int i = 0; i < v.size(); i += 2)
+ sum ++;
+}
+
+// Checks to make sure that the index isn't used outside of the container:
+void indexUse() {
+ for (int i = 0; i < v.size(); ++i)
+ v[i] += 1 + i;
+}
+
+// Checks for incorrect loop variables.
+void mixedVariables() {
+ int badIndex;
+ for (int i = 0; badIndex < v.size(); ++i)
+ sum += v[i];
+
+ for (int i = 0; i < v.size(); ++badIndex)
+ sum += v[i];
+
+ for (int i = 0; badIndex < v.size(); ++badIndex)
+ sum += v[i];
+
+ for (int i = 0; badIndex < v.size(); ++badIndex)
+ sum += v[badIndex];
+}
+
+// Checks for an array indexed in addition to the container.
+void multipleArrays() {
+ int badArr[N];
+
+ for (int i = 0; i < v.size(); ++i)
+ sum += v[i] + badArr[i];
+
+ for (int i = 0; i < v.size(); ++i)
+ sum += badArr[i];
+
+ for (int i = 0; i < v.size(); ++i) {
+ int k = badArr[i];
+ sum += k + 2;
+ }
+
+ for (int i = 0; i < v.size(); ++i) {
+ int k = badArr[i];
+ sum += v[i] + k;
+ }
+}
+
+// Checks for multiple containers being indexed container.
+void multipleContainers() {
+ dependent<int> badArr;
+
+ for (int i = 0; i < v.size(); ++i)
+ sum += v[i] + badArr[i];
+
+ for (int i = 0; i < v.size(); ++i)
+ sum += badArr[i];
+
+ for (int i = 0; i < v.size(); ++i) {
+ int k = badArr[i];
+ sum += k + 2;
+ }
+
+ for (int i = 0; i < v.size(); ++i) {
+ int k = badArr[i];
+ sum += v[i] + k;
+ }
+}
+
+// Check to make sure that dereferenced pointers-to-containers behave nicely
+void derefContainer() {
+ // Note the dependent<T>::operator*() returns another dependent<T>.
+ // This test makes sure that we don't allow an arbitrary number of *'s.
+ for (int i = 0; i < pv->size(); ++i)
+ sum += (**pv).at(i);
+
+ for (int i = 0; i < pv->size(); ++i)
+ sum += (**pv)[i];
+}
+
+void wrongEnd() {
+ int bad;
+ for (int i = 0, e = v.size(); i < bad; ++i)
+ sum += v[i];
+}
diff --git a/test/loop-convert/loop-convert-negative.cpp b/test/loop-convert/loop-convert-negative.cpp
new file mode 100644
index 00000000..55975572
--- /dev/null
+++ b/test/loop-convert/loop-convert-negative.cpp
@@ -0,0 +1,125 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %S/Inputs/negative-header.h > \
+// RUN: %T/negative-header.h
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs/ \
+// RUN: && FileCheck -input-file=%t.cpp %s \
+// RUN: && FileCheck -input-file=%T/negative-header.h \
+// RUN: %S/Inputs/negative-header.h
+
+#include "negative-header.h"
+#include "structures.h"
+
+// Single FileCheck line to make sure that no loops are converted.
+// CHECK-NOT: for ({{.*[^:]:[^:].*}})
+
+const int N = 6;
+int arr[N] = {1, 2, 3, 4, 5, 6};
+int (*pArr)[N] = &arr;
+int sum = 0;
+
+// Checks for the index start and end:
+void indexStartAndEnd() {
+ for (int i = 0; i < N + 1; ++i)
+ sum += arr[i];
+
+ for (int i = 0; i < N - 1; ++i)
+ sum += arr[i];
+
+ for (int i = 1; i < N; ++i)
+ sum += arr[i];
+
+ for (int i = 1; i < N; ++i)
+ sum += arr[i];
+
+ for (int i = 0; ; ++i)
+ sum += (*pArr)[i];
+}
+
+// Checks for invalid increment steps:
+void increment() {
+ for (int i = 0; i < N; --i)
+ sum += arr[i];
+
+ for (int i = 0; i < N; i)
+ sum += arr[i];
+
+ for (int i = 0; i < N;)
+ sum += arr[i];
+
+ for (int i = 0; i < N; i += 2)
+ sum ++;
+}
+
+// Checks to make sure that the index isn't used outside of the array:
+void indexUse() {
+ for (int i = 0; i < N; ++i)
+ arr[i] += 1 + i;
+}
+
+// Check for loops that don't mention arrays
+void noArray() {
+ for (int i = 0; i < N; ++i)
+ sum += i;
+
+ for (int i = 0; i < N; ++i) { }
+
+ for (int i = 0; i < N; ++i) ;
+}
+
+// Checks for incorrect loop variables.
+void mixedVariables() {
+ int badIndex;
+ for (int i = 0; badIndex < N; ++i)
+ sum += arr[i];
+
+ for (int i = 0; i < N; ++badIndex)
+ sum += arr[i];
+
+ for (int i = 0; badIndex < N; ++badIndex)
+ sum += arr[i];
+
+ for (int i = 0; badIndex < N; ++badIndex)
+ sum += arr[badIndex];
+}
+
+// Checks for multiple arrays indexed.
+void multipleArrays() {
+ int badArr[N];
+
+ for (int i = 0; i < N; ++i)
+ sum += arr[i] + badArr[i];
+
+ for (int i = 0; i < N; ++i) {
+ int k = badArr[i];
+ sum += arr[i] + k;
+ }
+}
+
+struct HasArr {
+ int Arr[N];
+ Val ValArr[N];
+};
+
+struct HasIndirectArr {
+ HasArr HA;
+ void implicitThis() {
+ for (int i = 0; i < N; ++i) {
+ printf("%d", HA.Arr[i]);
+ }
+
+ for (int i = 0; i < N; ++i) {
+ printf("%d", HA.ValArr[i].x);
+ }
+ }
+
+ void explicitThis() {
+ for (int i = 0; i < N; ++i) {
+ printf("%d", this->HA.Arr[i]);
+ }
+
+ for (int i = 0; i < N; ++i) {
+ printf("%d", this->HA.ValArr[i].x);
+ }
+ }
+};
diff --git a/test/loop-convert/loop-convert-nesting.cpp b/test/loop-convert/loop-convert-nesting.cpp
new file mode 100644
index 00000000..8e960a89
--- /dev/null
+++ b/test/loop-convert/loop-convert-nesting.cpp
@@ -0,0 +1,58 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+
+#include "structures.h"
+
+void f() {
+ const int N = 10;
+ const int M = 15;
+ Val Arr[N];
+ for (int i = 0; i < N; ++i) {
+ for (int j = 0; j < N; ++j) {
+ int k = Arr[i].x + Arr[j].x;
+ // The repeat is there to allow FileCheck to make sure the two variable
+ // names aren't the same.
+ int l = Arr[i].x + Arr[j].x;
+ }
+ }
+ // CHECK: for (auto & [[VAR:[a-zA-Z_]+]] : Arr)
+ // CHECK-NEXT: for (auto & [[INNERVAR:[a-zA-Z_]+]] : Arr)
+ // CHECK-NEXT: int k = [[VAR]].x + [[INNERVAR]].x;
+ // CHECK-NOT: int l = [[VAR]].x + [[VAR]].x;
+
+ Val Nest[N][M];
+ for (int i = 0; i < N; ++i) {
+ for (int j = 0; j < M; ++j) {
+ printf("Got item %d", Nest[i][j].x);
+ }
+ }
+ // The inner loop is also convertible, but doesn't need to be converted
+ // immediately. Update this test when that changes!
+ // CHECK: for (auto & [[VAR:[a-zA-Z_]+]] : Nest)
+ // CHECK-NEXT: for (int j = 0; j < M; ++j)
+ // CHECK-NEXT: printf("Got item %d", [[VAR]][j].x);
+
+ // Note that the order of M and N are switched for this test.
+ for (int j = 0; j < M; ++j) {
+ for (int i = 0; i < N; ++i) {
+ printf("Got item %d", Nest[i][j].x);
+ }
+ }
+ // CHECK-NOT: for (auto & {{[a-zA-Z_]+}} : Nest[i])
+ // CHECK: for (int j = 0; j < M; ++j)
+ // CHECK-NEXT: for (auto & [[VAR:[a-zA-Z_]+]] : Nest)
+ // CHECK-NEXT: printf("Got item %d", [[VAR]][j].x);
+ Nested<T> NestT;
+ for (Nested<T>::iterator I = NestT.begin(), E = NestT.end(); I != E; ++I) {
+ for (T::iterator TI = (*I).begin(), TE = (*I).end(); TI != TE; ++TI) {
+ printf("%d", *TI);
+ }
+ }
+ // The inner loop is also convertible, but doesn't need to be converted
+ // immediately. Update this test when that changes!
+ // CHECK: for (auto & [[VAR:[a-zA-Z_]+]] : NestT) {
+ // CHECK-NEXT: for (T::iterator TI = ([[VAR]]).begin(), TE = ([[VAR]]).end(); TI != TE; ++TI) {
+ // CHECK-NEXT: printf("%d", *TI);
+}
diff --git a/test/loop-convert/loop-convert-nocompile.cpp b/test/loop-convert/loop-convert-nocompile.cpp
new file mode 100644
index 00000000..32390102
--- /dev/null
+++ b/test/loop-convert/loop-convert-nocompile.cpp
@@ -0,0 +1,23 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: || FileCheck -input-file=%t.cpp %s
+// Note that this test expects the compilation to fail!
+
+void valid() {
+ const int arr[5];
+ int sum = 0;
+ for (int i = 0; i < 5; ++i) {
+ sum += arr[i];
+ }
+}
+void hasSyntaxError = 3;
+// CHECK: void valid() {
+// CHECK-NEXT: const int arr[5];
+// CHECK-NEXT: int sum = 0;
+// CHECK-NEXT: for (int i = 0; i < 5; ++i) {
+// CHECK-NEXT: sum += arr[i];
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+
+// CHECK-NEXT: void hasSyntaxError = 3;
diff --git a/test/loop-convert/loop-convert-pseudoarray.cpp b/test/loop-convert/loop-convert-pseudoarray.cpp
new file mode 100644
index 00000000..b47616d0
--- /dev/null
+++ b/test/loop-convert/loop-convert-pseudoarray.cpp
@@ -0,0 +1,68 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+// RUN: rm -rf %t.cpp
+#include "structures.h"
+
+const int N = 6;
+dependent<int> v;
+dependent<int> *pv;
+
+transparent<dependent<int> > cv;
+
+void f() {
+ int sum = 0;
+ for (int i = 0, e = v.size(); i < e; ++i) {
+ printf("Fibonacci number is %d\n", v[i]);
+ sum += v[i] + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : v)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+
+ for (int i = 0, e = v.size(); i < e; ++i) {
+ printf("Fibonacci number is %d\n", v.at(i));
+ sum += v.at(i) + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : v)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+
+ for (int i = 0, e = pv->size(); i < e; ++i) {
+ printf("Fibonacci number is %d\n", pv->at(i));
+ sum += pv->at(i) + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : *pv)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+
+ // This test will fail if size() isn't called repeatedly, since it
+ // returns unsigned int, and 0 is deduced to be signed int.
+ // FIXME: Insert the necessary explicit conversion, or write out the types
+ // explicitly.
+ for (int i = 0; i < pv->size(); ++i) {
+ printf("Fibonacci number is %d\n", (*pv).at(i));
+ sum += (*pv)[i] + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : *pv)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+
+ for (int i = 0; i < cv->size(); ++i) {
+ printf("Fibonacci number is %d\n", cv->at(i));
+ sum += cv->at(i) + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : *cv)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+}
+
+// Check for loops that don't mention containers
+void noContainer() {
+ for (auto i = 0; i < v.size(); ++i) { }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : v) { }
+
+ for (auto i = 0; i < v.size(); ++i) ;
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : v) ;
+}
diff --git a/test/loop-convert/loop-convert-single-iterator.cpp b/test/loop-convert/loop-convert-single-iterator.cpp
new file mode 100644
index 00000000..2359a3ac
--- /dev/null
+++ b/test/loop-convert/loop-convert-single-iterator.cpp
@@ -0,0 +1,118 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: rm -rf %t.cpp
+
+#include "structures.h"
+
+void complexContainer() {
+ X exes[5];
+ int index = 0;
+
+ for (S::iterator i = exes[index].getS().begin(), e = exes[index].getS().end(); i != e; ++i) {
+ MutableVal k = *i;
+ MutableVal j = *i;
+ }
+ // CHECK: for ({{[a-zA-Z_ ]+&? ?}}[[VAR:[a-z_]+]] : exes[index].getS())
+ // CHECK-NEXT: MutableVal k = [[VAR]];
+ // CHECK-NEXT: MutableVal j = [[VAR]];
+}
+
+void f() {
+ /// begin()/end() - based for loops here:
+ T t;
+ for (T::iterator it = t.begin(); it != t.end(); ++it) {
+ printf("I found %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]+&? ?}}[[VAR:[a-z_]+]] : t)
+ // CHECK-NEXT: printf("I found %d\n", [[VAR]]);
+
+ T *pt;
+ for (T::iterator it = pt->begin(); it != pt->end(); ++it) {
+ printf("I found %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]+&? ?}}[[VAR:[a-z_]+]] : *pt)
+ // CHECK-NEXT: printf("I found %d\n", [[VAR]]);
+
+ S s;
+ for (S::const_iterator it = s.begin(); it != s.end(); ++it) {
+ printf("s has value %d\n", (*it).x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: printf("s has value %d\n", ([[VAR]]).x);
+
+ S *ps;
+ for (S::const_iterator it = ps->begin(); it != ps->end(); ++it) {
+ printf("s has value %d\n", (*it).x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : *ps)
+ // CHECK-NEXT: printf("s has value %d\n", ([[VAR]]).x);
+
+ for (S::const_iterator it = s.begin(); it != s.end(); ++it) {
+ printf("s has value %d\n", it->x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: printf("s has value %d\n", [[VAR]].x);
+
+ for (S::iterator it = s.begin(); it != s.end(); ++it) {
+ it->x = 3;
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: [[VAR]].x = 3;
+
+ for (S::iterator it = s.begin(); it != s.end(); ++it) {
+ (*it).x = 3;
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: ([[VAR]]).x = 3;
+
+ for (S::iterator it = s.begin(); it != s.end(); ++it) {
+ it->nonConstFun(4, 5);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: [[VAR]].nonConstFun(4, 5);
+
+ U u;
+ for (U::iterator it = u.begin(); it != u.end(); ++it) {
+ printf("s has value %d\n", it->x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : u)
+ // CHECK-NEXT: printf("s has value %d\n", [[VAR]].x);
+
+ for (U::iterator it = u.begin(); it != u.end(); ++it) {
+ printf("s has value %d\n", (*it).x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : u)
+ // CHECK-NEXT: printf("s has value %d\n", ([[VAR]]).x);
+
+ U::iterator A;
+ for (U::iterator i = u.begin(); i != u.end(); ++i)
+ int k = A->x + i->x;
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : u)
+ // CHECK-NEXT: int k = A->x + [[VAR]].x;
+
+ dependent<int> v;
+ for (dependent<int>::const_iterator it = v.begin();
+ it != v.end(); ++it) {
+ printf("Fibonacci number is %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : v)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+
+ for (dependent<int>::const_iterator it(v.begin());
+ it != v.end(); ++it) {
+ printf("Fibonacci number is %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : v)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+
+ doublyDependent<int,int> intmap;
+ for (doublyDependent<int,int>::iterator it = intmap.begin();
+ it != intmap.end(); ++it) {
+ printf("intmap[%d] = %d", it->first, it->second);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : intmap)
+ // CHECK-NEXT: printf("intmap[%d] = %d", [[VAR]].first, [[VAR]].second);
+}
diff --git a/test/loop-convert/negative-pseudoarray-extra.cpp b/test/loop-convert/negative-pseudoarray-extra.cpp
new file mode 100644
index 00000000..224a87bf
--- /dev/null
+++ b/test/loop-convert/negative-pseudoarray-extra.cpp
@@ -0,0 +1,30 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert -A1 . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+
+#include "structures.h"
+
+// Single FileCheck line to make sure that no loops are converted.
+// CHECK-NOT: for ({{.*[^:]:[^:].*}})
+
+const int N = 6;
+dependent<int> v;
+dependent<int> *pv;
+
+int sum = 0;
+
+// Checks to see that non-const member functions are not called on the container
+// object.
+// These could be conceivably allowed with a lower required confidence level.
+void memberFunctionCalled() {
+ for (int i = 0; i < v.size(); ++i) {
+ sum += v[i];
+ v.foo();
+ }
+
+ for (int i = 0; i < v.size(); ++i) {
+ sum += v[i];
+ dependent<int>::iterator it = v.begin();
+ }
+}