diff options
author | Sam Panzer <espanz@gmail.com> | 2012-08-24 22:10:10 +0000 |
---|---|---|
committer | Sam Panzer <espanz@gmail.com> | 2012-08-24 22:10:10 +0000 |
commit | 1f4dc0491680daa06f93ef64e00e07c217a73609 (patch) | |
tree | e821bc88eb805000267fb7d925a290d4950d7790 /test | |
parent | 46499ecc44641e2437a723ab148f8749d3988e46 (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.txt | 2 | ||||
-rw-r--r-- | test/loop-convert/Inputs/negative-header.h | 14 | ||||
-rw-r--r-- | test/loop-convert/Inputs/structures.h | 140 | ||||
-rw-r--r-- | test/loop-convert/loop-convert-array.cpp | 135 | ||||
-rw-r--r-- | test/loop-convert/loop-convert-confidence.cpp | 36 | ||||
-rw-r--r-- | test/loop-convert/loop-convert-dependency.cpp | 27 | ||||
-rw-r--r-- | test/loop-convert/loop-convert-iterator.cpp | 106 | ||||
-rw-r--r-- | test/loop-convert/loop-convert-naming.cpp | 68 | ||||
-rw-r--r-- | test/loop-convert/loop-convert-negative-iterator.cpp | 161 | ||||
-rw-r--r-- | test/loop-convert/loop-convert-negative-multi-end-call.cpp | 65 | ||||
-rw-r--r-- | test/loop-convert/loop-convert-negative-pseudoarray.cpp | 130 | ||||
-rw-r--r-- | test/loop-convert/loop-convert-negative.cpp | 125 | ||||
-rw-r--r-- | test/loop-convert/loop-convert-nesting.cpp | 58 | ||||
-rw-r--r-- | test/loop-convert/loop-convert-nocompile.cpp | 23 | ||||
-rw-r--r-- | test/loop-convert/loop-convert-pseudoarray.cpp | 68 | ||||
-rw-r--r-- | test/loop-convert/loop-convert-single-iterator.cpp | 118 | ||||
-rw-r--r-- | test/loop-convert/negative-pseudoarray-extra.cpp | 30 |
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(); + } +} |