forked from OSchip/llvm-project
Transform for loops over pseudo-arrays only if begin/end members exist
For loops using pseudo-arrays, classes that can be used like arrays from the Loop Convert Transform's point of view, should only get transformed if the pseudo-array class has begin()/end() members for the range-based for-loop to call. Free versions of begin()/end() should also be allowed but this is an enhancement for another revision. llvm-svn: 181539
This commit is contained in:
parent
acbb1a5db5
commit
b40bf83eab
|
@ -258,10 +258,57 @@ StatementMatcher makeIteratorLoopMatcher() {
|
||||||
/// - If the end iterator variable 'g' is defined, it is the same as 'j'
|
/// - If the end iterator variable 'g' is defined, it is the same as 'j'
|
||||||
/// - The container's iterators would not be invalidated during the loop
|
/// - The container's iterators would not be invalidated during the loop
|
||||||
StatementMatcher makePseudoArrayLoopMatcher() {
|
StatementMatcher makePseudoArrayLoopMatcher() {
|
||||||
|
// Test that the incoming type has a record declaration that has methods
|
||||||
|
// called 'begin' and 'end'. If the incoming type is const, then make sure
|
||||||
|
// these methods are also marked const.
|
||||||
|
//
|
||||||
|
// FIXME: To be completely thorough this matcher should also ensure the
|
||||||
|
// return type of begin/end is an iterator that dereferences to the same as
|
||||||
|
// what operator[] or at() returns. Such a test isn't likely to fail except
|
||||||
|
// for pathological cases.
|
||||||
|
//
|
||||||
|
// FIXME: Also, a record doesn't necessarily need begin() and end(). Free
|
||||||
|
// functions called begin() and end() taking the container as an argument
|
||||||
|
// are also allowed.
|
||||||
|
TypeMatcher RecordWithBeginEnd =
|
||||||
|
qualType(anyOf(
|
||||||
|
qualType(
|
||||||
|
isConstQualified(),
|
||||||
|
hasDeclaration(
|
||||||
|
recordDecl(
|
||||||
|
hasMethod(
|
||||||
|
methodDecl(
|
||||||
|
hasName("begin"),
|
||||||
|
isConst()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
hasMethod(
|
||||||
|
methodDecl(
|
||||||
|
hasName("end"),
|
||||||
|
isConst()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) // hasDeclaration
|
||||||
|
), // qualType
|
||||||
|
qualType(
|
||||||
|
unless(isConstQualified()),
|
||||||
|
hasDeclaration(
|
||||||
|
recordDecl(
|
||||||
|
hasMethod(hasName("begin")),
|
||||||
|
hasMethod(hasName("end"))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) // qualType
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
StatementMatcher SizeCallMatcher =
|
StatementMatcher SizeCallMatcher =
|
||||||
memberCallExpr(argumentCountIs(0),
|
memberCallExpr(argumentCountIs(0),
|
||||||
callee(methodDecl(anyOf(hasName("size"),
|
callee(methodDecl(anyOf(hasName("size"),
|
||||||
hasName("length")))));
|
hasName("length")))),
|
||||||
|
on(anyOf(hasType(pointsTo(RecordWithBeginEnd)),
|
||||||
|
hasType(RecordWithBeginEnd))));
|
||||||
|
|
||||||
StatementMatcher EndInitMatcher =
|
StatementMatcher EndInitMatcher =
|
||||||
expr(anyOf(
|
expr(anyOf(
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
|
||||||
|
// RUN: cpp11-migrate -loop-convert %t.cpp -- -I %S/Inputs -std=c++11
|
||||||
|
// RUN: FileCheck -input-file=%t.cpp %s
|
||||||
|
// XFAIL: *
|
||||||
|
|
||||||
|
struct MyArray {
|
||||||
|
unsigned size();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct MyContainer {
|
||||||
|
};
|
||||||
|
|
||||||
|
int *begin(const MyArray &Arr);
|
||||||
|
int *end(const MyArray &Arr);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T *begin(const MyContainer<T> &C);
|
||||||
|
template <typename T>
|
||||||
|
T *end(const MyContainer<T> &C);
|
||||||
|
|
||||||
|
// The Loop Convert Transform doesn't detect free functions begin()/end() and
|
||||||
|
// so fails to transform these cases which it should.
|
||||||
|
void f() {
|
||||||
|
MyArray Arr;
|
||||||
|
for (unsigned i = 0, e = Arr.size(); i < e; ++i) {}
|
||||||
|
// CHECK: for (auto & elem : Arr) {}
|
||||||
|
|
||||||
|
MyContainer<int> C;
|
||||||
|
for (int *I = begin(C), *E = end(C); I != E; ++I) {}
|
||||||
|
// CHECK: for (auto & elem : C) {}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
|
// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
|
||||||
// RUN: cpp11-migrate -loop-convert %t.cpp -- -I %S/Inputs
|
// RUN: cpp11-migrate -loop-convert %t.cpp -- -I %S/Inputs -std=c++11
|
||||||
// RUN: FileCheck -input-file=%t.cpp %s
|
// RUN: FileCheck -input-file=%t.cpp %s
|
||||||
#include "structures.h"
|
#include "structures.h"
|
||||||
|
|
||||||
|
@ -64,3 +64,42 @@ void noContainer() {
|
||||||
for (auto i = 0; i < v.size(); ++i) ;
|
for (auto i = 0; i < v.size(); ++i) ;
|
||||||
// CHECK: for (auto & elem : v) ;
|
// CHECK: for (auto & elem : v) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct NoBeginEnd {
|
||||||
|
unsigned size() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NoConstBeginEnd {
|
||||||
|
NoConstBeginEnd();
|
||||||
|
unsigned size() const;
|
||||||
|
unsigned begin();
|
||||||
|
unsigned end();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConstBeginEnd {
|
||||||
|
ConstBeginEnd();
|
||||||
|
unsigned size() const;
|
||||||
|
unsigned begin() const;
|
||||||
|
unsigned end() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Shouldn't transform pseudo-array uses if the container doesn't provide
|
||||||
|
// begin() and end() of the right const-ness.
|
||||||
|
void NoBeginEndTest() {
|
||||||
|
NoBeginEnd NBE;
|
||||||
|
for (unsigned i = 0, e = NBE.size(); i < e; ++i) {}
|
||||||
|
// CHECK: for (unsigned i = 0, e = NBE.size(); i < e; ++i) {}
|
||||||
|
|
||||||
|
const NoConstBeginEnd const_NCBE;
|
||||||
|
for (unsigned i = 0, e = const_NCBE.size(); i < e; ++i) {}
|
||||||
|
// CHECK: for (unsigned i = 0, e = const_NCBE.size(); i < e; ++i) {}
|
||||||
|
|
||||||
|
ConstBeginEnd CBE;
|
||||||
|
for (unsigned i = 0, e = CBE.size(); i < e; ++i) {}
|
||||||
|
// CHECK: for (auto & elem : CBE) {}
|
||||||
|
|
||||||
|
const ConstBeginEnd const_CBE;
|
||||||
|
for (unsigned i = 0, e = const_CBE.size(); i < e; ++i) {}
|
||||||
|
// CHECK: for (auto & elem : const_CBE) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue