Transferred loop-convert tests to cpp11-migrate

- Turned off -count-only tests as they aren't supported in cpp11-migrate
  yet.
- Updated tests to use new binary name and options to access
  loop-convert transform.
- Fixed header guards to not use restricted names.

Reviewers: klimek, gribozavr
llvm-svn: 171852
This commit is contained in:
Edwin Vane 2013-01-08 14:36:29 +00:00
parent 76c6521ba1
commit 31896624da
16 changed files with 1304 additions and 0 deletions

View File

@ -0,0 +1,14 @@
#ifndef NEGATIVE_HEADER_H
#define NEGATIVE_HEADER_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 // NEGATIVE_HEADER_H

View File

@ -0,0 +1,140 @@
#ifndef STRUCTURES_H
#define 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 // STRUCTURES_H

View File

@ -0,0 +1,155 @@
// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
// RUN: cp %t.cpp %t.base
// RUN: cpp11-migrate -loop-convert %t.cpp -- -I %S/Inputs
// RUN: FileCheck -input-file=%t.cpp %s
// RUN: cp %t.base %t.cpp
// NORUN cpp11-migrate -count-only . %t.cpp -- -I %S/Inputs > %T/out
// NORUN FileCheck -check-prefix=COUNTONLY -input-file=%T/out %s
// RUN: diff %t.cpp %t.base
#include "structures.h"
const int N = 6;
const int NMinusOne = N - 1;
int arr[N] = {1, 2, 3, 4, 5, 6};
int (*pArr)[N] = &arr;
void f() {
int sum = 0;
// Update the number of correctly converted loops as this test changes:
// COUNTONLY: 15 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: }
}
};
// Loops whose bounds are value-dependent shold not be converted.
template<int N>
void dependentExprBound() {
for (int i = 0; i < N; ++i)
arr[i] = 0;
// CHECK: for (int i = 0; i < N; ++i)
// CHECK-NEXT: arr[i] = 0;
}
template void dependentExprBound<20>();
void memberFunctionPointer() {
Val v;
void (Val::*mfpArr[N])(void) = { &Val::g };
for (int i = 0; i < N; ++i)
(v.*mfpArr[i])();
// CHECK: for (auto & [[VAR:[a-z_]+]] : mfpArr)
// CHECK-NEXT: (v.*[[VAR]])();
}

View File

@ -0,0 +1,35 @@
// 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
// RUN: cpp11-migrate -loop-convert %t.cpp -risk=risky -- -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: }
}

View File

@ -0,0 +1,26 @@
// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
// RUN: cpp11-migrate -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: }
}

View File

@ -0,0 +1,103 @@
// 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"
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);
}

View File

@ -0,0 +1,67 @@
// 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;
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: }
}

View File

@ -0,0 +1,160 @@
// 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"
// 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;
}

View File

@ -0,0 +1,64 @@
// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
// RUN: cpp11-migrate -loop-convert -risk=safe %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;
}
}

View File

@ -0,0 +1,29 @@
// 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"
// 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();
}
}

View File

@ -0,0 +1,129 @@
// 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"
// 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];
}

View File

@ -0,0 +1,123 @@
// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/negative-header.h > \
// RUN: %T/negative-header.h
// RUN: cpp11-migrate -loop-convert %t.cpp -- -I %S/Inputs/
// RUN: FileCheck -input-file=%t.cpp %s
// RUN: FileCheck -input-file=%T/negative-header.h %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);
}
}
};

View File

@ -0,0 +1,57 @@
// 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"
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);
}

View File

@ -0,0 +1,21 @@
// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
// RUN: not cpp11-migrate -loop-convert %t.cpp -- -I %S/Inputs
// RUN: FileCheck -input-file=%t.cpp %s
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;

View File

@ -0,0 +1,66 @@
// 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 = 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) ;
}

View File

@ -0,0 +1,115 @@
// 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"
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);
}