[clang] 816e292 - [Clang] Correct diagnostic notes for C++11 range-based for statements with invalid iterator types (#201461)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 4 08:15:35 PDT 2026
Author: Tom Honermann
Date: 2026-06-04T11:15:30-04:00
New Revision: 816e2924786a0d7d300aa9a2ff80e5a2a082e6fa
URL: https://github.com/llvm/llvm-project/commit/816e2924786a0d7d300aa9a2ff80e5a2a082e6fa
DIFF: https://github.com/llvm/llvm-project/commit/816e2924786a0d7d300aa9a2ff80e5a2a082e6fa.diff
LOG: [Clang] Correct diagnostic notes for C++11 range-based for statements with invalid iterator types (#201461)
Previously, diagnostic notes issued for errors encountered due to invalid
iterator types in C++11 range-based for statements reported the range type
as the iterator type instead of the invalid iterator type. Now fixed.
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaStmt.cpp
clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
clang/test/SemaCXX/co_await-range-for.cpp
clang/test/SemaCXX/for-range-dereference.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9e4a47a5b18fc..2307ee7e07d64 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -598,6 +598,9 @@ Improvements to Clang's diagnostics
- Clang now rejects inline asm constraints and clobbers that contain an
embedded null character, instead of silently truncating them. (#GH173900)
+- Diagnostics for the C++11 range-based for statement now report the correct
+ iterator type in notes for invalid iterator types.
+
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 077aace321264..4e3585b7b8191 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2965,7 +2965,11 @@ def err_for_range_dereference : Error<
"invalid range expression of type %0; did you mean to dereference it "
"with '*'?">;
def note_for_range_invalid_iterator : Note <
- "in implicit call to 'operator%select{!=|*|++}0' for iterator of type %1">;
+ "in implicit call to 'operator%enum_select<InvalidRangeForIterator>{"
+ "%OpNotEq{!=}|"
+ "%OpDeref{*}|"
+ "%OpAdvance{++}"
+ "}0' for iterator of type %1">;
def note_for_range_begin_end : Note<
"selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">;
def warn_for_range_const_ref_binds_temp_built_from_ref : Warning<
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 33c42b20b15ad..98f88b49aa67d 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2942,7 +2942,8 @@ StmtResult Sema::BuildCXXForRangeStmt(
ActOnFinishFullExpr(NotEqExpr.get(), /*DiscardedValue*/ false);
if (NotEqExpr.isInvalid()) {
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
- << RangeLoc << 0 << BeginRangeRef.get()->getType();
+ << RangeLoc << diag::InvalidRangeForIterator::OpNotEq
+ << BeginRef.get()->getType();
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
if (!Context.hasSameType(BeginType, EndType))
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
@@ -2965,7 +2966,8 @@ StmtResult Sema::BuildCXXForRangeStmt(
IncrExpr = ActOnFinishFullExpr(IncrExpr.get(), /*DiscardedValue*/ false);
if (IncrExpr.isInvalid()) {
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
- << RangeLoc << 2 << BeginRangeRef.get()->getType() ;
+ << RangeLoc << diag::InvalidRangeForIterator::OpAdvance
+ << BeginRef.get()->getType();
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
return StmtError();
}
@@ -2979,7 +2981,8 @@ StmtResult Sema::BuildCXXForRangeStmt(
ExprResult DerefExpr = ActOnUnaryOp(S, ColonLoc, tok::star, BeginRef.get());
if (DerefExpr.isInvalid()) {
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
- << RangeLoc << 1 << BeginRangeRef.get()->getType();
+ << RangeLoc << diag::InvalidRangeForIterator::OpDeref
+ << BeginRef.get()->getType();
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
return StmtError();
}
diff --git a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
index 938a3d096ae37..45d02d4272d22 100644
--- a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ b/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -176,7 +176,7 @@ void g() {
void *end();
};
for (auto u : NoIncr()) { // expected-error {{arithmetic on a pointer to void}}\
- expected-note {{in implicit call to 'operator++' for iterator of type 'NoIncr'}}
+ expected-note {{in implicit call to 'operator++' for iterator of type 'void *'}}
}
struct NoNotEq {
diff --git a/clang/test/SemaCXX/co_await-range-for.cpp b/clang/test/SemaCXX/co_await-range-for.cpp
index 064a35038e1c7..eb824c0128db3 100644
--- a/clang/test/SemaCXX/co_await-range-for.cpp
+++ b/clang/test/SemaCXX/co_await-range-for.cpp
@@ -108,7 +108,7 @@ ForLoopAwaiterBadIncTransform bad_inc_transform() {
Range<float> R;
for co_await(auto i : R) {} // expected-warning {{'for co_await' belongs to CoroutineTS instead of C++20, which is deprecated}}
// expected-error at -1 {{overload resolution selected deleted operator 'co_await'}}
- // expected-note at -2 {{in implicit call to 'operator++' for iterator of type 'Range<float>'}}
+ // expected-note at -2 {{in implicit call to 'operator++' for iterator of type 'Iter<float>'}}
}
template <class Dummy>
@@ -116,7 +116,7 @@ ForLoopAwaiterBadIncTransform bad_inc_transform_template(Dummy) {
Range<Dummy> R;
for co_await(auto i : R) {} // expected-warning {{'for co_await' belongs to CoroutineTS instead of C++20, which is deprecated}}
// expected-error at -1 {{overload resolution selected deleted operator 'co_await'}}
- // expected-note at -2 {{in implicit call to 'operator++' for iterator of type 'Range<long>'}}
+ // expected-note at -2 {{in implicit call to 'operator++' for iterator of type 'Iter<long>'}}
}
template ForLoopAwaiterBadIncTransform bad_inc_transform_template(long); // expected-note {{requested here}}
diff --git a/clang/test/SemaCXX/for-range-dereference.cpp b/clang/test/SemaCXX/for-range-dereference.cpp
index de4958c31bce7..7d7fa3bef767d 100644
--- a/clang/test/SemaCXX/for-range-dereference.cpp
+++ b/clang/test/SemaCXX/for-range-dereference.cpp
@@ -33,6 +33,36 @@ struct OverloadedStar {
T operator*();
};
+struct NonComparableIterator {
+ struct iterator {
+ bool operator!=(iterator) const = delete; // expected-note {{candidate function has been explicitly deleted}}
+ Data operator*() const;
+ iterator operator++() const;
+ };
+ iterator begin(); // expected-note {{selected 'begin' function with iterator type 'iterator'}}
+ iterator end();
+};
+
+struct NonIncrementableIterator {
+ struct iterator {
+ bool operator!=(iterator) const;
+ Data operator*() const;
+ iterator operator++() const = delete; // expected-note {{candidate function has been explicitly deleted}}
+ };
+ iterator begin(); // expected-note {{selected 'begin' function with iterator type 'iterator'}}
+ iterator end();
+};
+
+struct NonDereferenceableIterator {
+ struct iterator {
+ bool operator!=(iterator) const;
+ Data operator*() const = delete; // expected-note {{candidate function has been explicitly deleted}}
+ iterator operator++() const;
+ };
+ iterator begin(); // expected-note {{selected 'begin' function with iterator type 'iterator'}}
+ iterator end();
+};
+
void f() {
T t;
for (auto i : t) { }
@@ -86,4 +116,16 @@ expected-note {{when looking up 'end' function for range expression of type 'Del
for (Data *p : pt) { } // expected-error {{invalid range expression of type 'T *'; did you mean to dereference it with '*'?}}
// expected-error at -1 {{no viable conversion from 'Data' to 'Data *'}}
// expected-note at 4 {{selected 'begin' function with iterator type 'Data *'}}
+
+ NonComparableIterator NCI;
+ for (auto i : NCI) { } // expected-error {{overload resolution selected deleted operator '!='}}
+ // expected-note at -1 {{in implicit call to 'operator!=' for iterator of type 'iterator'}}
+
+ NonIncrementableIterator NII;
+ for (auto i : NII) { } // expected-error {{overload resolution selected deleted operator '++'}}
+ // expected-note at -1 {{in implicit call to 'operator++' for iterator of type 'iterator'}}
+
+ NonDereferenceableIterator NDI;
+ for (auto i : NDI) { } // expected-error {{overload resolution selected deleted operator '*'}}
+ // expected-note at -1 {{in implicit call to 'operator*' for iterator of type 'iterator'}}
}
More information about the cfe-commits
mailing list