Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td +++ include/clang/Basic/DiagnosticParseKinds.td @@ -204,6 +204,8 @@ def err_expected_semi_after_static_assert : Error< "expected ';' after static_assert">; def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">; +def note_invalid_for_range : Note< + "range based for statement requires ':' after range declaration">; def warn_missing_selector_name : Warning< "%0 used as the name of the previous parameter rather than as part " "of the selector">, Index: lib/Parse/ParseStmt.cpp =================================================================== --- lib/Parse/ParseStmt.cpp +++ lib/Parse/ParseStmt.cpp @@ -1469,8 +1469,16 @@ if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode? Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); + const bool RangeInitIsAuto = Tok.is(tok::kw_auto); // In C++0x, "for (T NS:a" might not be a typo for :: - bool MightBeForRangeStmt = getLangOpts().CPlusPlus; + const bool MightBeForRangeStmt = getLangOpts().CPlusPlus; + SourceLocation EqualLoc; + if (MightBeForRangeStmt && RangeInitIsAuto) { + TentativeParsingAction FindEqual(*this); + if (SkipUntil(tok::equal, StopAtSemi | StopBeforeMatch)) + EqualLoc = Tok.getLocation(); + FindEqual.Revert(); + } ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; @@ -1501,6 +1509,9 @@ Collection = ParseExpression(); } else { Diag(Tok, diag::err_expected_semi_for); + if (getLangOpts().CPlusPlus11 && RangeInitIsAuto && EqualLoc.isValid()) + Diag(EqualLoc, diag::note_invalid_for_range) + << FixItHint::CreateReplacement(EqualLoc, ":"); } } else { ProhibitAttributes(attrs); Index: test/Parser/cxx0x-for-range.cpp =================================================================== --- test/Parser/cxx0x-for-range.cpp +++ test/Parser/cxx0x-for-range.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++11 %s 2>&1 | FileCheck %s template struct pair {}; @@ -28,3 +28,31 @@ return n; } + +namespace PR19176 { +struct Vector { + struct iterator { + int &operator*(); + iterator &operator++(); + iterator &operator++(int); + bool operator==(const iterator &) const; + }; + iterator begin(); + iterator end(); +}; + +void f() { + Vector v; + int a[] = {1, 2, 3, 4}; + for (auto foo = a) // expected-error {{expected ';' in 'for' statement specifier}} + // expected-note@-1 {{range based for statement requires ':' after range declaration}} + // expected-error@-2 {{expected ';' in 'for' statement specifier}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:18}:":" + (void)foo; + for (auto i = v) // expected-error {{expected ';' in 'for' statement specifier}} + // expected-note@-1 {{range based for statement requires ':' after range declaration}} + // expected-error@-2 {{expected ';' in 'for' statement specifier}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:15-[[@LINE-3]]:16}:":" + (void)i; +} +}