From: Ismail Pazarbasi Date: Thu, 8 May 2014 11:28:25 +0000 (+0000) Subject: Suggest fix-it ':' when '=' used in for-range-declaration X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7716d5441601112c1ef262880c0cb8f5593188dc;p=clang Suggest fix-it ':' when '=' used in for-range-declaration Fix for PR19176. Clang will suggest a fix-it hint for cases like: int arr[] = {1, 2, 3, 4}; for (auto i = arr) ^ : git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@208299 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 335b6abf13..70e16ceca1 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -204,6 +204,8 @@ def err_expected_semi_after_attribute_list : Error< def err_expected_semi_after_static_assert : Error< "expected ';' after static_assert">; def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">; +def err_single_decl_assign_in_for_range : Error< + "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">, diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 0b15eb6841..79c65c6db4 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1727,8 +1727,10 @@ private: Decl *ParseDeclarationAfterDeclarator(Declarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); bool ParseAsmAttributesAfterDeclarator(Declarator &D); - Decl *ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, - const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); + Decl *ParseDeclarationAfterDeclaratorAndAttributes( + Declarator &D, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + ForRangeInit *FRI = nullptr); Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope); Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 42369bfbc9..3c1c378dbf 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1620,7 +1620,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } SmallVector DeclsInGroup; - Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D); + Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes( + D, ParsedTemplateInfo(), FRI); if (LateParsedAttrs.size() > 0) ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false); D.complete(FirstDecl); @@ -1726,16 +1727,16 @@ bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) { /// According to the standard grammar, =default and =delete are function /// definitions, but that definitely doesn't fit with the parser here. /// -Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, - const ParsedTemplateInfo &TemplateInfo) { +Decl *Parser::ParseDeclarationAfterDeclarator( + Declarator &D, const ParsedTemplateInfo &TemplateInfo) { if (ParseAsmAttributesAfterDeclarator(D)) return 0; return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo); } -Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, - const ParsedTemplateInfo &TemplateInfo) { +Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( + Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) { // Inform the current actions module that we just parsed this declarator. Decl *ThisDecl = 0; switch (TemplateInfo.Kind) { @@ -1800,7 +1801,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, // Parse declarator '=' initializer. // If a '==' or '+=' is found, suggest a fixit to '='. if (isTokenEqualOrEqualTypo()) { - ConsumeToken(); + SourceLocation EqualLoc = ConsumeToken(); if (Tok.is(tok::kw_delete)) { if (D.isFunctionDeclarator()) @@ -1829,13 +1830,29 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, ExprResult Init(ParseInitializer()); + // If this is the only decl in (possibly) range based for statement, + // our best guess is that the user meant ':' instead of '='. + if (Tok.is(tok::r_paren) && FRI && D.isFirstDeclarator()) { + Diag(EqualLoc, diag::err_single_decl_assign_in_for_range) + << FixItHint::CreateReplacement(EqualLoc, ":"); + // We are trying to stop parser from looking for ';' in this for + // statement, therefore preventing spurious errors to be issued. + FRI->ColonLoc = EqualLoc; + Init = ExprError(); + FRI->RangeExpr = Init; + } + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); ExitScope(); } if (Init.isInvalid()) { - SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); + SmallVector StopTokens; + StopTokens.push_back(tok::comma); + if (D.getContext() == Declarator::ForContext) + StopTokens.push_back(tok::r_paren); + SkipUntil(StopTokens, StopAtSemi | StopBeforeMatch); Actions.ActOnInitializerError(ThisDecl); } else Actions.AddInitializerToDecl(ThisDecl, Init.take(), diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index eafe334891..a187b2ce3e 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1479,12 +1479,10 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; StmtVector Stmts; - DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext, - DeclEnd, attrs, false, - MightBeForRangeStmt ? - &ForRangeInit : 0); + DeclGroupPtrTy DG = ParseSimpleDeclaration( + Stmts, Declarator::ForContext, DeclEnd, attrs, false, + MightBeForRangeStmt ? &ForRangeInit : nullptr); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); - if (ForRangeInit.ParsedForRangeDecl()) { Diag(ForRangeInit.ColonLoc, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_for_range : diag::ext_for_range); diff --git a/test/Parser/cxx0x-for-range.cpp b/test/Parser/cxx0x-for-range.cpp index f920ef9085..f75b67c486 100644 --- a/test/Parser/cxx0x-for-range.cpp +++ b/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,35 @@ int foo(map &m) { 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 {{range based for statement requires ':' after range declaration}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:19-[[@LINE-1]]:20}:":" + (void)foo; + for (auto i + = + v) // expected-error@-1 {{range based for statement requires ':' after range declaration}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:7-[[@LINE-2]]:8}:":" + (void)i; +#define FORRANGE(v, a) for (DECLVARWITHINIT(v) a) // expected-note {{expanded from macro}} +#define DECLAUTOVAR(v) auto v +#define DECLVARWITHINIT(v) DECLAUTOVAR(v) = // expected-note {{expanded from macro}} + FORRANGE(i, a) { // expected-error {{range based for statement requires ':' after range declaration}} + + } +} +}