From: Richard Smith Date: Mon, 9 Jan 2012 22:31:44 +0000 (+0000) Subject: Extend the diagnostic for a ',' at the end of a declaration where a ';' was X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1c94c16317c1a35c1549e022958188eea2567089;p=clang Extend the diagnostic for a ',' at the end of a declaration where a ';' was intended to cover C++ class definitions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147808 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index fca56a8eb8..31b5022166 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1924,7 +1924,10 @@ private: void ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation *endLoc = 0); - VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const; + VirtSpecifiers::Specifier isCXX0XVirtSpecifier(const Token &Tok) const; + VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const { + return isCXX0XVirtSpecifier(Tok); + } void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS); bool isCXX0XFinalKeyword() const; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 16321491ee..5c4e898bf6 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -994,9 +994,15 @@ bool Parser::MightBeDeclarator(unsigned Context) { case tok::amp: case tok::ampamp: - case tok::colon: // Might be a typo for '::'. return getLang().CPlusPlus; + case tok::l_square: // Might be an attribute on an unnamed bit-field. + return Context == Declarator::MemberContext && getLang().CPlusPlus0x && + NextToken().is(tok::l_square); + + case tok::colon: // Might be a typo for '::' or an unnamed bit-field. + return Context == Declarator::MemberContext || getLang().CPlusPlus; + case tok::identifier: switch (NextToken().getKind()) { case tok::code_completion: @@ -1019,8 +1025,13 @@ bool Parser::MightBeDeclarator(unsigned Context) { case tok::colon: // At namespace scope, 'identifier:' is probably a typo for 'identifier::' - // and in block scope it's probably a label. - return getLang().CPlusPlus && Context == Declarator::FileContext; + // and in block scope it's probably a label. Inside a class definition, + // this is a bit-field. + return Context == Declarator::MemberContext || + (getLang().CPlusPlus && Context == Declarator::FileContext); + + case tok::identifier: // Possible virt-specifier. + return getLang().CPlusPlus0x && isCXX0XVirtSpecifier(NextToken()); default: return false; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 5bae0e4d2c..05a346353b 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1548,13 +1548,13 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, } } -/// isCXX0XVirtSpecifier - Determine whether the next token is a C++0x +/// isCXX0XVirtSpecifier - Determine whether the given token is a C++0x /// virt-specifier. /// /// virt-specifier: /// override /// final -VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier() const { +VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const { if (!getLang().CPlusPlus) return VirtSpecifiers::VS_None; @@ -1896,6 +1896,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SmallVector DeclsInGroup; ExprResult BitfieldSize; + bool ExpectSemi = true; while (1) { // member-declarator: @@ -2023,7 +2024,18 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, break; // Consume the comma. - ConsumeToken(); + SourceLocation CommaLoc = ConsumeToken(); + + if (Tok.isAtStartOfLine() && + !MightBeDeclarator(Declarator::MemberContext)) { + // This comma was followed by a line-break and something which can't be + // the start of a declarator. The comma was probably a typo for a + // semicolon. + Diag(CommaLoc, diag::err_expected_semi_declaration) + << FixItHint::CreateReplacement(CommaLoc, ";"); + ExpectSemi = false; + break; + } // Parse the next declarator. DeclaratorInfo.clear(); @@ -2039,7 +2051,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParseDeclarator(DeclaratorInfo); } - if (ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) { + if (ExpectSemi && + ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) { // Skip to end of block or statement. SkipUntil(tok::r_brace, true, true); // If we stopped at a ';', eat it. diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp index b2b69b6f4b..9895c1f53c 100644 --- a/test/FixIt/fixit-cxx0x.cpp +++ b/test/FixIt/fixit-cxx0x.cpp @@ -22,4 +22,18 @@ namespace SemiCommaTypo { int m {}, n [[]], // expected-error {{expected ';' at end of declaration}} int o; + + struct Base { + virtual void f2(), f3(); + }; + struct MemberDeclarator : Base { + int k : 4, + //[[]] : 1, FIXME: test this once we support attributes here + : 9, // expected-error {{expected ';' at end of declaration}} + char c, // expected-error {{expected ';' at end of declaration}} + typedef void F(), // expected-error {{expected ';' at end of declaration}} + F f1, + f2 final, + f3 override, // expected-error {{expected ';' at end of declaration}} + }; } diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp index 31ef18e404..f7bf35b09e 100644 --- a/test/FixIt/fixit.cpp +++ b/test/FixIt/fixit.cpp @@ -125,6 +125,19 @@ AD oopsMoreCommas() { AD ad, // expected-error {{expected ';' at end of declaration}} return ad; } +struct MoreAccidentalCommas { + int a : 5, + b : 7, + : 4, // expected-error {{expected ';' at end of declaration}} + char c, // expected-error {{expected ';' at end of declaration}} + double d, // expected-error {{expected ';' at end of declaration}} + MoreAccidentalCommas *next, // expected-error {{expected ';' at end of declaration}} +public: + int k, // expected-error {{expected ';' at end of declaration}} + friend void f(MoreAccidentalCommas) {} + int k2, // expected-error {{expected ';' at end of declaration}} + virtual void g(), // expected-error {{expected ';' at end of declaration}} +}; template struct Mystery; template typedef Mystery::type getMysteriousThing() { // \