r208299 - Suggest fix-it ':' when '=' used in for-range-declaration
Ismail Pazarbasi
ismail.pazarbasi at gmail.com
Thu May 8 04:28:25 PDT 2014
Author: ismailp
Date: Thu May 8 06:28:25 2014
New Revision: 208299
URL: http://llvm.org/viewvc/llvm-project?rev=208299&view=rev
Log:
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)
^
:
Modified:
cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseStmt.cpp
cfe/trunk/test/Parser/cxx0x-for-range.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=208299&r1=208298&r2=208299&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Thu May 8 06:28:25 2014
@@ -204,6 +204,8 @@ def err_expected_semi_after_attribute_li
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">,
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=208299&r1=208298&r2=208299&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Thu May 8 06:28:25 2014
@@ -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);
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=208299&r1=208298&r2=208299&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu May 8 06:28:25 2014
@@ -1620,7 +1620,8 @@ Parser::DeclGroupPtrTy Parser::ParseDecl
}
SmallVector<Decl *, 8> 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::ParseAsmAttributesAfterDecl
/// 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::ParseDeclarationAfterDecla
// 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::ParseDeclarationAfterDecla
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<tok::TokenKind, 2> 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(),
Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=208299&r1=208298&r2=208299&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Thu May 8 06:28:25 2014
@@ -1479,12 +1479,10 @@ StmtResult Parser::ParseForStatement(Sou
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);
Modified: cfe/trunk/test/Parser/cxx0x-for-range.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-for-range.cpp?rev=208299&r1=208298&r2=208299&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx0x-for-range.cpp (original)
+++ cfe/trunk/test/Parser/cxx0x-for-range.cpp Thu May 8 06:28:25 2014
@@ -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<typename T, typename U>
struct pair {};
@@ -28,3 +28,35 @@ int foo(map<char*,int> &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 at -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}}
+
+ }
+}
+}
More information about the cfe-commits
mailing list