[clang-tools-extra] r181528 - Use 'auto const&' for iterators whose deref operator return a const var
Ariel J. Bernal
ariel.j.bernal at intel.com
Thu May 9 10:46:20 PDT 2013
Author: ajbernal
Date: Thu May 9 12:46:20 2013
New Revision: 181528
URL: http://llvm.org/viewvc/llvm-project?rev=181528&view=rev
Log:
Use 'auto const&' for iterators whose deref operator return a const var
This patch fixes PR15601.
- Added check for whether the loop variable and the initializer have the same
type.
- Added tests.
Modified:
clang-tools-extra/trunk/cpp11-migrate/AddOverride/AddOverrideActions.cpp
clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopActions.cpp
clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopActions.h
clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopMatchers.cpp
clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopMatchers.h
clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/Inputs/structures.h
clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/iterator.cpp
clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/naming-conflict.cpp
clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/nesting.cpp
clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/single-iterator.cpp
Modified: clang-tools-extra/trunk/cpp11-migrate/AddOverride/AddOverrideActions.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/AddOverride/AddOverrideActions.cpp?rev=181528&r1=181527&r2=181528&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/AddOverride/AddOverrideActions.cpp (original)
+++ clang-tools-extra/trunk/cpp11-migrate/AddOverride/AddOverrideActions.cpp Thu May 9 12:46:20 2013
@@ -32,6 +32,10 @@ void AddOverrideFixer::run(const MatchFi
const CXXMethodDecl *M = Result.Nodes.getDeclAs<CXXMethodDecl>(MethodId);
assert(M && "Bad Callback. No node provided");
+ // Check that the method declaration in the main file
+ if (!SM.isFromMainFile(M->getLocStart()))
+ return;
+
// First check that there isn't already an override attribute.
if (!M->hasAttr<OverrideAttr>()) {
if (M->getLocStart().isFileID()) {
Modified: clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopActions.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopActions.cpp?rev=181528&r1=181527&r2=181528&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopActions.cpp (original)
+++ clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopActions.cpp Thu May 9 12:46:20 2013
@@ -791,7 +791,8 @@ void LoopFixer::doConversion(ASTContext
bool AliasFromForInit,
const ForStmt *TheLoop,
bool ContainerNeedsDereference,
- bool DerefByValue) {
+ bool DerefByValue,
+ bool DerefByConstRef) {
std::string VarName;
bool VarNameFromAlias = Usages.size() == 1 && AliasDecl;
bool AliasVarIsRef = false;
@@ -849,8 +850,11 @@ void LoopFixer::doConversion(ASTContext
// to 'T&&'.
if (DerefByValue)
AutoRefType = Context->getRValueReferenceType(AutoRefType);
- else
+ else {
+ if (DerefByConstRef)
+ AutoRefType = Context->getConstType(AutoRefType);
AutoRefType = Context->getLValueReferenceType(AutoRefType);
+ }
}
std::string MaybeDereference = ContainerNeedsDereference ? "*" : "";
@@ -979,6 +983,7 @@ void LoopFixer::findAndVerifyUsages(ASTC
const Expr *BoundExpr,
bool ContainerNeedsDereference,
bool DerefByValue,
+ bool DerefByConstRef,
const ForStmt *TheLoop,
Confidence ConfidenceLevel) {
ForLoopIndexUseVisitor Finder(Context, LoopVar, EndVar, ContainerExpr,
@@ -1013,7 +1018,7 @@ void LoopFixer::findAndVerifyUsages(ASTC
doConversion(Context, LoopVar, getReferencedVariable(ContainerExpr),
ContainerString, Finder.getUsages(), Finder.getAliasDecl(),
Finder.aliasUseRequired(), Finder.aliasFromForInit(), TheLoop,
- ContainerNeedsDereference, DerefByValue);
+ ContainerNeedsDereference, DerefByValue, DerefByConstRef);
++*AcceptedChanges;
}
@@ -1051,14 +1056,67 @@ void LoopFixer::run(const MatchFinder::M
ConfidenceLevel.lowerTo(RL_Reasonable);
const Expr *ContainerExpr = NULL;
+ bool DerefByValue = false;
+ bool DerefByConstRef = false;
bool ContainerNeedsDereference = false;
// FIXME: Try to put most of this logic inside a matcher. Currently, matchers
// don't allow the right-recursive checks in digThroughConstructors.
- if (FixerKind == LFK_Iterator)
+ if (FixerKind == LFK_Iterator) {
ContainerExpr = findContainer(Context, LoopVar->getInit(),
EndVar ? EndVar->getInit() : EndCall,
&ContainerNeedsDereference);
- else if (FixerKind == LFK_PseudoArray) {
+
+ QualType InitVarType = InitVar->getType();
+ QualType CanonicalInitVarType = InitVarType.getCanonicalType();
+
+ const CXXMemberCallExpr *BeginCall =
+ Nodes.getNodeAs<CXXMemberCallExpr>(BeginCallName);
+ assert(BeginCall != 0 && "Bad Callback. No begin call expression.");
+ QualType CanonicalBeginType =
+ BeginCall->getMethodDecl()->getResultType().getCanonicalType();
+
+ if (CanonicalBeginType->isPointerType() &&
+ CanonicalInitVarType->isPointerType()) {
+ QualType BeginPointeeType = CanonicalBeginType->getPointeeType();
+ QualType InitPointeeType = CanonicalInitVarType->getPointeeType();
+ // If the initializer and the variable are both pointers check if the
+ // un-qualified pointee types match otherwise we don't use auto.
+ if (!Context->hasSameUnqualifiedType(InitPointeeType, BeginPointeeType))
+ return;
+ } else {
+ // Check for qualified types to avoid conversions from non-const to const
+ // iterator types.
+ if (!Context->hasSameType(CanonicalInitVarType, CanonicalBeginType))
+ return;
+ }
+
+ DerefByValue = Nodes.getNodeAs<QualType>(DerefByValueResultName) != 0;
+ if (!DerefByValue) {
+ if (const QualType *DerefType =
+ Nodes.getNodeAs<QualType>(DerefByRefResultName)) {
+ // A node will only be bound with DerefByRefResultName if we're dealing
+ // with a user-defined iterator type. Test the const qualification of
+ // the reference type.
+ DerefByConstRef = (*DerefType)->getAs<ReferenceType>()->getPointeeType()
+ .isConstQualified();
+ } else {
+ // By nature of the matcher this case is triggered only for built-in
+ // iterator types (i.e. pointers).
+ assert(isa<PointerType>(CanonicalInitVarType) &&
+ "Non-class iterator type is not a pointer type");
+ QualType InitPointeeType = CanonicalInitVarType->getPointeeType();
+ QualType BeginPointeeType = CanonicalBeginType->getPointeeType();
+ // If the initializer and variable have both the same type just use auto
+ // otherwise we test for const qualification of the pointed-at type.
+ if (!Context->hasSameType(InitPointeeType, BeginPointeeType))
+ DerefByConstRef = InitPointeeType.isConstQualified();
+ }
+ } else {
+ // If the de-referece operator return by value then test for the canonical
+ // const qualification of the init variable type.
+ DerefByConstRef = CanonicalInitVarType.isConstQualified();
+ }
+ } else if (FixerKind == LFK_PseudoArray) {
if (!EndCall)
return;
ContainerExpr = EndCall->getImplicitObjectArgument();
@@ -1071,9 +1129,7 @@ void LoopFixer::run(const MatchFinder::M
if (!ContainerExpr && !BoundExpr)
return;
- bool DerefByValue = Nodes.getNodeAs<QualType>(DerefByValueResultName) != 0;
-
findAndVerifyUsages(Context, LoopVar, EndVar, ContainerExpr, BoundExpr,
- ContainerNeedsDereference, DerefByValue, TheLoop,
- ConfidenceLevel);
+ ContainerNeedsDereference, DerefByValue, DerefByConstRef,
+ TheLoop, ConfidenceLevel);
}
Modified: clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopActions.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopActions.h?rev=181528&r1=181527&r2=181528&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopActions.h (original)
+++ clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopActions.h Thu May 9 12:46:20 2013
@@ -77,7 +77,8 @@ class LoopFixer : public clang::ast_matc
bool AliasFromForInit,
const clang::ForStmt *TheLoop,
bool ContainerNeedsDereference,
- bool DerefByValue);
+ bool DerefByValue,
+ bool DerefByConstRef);
/// \brief Given a loop header that would be convertible, discover all usages
/// of the index variable and convert the loop if possible.
@@ -88,6 +89,7 @@ class LoopFixer : public clang::ast_matc
const clang::Expr *BoundExpr,
bool ContainerNeedsDereference,
bool DerefByValue,
+ bool DerefByConstRef,
const clang::ForStmt *TheLoop,
Confidence ConfidenceLevel);
Modified: clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopMatchers.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopMatchers.cpp?rev=181528&r1=181527&r2=181528&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopMatchers.cpp (original)
+++ clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopMatchers.cpp Thu May 9 12:46:20 2013
@@ -22,10 +22,12 @@ const char ConditionBoundName[] = "condi
const char ConditionVarName[] = "conditionVar";
const char IncrementVarName[] = "incrementVar";
const char InitVarName[] = "initVar";
+const char BeginCallName[] = "beginCall";
const char EndCallName[] = "endCall";
const char ConditionEndVarName[] = "conditionEndVar";
const char EndVarName[] = "endVar";
const char DerefByValueResultName[] = "derefByValueResult";
+const char DerefByRefResultName[] = "derefByRefResult";
// shared matchers
static const TypeMatcher AnyType = anything();
@@ -109,10 +111,23 @@ StatementMatcher makeArrayLoopMatcher()
/// - If the end iterator variable 'g' is defined, it is the same as 'f'
StatementMatcher makeIteratorLoopMatcher() {
StatementMatcher BeginCallMatcher =
- memberCallExpr(argumentCountIs(0), callee(methodDecl(hasName("begin"))));
+ memberCallExpr(
+ argumentCountIs(0),
+ callee(
+ methodDecl(hasName("begin"))
+ )
+ ).bind(BeginCallName);
DeclarationMatcher InitDeclMatcher =
- varDecl(hasInitializer(anything())).bind(InitVarName);
+ varDecl(
+ hasInitializer(
+ anyOf(
+ ignoringParenImpCasts(BeginCallMatcher),
+ materializeTemporaryExpr(ignoringParenImpCasts(BeginCallMatcher)),
+ hasDescendant(BeginCallMatcher)
+ )
+ )
+ ).bind(InitVarName);
DeclarationMatcher EndDeclMatcher =
varDecl(hasInitializer(anything())).bind(EndVarName);
@@ -157,7 +172,11 @@ StatementMatcher makeIteratorLoopMatcher
returns(
// Skip loops where the iterator's operator* returns an
// rvalue reference. This is just weird.
- qualType(unless(hasCanonicalType(rValueReferenceType())))
+ qualType(
+ unless(
+ hasCanonicalType(rValueReferenceType())
+ )
+ ).bind(DerefByRefResultName)
)
)
)
@@ -165,6 +184,7 @@ StatementMatcher makeIteratorLoopMatcher
)
);
+
return
forStmt(
hasLoopInit(anyOf(
Modified: clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopMatchers.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopMatchers.h?rev=181528&r1=181527&r2=181528&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopMatchers.h (original)
+++ clang-tools-extra/trunk/cpp11-migrate/LoopConvert/LoopMatchers.h Thu May 9 12:46:20 2013
@@ -27,10 +27,12 @@ extern const char ConditionVarName[];
extern const char ConditionEndVarName[];
extern const char IncrementVarName[];
extern const char InitVarName[];
+extern const char BeginCallName[];
extern const char EndExprName[];
extern const char EndCallName[];
extern const char EndVarName[];
extern const char DerefByValueResultName[];
+extern const char DerefByRefResultName[];
clang::ast_matchers::StatementMatcher makeArrayLoopMatcher();
clang::ast_matchers::StatementMatcher makeIteratorLoopMatcher();
Modified: clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/Inputs/structures.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/Inputs/structures.h?rev=181528&r1=181527&r2=181528&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/Inputs/structures.h (original)
+++ clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/Inputs/structures.h Thu May 9 12:46:20 2013
@@ -131,10 +131,13 @@ class transparent {
template<typename IteratorType>
struct Nested {
typedef IteratorType* iterator;
+ typedef const IteratorType* const_iterator;
IteratorType *operator->();
IteratorType operator*();
iterator begin();
iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
};
// Like llvm::SmallPtrSet, the iterator has a dereference operator that returns
Modified: clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/iterator.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/iterator.cpp?rev=181528&r1=181527&r2=181528&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/iterator.cpp (original)
+++ clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/iterator.cpp Thu May 9 12:46:20 2013
@@ -23,20 +23,20 @@ void f() {
// CHECK-NEXT: printf("I found %d\n", elem);
S s;
- for (S::const_iterator it = s.begin(), e = s.end(); it != e; ++it) {
+ for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) {
printf("s has value %d\n", (*it).x);
}
// CHECK: for (auto & elem : s)
// CHECK-NEXT: printf("s has value %d\n", (elem).x);
S *ps;
- for (S::const_iterator it = ps->begin(), e = ps->end(); it != e; ++it) {
+ for (S::iterator it = ps->begin(), e = ps->end(); it != e; ++it) {
printf("s has value %d\n", (*it).x);
}
// CHECK: for (auto & p : *ps)
// CHECK-NEXT: printf("s has value %d\n", (p).x);
- for (S::const_iterator it = s.begin(), e = s.end(); it != e; ++it) {
+ for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) {
printf("s has value %d\n", it->x);
}
// CHECK: for (auto & elem : s)
@@ -80,18 +80,18 @@ void f() {
// CHECK-NEXT: int k = A->x + elem.x;
dependent<int> v;
- for (dependent<int>::const_iterator it = v.begin(), e = v.end();
+ for (dependent<int>::iterator it = v.begin(), e = v.end();
it != e; ++it) {
printf("Fibonacci number is %d\n", *it);
}
- // CHECK: for (auto & elem : v)
+ // CHECK: for (auto & elem : v) {
// CHECK-NEXT: printf("Fibonacci number is %d\n", elem);
- for (dependent<int>::const_iterator it(v.begin()), e = v.end();
+ for (dependent<int>::iterator it(v.begin()), e = v.end();
it != e; ++it) {
printf("Fibonacci number is %d\n", *it);
}
- // CHECK: for (auto & elem : v)
+ // CHECK: for (auto & elem : v) {
// CHECK-NEXT: printf("Fibonacci number is %d\n", elem);
doublyDependent<int,int> intmap;
@@ -134,6 +134,46 @@ void f() {
}
}
+// Tests to verify the proper use of auto where the init variable type and the
+// initializer type differ or are mostly the same except for const qualifiers.
+void different_type() {
+ // s.begin() returns a type 'iterator' which is just a non-const pointer and
+ // differs from const_iterator only on the const qualification.
+ 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 (auto const & elem : s)
+ // CHECK-NEXT: printf("s has value %d\n", (elem).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 (auto const & p : *ps)
+ // CHECK-NEXT: printf("s has value %d\n", (p).x);
+
+ // v.begin() returns a user-defined type 'iterator' which, since it's
+ // different from const_iterator, disqualifies these loops from
+ // transformation.
+ 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 (dependent<int>::const_iterator it = v.begin(), e = v.end();
+ // CHECK-NEXT: it != e; ++it) {
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", *it);
+
+ for (dependent<int>::const_iterator it(v.begin()), e = v.end();
+ it != e; ++it) {
+ printf("Fibonacci number is %d\n", *it);
+ }
+ // CHECK: for (dependent<int>::const_iterator it(v.begin()), e = v.end();
+ // CHECK-NEXT: it != e; ++it) {
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", *it);
+}
+
// Tests to ensure that an implicit 'this' is picked up as the container.
// If member calls are made to 'this' within the loop, the transform becomes
// risky as these calls may affect state that affects the loop.
Modified: clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/naming-conflict.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/naming-conflict.cpp?rev=181528&r1=181527&r2=181528&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/naming-conflict.cpp (original)
+++ clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/naming-conflict.cpp Thu May 9 12:46:20 2013
@@ -32,7 +32,7 @@ void sameNames() {
void macroConflict() {
S MAXs;
- for (S::const_iterator it = MAXs.begin(), e = MAXs.end(); it != e; ++it) {
+ for (S::iterator it = MAXs.begin(), e = MAXs.end(); it != e; ++it) {
printf("s has value %d\n", (*it).x);
printf("Max of 3 and 5: %d\n", MAX(3,5));
}
@@ -40,6 +40,14 @@ void macroConflict() {
// CHECK-NEXT: printf("s has value %d\n", (MAXs_it).x);
// CHECK-NEXT: printf("Max of 3 and 5: %d\n", MAX(3,5));
+ for (S::const_iterator it = MAXs.begin(), e = MAXs.end(); it != e; ++it) {
+ printf("s has value %d\n", (*it).x);
+ printf("Max of 3 and 5: %d\n", MAX(3,5));
+ }
+ // CHECK: for (auto const & MAXs_it : MAXs)
+ // CHECK-NEXT: printf("s has value %d\n", (MAXs_it).x);
+ // CHECK-NEXT: printf("Max of 3 and 5: %d\n", MAX(3,5));
+
T DEFs;
for (T::iterator it = DEFs.begin(), e = DEFs.end(); it != e; ++it) {
if (*it == DEF) {
Modified: clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/nesting.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/nesting.cpp?rev=181528&r1=181527&r2=181528&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/nesting.cpp (original)
+++ clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/nesting.cpp Thu May 9 12:46:20 2013
@@ -54,4 +54,16 @@ void f() {
// CHECK: for (auto & elem : NestT) {
// CHECK-NEXT: for (T::iterator TI = (elem).begin(), TE = (elem).end(); TI != TE; ++TI) {
// CHECK-NEXT: printf("%d", *TI);
+
+ Nested<S> NestS;
+ for (Nested<S>::const_iterator I = NestS.begin(), E = NestS.end(); I != E; ++I) {
+ for (S::const_iterator SI = (*I).begin(), SE = (*I).end(); SI != SE; ++SI) {
+ printf("%d", *SI);
+ }
+ }
+ // The inner loop is also convertible, but doesn't need to be converted
+ // immediately. Update this test when that changes!
+ // CHECK: for (auto const & elem : NestS) {
+ // CHECK-NEXT: for (S::const_iterator SI = (elem).begin(), SE = (elem).end(); SI != SE; ++SI) {
+ // CHECK-NEXT: printf("%d", *SI);
}
Modified: clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/single-iterator.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/single-iterator.cpp?rev=181528&r1=181527&r2=181528&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/single-iterator.cpp (original)
+++ clang-tools-extra/trunk/test/cpp11-migrate/LoopConvert/single-iterator.cpp Thu May 9 12:46:20 2013
@@ -34,20 +34,20 @@ void f() {
// CHECK-NEXT: printf("I found %d\n", elem);
S s;
- for (S::const_iterator it = s.begin(); it != s.end(); ++it) {
+ for (S::iterator it = s.begin(); it != s.end(); ++it) {
printf("s has value %d\n", (*it).x);
}
// CHECK: for (auto & elem : s)
// CHECK-NEXT: printf("s has value %d\n", (elem).x);
S *ps;
- for (S::const_iterator it = ps->begin(); it != ps->end(); ++it) {
+ for (S::iterator it = ps->begin(); it != ps->end(); ++it) {
printf("s has value %d\n", (*it).x);
}
// CHECK: for (auto & p : *ps)
// CHECK-NEXT: printf("s has value %d\n", (p).x);
- for (S::const_iterator it = s.begin(); it != s.end(); ++it) {
+ for (S::iterator it = s.begin(); it != s.end(); ++it) {
printf("s has value %d\n", it->x);
}
// CHECK: for (auto & elem : s)
@@ -91,18 +91,18 @@ void f() {
// CHECK-NEXT: int k = A->x + elem.x;
dependent<int> v;
- for (dependent<int>::const_iterator it = v.begin();
+ for (dependent<int>::iterator it = v.begin();
it != v.end(); ++it) {
printf("Fibonacci number is %d\n", *it);
}
- // CHECK: for (auto & elem : v)
+ // CHECK: for (auto & elem : v) {
// CHECK-NEXT: printf("Fibonacci number is %d\n", elem);
- for (dependent<int>::const_iterator it(v.begin());
+ for (dependent<int>::iterator it(v.begin());
it != v.end(); ++it) {
printf("Fibonacci number is %d\n", *it);
}
- // CHECK: for (auto & elem : v)
+ // CHECK: for (auto & elem : v) {
// CHECK-NEXT: printf("Fibonacci number is %d\n", elem);
doublyDependent<int,int> intmap;
@@ -113,3 +113,40 @@ void f() {
// CHECK: for (auto & elem : intmap)
// CHECK-NEXT: printf("intmap[%d] = %d", elem.first, elem.second);
}
+
+void different_type() {
+ // Tests to verify the proper use of auto where the init variable type and the
+ // initializer type differ or are mostly the same except for const qualifiers.
+
+ // s.begin() returns a type 'iterator' which is just a non-const pointer and
+ // differs from const_iterator only on the const qualification.
+ S s;
+ for (S::const_iterator it = s.begin(); it != s.end(); ++it) {
+ printf("s has value %d\n", (*it).x);
+ }
+ // CHECK: for (auto const & elem : s)
+ // CHECK-NEXT: printf("s has value %d\n", (elem).x);
+
+ S *ps;
+ for (S::const_iterator it = ps->begin(); it != ps->end(); ++it) {
+ printf("s has value %d\n", (*it).x);
+ }
+ // CHECK: for (auto const & p : *ps)
+ // CHECK-NEXT: printf("s has value %d\n", (p).x);
+
+ // v.begin() returns a user-defined type 'iterator' which, since it's
+ // different from const_iterator, disqualifies these loops from
+ // transformation.
+ dependent<int> v;
+ for (dependent<int>::const_iterator it = v.begin(); it != v.end(); ++it) {
+ printf("Fibonacci number is %d\n", *it);
+ }
+ // CHECK: for (dependent<int>::const_iterator it = v.begin(); it != v.end(); ++it) {
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", *it);
+
+ for (dependent<int>::const_iterator it(v.begin()); it != v.end(); ++it) {
+ printf("Fibonacci number is %d\n", *it);
+ }
+ // CHECK: for (dependent<int>::const_iterator it(v.begin()); it != v.end(); ++it) {
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", *it);
+}
More information about the cfe-commits
mailing list