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@-1 {{overload resolution selected deleted operator 'co_await'}} - // expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'Range<float>'}} + // expected-note@-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@-1 {{overload resolution selected deleted operator 'co_await'}} - // expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'Range<long>'}} + // expected-note@-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@-1 {{no viable conversion from 'Data' to 'Data *'}} // expected-note@4 {{selected 'begin' function with iterator type 'Data *'}} + + NonComparableIterator NCI; + for (auto i : NCI) { } // expected-error {{overload resolution selected deleted operator '!='}} + // expected-note@-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@-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@-1 {{in implicit call to 'operator*' for iterator of type 'iterator'}} } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
