Better diagnostics for range-based for loops with bad range types.
The old error message stating that 'begin' was an undeclared identifier
is replaced with a new message explaining that the error is in the range
expression, along with which of the begin() and end() functions was
problematic if relevant.
Additionally, if the range was a pointer type or defines operator*,
attempt to dereference the range, and offer a FixIt if the modified range
works.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162248 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
index 96bb472..66e30f5 100644
--- a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -3,7 +3,7 @@
struct pr12960 {
int begin;
void foo(int x) {
- for (int& it : x) { // expected-error {{use of undeclared identifier 'begin'}} expected-note {{range has type 'int'}}
+ for (int& it : x) { // expected-error {{invalid range expression of type 'int'; no viable 'begin' function available}}
}
}
};
@@ -116,9 +116,9 @@
struct NoEndADL {
null_t alt_begin();
};
- for (auto u : NoBeginADL()) { // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type 'NoBeginADL'}}
+ for (auto u : NoBeginADL()) { // expected-error {{invalid range expression of type 'NoBeginADL'; no viable 'begin' function available}}
}
- for (auto u : NoEndADL()) { // expected-error {{no matching function for call to 'end'}} expected-note {{range has type 'NoEndADL'}}
+ for (auto u : NoEndADL()) { // expected-error {{invalid range expression of type 'NoEndADL'; no viable 'end' function available}}
}
struct NoBegin {
@@ -156,8 +156,7 @@
for (int n : NoCopy()) { // ok
}
- for (int n : 42) { // expected-error {{no matching function for call to 'begin'}} \
- expected-note {{range has type 'int'}}
+ for (int n : 42) { // expected-error {{invalid range expression of type 'int'; no viable 'begin' function available}}
}
for (auto a : *also_incomplete) { // expected-error {{cannot use incomplete type 'struct Incomplete' as a range}}
@@ -179,9 +178,10 @@
template<typename T>
void i(T t) {
- for (auto u : t) { // expected-error {{no matching function for call to 'begin'}} \
+ for (auto u : t) { // expected-error {{invalid range expression of type 'A *'; no viable 'begin' function available}} \
expected-error {{member function 'begin' not viable}} \
- expected-note {{range has type}}
+ expected-note {{when looking up 'begin' function}}
+
}
}
template void i<A[13]>(A*); // expected-note {{requested here}}
@@ -204,9 +204,10 @@
void j() {
for (auto u : NS::ADL()) {
}
- for (auto u : NS::NoADL()) { // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
+ for (auto u : NS::NoADL()) { // expected-error {{invalid range expression of type 'NS::NoADL'; no viable 'begin' function available}}
}
for (auto a : VoidBeginADL()) { // expected-error {{cannot use type 'void' as an iterator}}
+
}
}
@@ -215,4 +216,3 @@
for (int &x : array)
x *= 2;
}
-
diff --git a/test/SemaCXX/for-range-dereference.cpp b/test/SemaCXX/for-range-dereference.cpp
new file mode 100644
index 0000000..3bf50f3
--- /dev/null
+++ b/test/SemaCXX/for-range-dereference.cpp
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+struct Data { };
+struct T {
+ Data *begin();
+ Data *end();
+};
+
+struct NoBegin {
+ Data *end();
+};
+
+struct DeletedEnd : public T {
+ Data *begin();
+ Data *end() = delete; //expected-note {{function has been explicitly marked deleted here}}
+};
+
+struct DeletedADLBegin { };
+
+int* begin(DeletedADLBegin) = delete; //expected-note {{candidate function has been explicitly deleted}} \
+ expected-note 6 {{candidate function not viable: no known conversion}}
+
+struct PrivateEnd {
+ Data *begin();
+
+ private:
+ Data *end(); // expected-note 1 {{declared private here}}
+};
+
+struct ADLNoEnd { };
+Data * begin(ADLNoEnd); // expected-note 7 {{candidate function not viable: no known conversion}}
+
+struct OverloadedStar {
+ T operator*();
+};
+
+void f() {
+ T t;
+ for (auto i : t) { }
+ T *pt;
+ for (auto i : pt) { } // expected-error{{invalid range expression of type 'T *'; did you mean to dereference it with '*'?}}
+
+ int arr[10];
+ for (auto i : arr) { }
+ int (*parr)[10];
+ for (auto i : parr) { }// expected-error{{invalid range expression of type 'int (*)[10]'; did you mean to dereference it with '*'?}}
+
+ NoBegin NB;
+ for (auto i : NB) { }// expected-error{{range type 'NoBegin' has 'end' member but no 'begin' member}}
+ NoBegin *pNB;
+ for (auto i : pNB) { }// expected-error{{invalid range expression of type 'NoBegin *'; no viable 'begin' function available}}
+ NoBegin **ppNB;
+ for (auto i : ppNB) { }// expected-error{{invalid range expression of type 'NoBegin **'; no viable 'begin' function available}}
+ NoBegin *****pppppNB;
+ for (auto i : pppppNB) { }// expected-error{{invalid range expression of type 'NoBegin *****'; no viable 'begin' function available}}
+
+ ADLNoEnd ANE;
+ for (auto i : ANE) { } // expected-error{{invalid range expression of type 'ADLNoEnd'; no viable 'end' function available}}
+ ADLNoEnd *pANE;
+ for (auto i : pANE) { } // expected-error{{invalid range expression of type 'ADLNoEnd *'; no viable 'begin' function available}}
+
+ DeletedEnd DE;
+ for (auto i : DE) { } // expected-error{{attempt to use a deleted function}} \
+expected-note {{when looking up 'end' function for range expression of type 'DeletedEnd'}}
+ DeletedEnd *pDE;
+
+ for (auto i : pDE) { } // expected-error {{invalid range expression of type 'DeletedEnd *'; no viable 'begin' function available}}
+
+ PrivateEnd PE;
+ // FIXME: This diagnostic should be improved, as it does not specify that
+ // the range is invalid.
+ for (auto i : PE) { } // expected-error{{'end' is a private member of 'PrivateEnd'}}
+
+ // FIXME: This diagnostic should be improved as well. It should not mention a
+ // deleted function, and we should not issue a FixIt suggesting a dereference.
+ PrivateEnd *pPE;
+ for (auto i : pPE) { }// expected-error {{invalid range expression of type 'PrivateEnd *'}}
+
+ DeletedADLBegin DAB;
+ for (auto i : DAB) { } // expected-error {{call to deleted function 'begin'}}\
+ expected-note {{when looking up 'begin' function for range expression of type 'DeletedADLBegin'}}
+
+ OverloadedStar OS;
+ for (auto i : *OS) { }
+
+ for (auto i : OS) { } // expected-error {{invalid range expression of type 'OverloadedStar'; did you mean to dereference it with '*'?}}
+}
diff --git a/test/SemaCXX/for-range-no-std.cpp b/test/SemaCXX/for-range-no-std.cpp
index fa42ca4..66b445e 100644
--- a/test/SemaCXX/for-range-no-std.cpp
+++ b/test/SemaCXX/for-range-no-std.cpp
@@ -31,10 +31,10 @@
void f() {
int a[] = {1, 2, 3};
for (auto b : S()) {} // ok
- for (auto b : T()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
+ for (auto b : T()) {} // expected-error {{invalid range expression of type 'T'}}
for (auto b : a) {} // ok
for (int b : NS::ADL()) {} // ok
- for (int b : NS::NoADL()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
+ for (int b : NS::NoADL()) {} // expected-error {{invalid range expression of type 'NS::NoADL'}}
}
void PR11601() {
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index 919edca..c21ef51 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -155,7 +155,7 @@
struct R {};
bool begun(R);
void RangeTest() {
- for (auto b : R()) {} // expected-error {{use of undeclared identifier 'begin'}} expected-note {{range has type}}
+ for (auto b : R()) {} // expected-error {{invalid range expression of type 'R'}}
}
// PR 12019 - Avoid infinite mutual recursion in DiagnoseInvalidRedeclaration