From: Richard Smith Date: Mon, 2 Jul 2012 19:14:01 +0000 (+0000) Subject: A ':' after an enum-specifier at class scope is a bitfield, not a typo for a ';'. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=139be7007eba3bd491ca50297888be507753a95d;p=clang A ':' after an enum-specifier at class scope is a bitfield, not a typo for a ';'. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159549 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 895cd04fd9..8fd597e1cf 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1949,7 +1949,7 @@ private: //===--------------------------------------------------------------------===// // C++ 9: classes [class] and C structs/unions. - bool isValidAfterTypeSpecifier(); + bool isValidAfterTypeSpecifier(bool CouldBeBitfield); void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, bool EnteringContext, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index c6db497a53..c61f5543a6 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3067,9 +3067,10 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, TypeResult BaseType; // Parse the fixed underlying type. + bool CanBeBitfield = getCurScope()->getFlags() & Scope::ClassScope; if (AllowFixedUnderlyingType && Tok.is(tok::colon)) { bool PossibleBitfield = false; - if (getCurScope()->getFlags() & Scope::ClassScope) { + if (CanBeBitfield) { // If we're in class scope, this can either be an enum declaration with // an underlying type, or a declaration of a bitfield member. We try to // use a simple disambiguation scheme first to catch the common cases @@ -3158,7 +3159,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, } } else if (DSC != DSC_type_specifier && (Tok.is(tok::semi) || - (Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier()))) { + (Tok.isAtStartOfLine() && + !isValidAfterTypeSpecifier(CanBeBitfield)))) { TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; if (Tok.isNot(tok::semi)) { // A semicolon was missing after this declaration. Diagnose and recover. @@ -3366,7 +3368,8 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { // The next token must be valid after an enum definition. If not, a ';' // was probably forgotten. - if (!isValidAfterTypeSpecifier()) { + bool CanBeBitfield = getCurScope()->getFlags() & Scope::ClassScope; + if (!isValidAfterTypeSpecifier(CanBeBitfield)) { ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, "enum"); // Push this token back into the preprocessor and change our current token // to ';' so that the rest of the code recovers as though there were an diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 23855cdf29..8e357f7e42 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -929,7 +929,7 @@ void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) { /// Determine whether the following tokens are valid after a type-specifier /// which could be a standalone declaration. This will conservatively return /// true if there's any doubt, and is appropriate for insert-';' fixits. -bool Parser::isValidAfterTypeSpecifier() { +bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { // This switch enumerates the valid "follow" set for type-specifiers. switch (Tok.getKind()) { default: break; @@ -944,6 +944,8 @@ bool Parser::isValidAfterTypeSpecifier() { case tok::l_paren: // struct foo {...} ( x); case tok::comma: // __builtin_offsetof(struct foo{...} , return true; + case tok::colon: + return CouldBeBitfield; // enum E { ... } : 2; // Type qualifiers case tok::kw_const: // struct foo {...} const x; case tok::kw_volatile: // struct foo {...} volatile x; @@ -1236,7 +1238,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } } else if (DSC != DSC_type_specifier && (Tok.is(tok::semi) || - (Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier()))) { + (Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(false)))) { TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; if (Tok.isNot(tok::semi)) { // A semicolon was missing after this declaration. Diagnose and recover. @@ -1466,7 +1468,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // In a template-declaration which defines a class, no declarator // is permitted. if (TUK == Sema::TUK_Definition && - (TemplateInfo.Kind || !isValidAfterTypeSpecifier())) { + (TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) { ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, TagType == DeclSpec::TST_class ? "class" : TagType == DeclSpec::TST_struct ? "struct" : "union"); diff --git a/test/Parser/declarators.c b/test/Parser/declarators.c index 476a9af0fd..f63b59f7ca 100644 --- a/test/Parser/declarators.c +++ b/test/Parser/declarators.c @@ -107,3 +107,8 @@ void test18() { int x = 4+(5-12)); // expected-error {{extraneous ')' before ';'}} } +enum E1 { e1 }: // expected-error {{expected ';'}} +struct EnumBitfield { + enum E2 { e2 } : 4; // ok + struct S { int n; }: // expected-error {{expected ';'}} +};