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

Reply via email to