diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-05-15 21:01:51 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-05-15 21:01:51 +0000 |
commit | 827adaff666e53ae2f2db994bcd62ebe1ff5b9ce (patch) | |
tree | cf9d47a7695bff9864f37b935fd0fda82fe7d7f7 /lib/Parse/ParseDecl.cpp | |
parent | 04e326b3d0ae1a84643b7366ce0ea5137e06ed69 (diff) |
Don't use the implicit int rule for error recovery in C++. Instead, try to
disambiguate whether the type name was forgotten or mistyped.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156854 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseDecl.cpp')
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 59 |
1 files changed, 54 insertions, 5 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 7ca9e280ca..dcc96cb861 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1638,12 +1638,13 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, assert(!DS.hasTypeSpecifier() && "Type specifier checked above"); // Since we know that this either implicit int (which is rare) or an - // error, do lookahead to try to do better recovery. This never applies within - // a type specifier. - // FIXME: Don't bail out here in languages with no implicit int (like - // C++ with no -fms-extensions). This is much more likely to be an undeclared - // type or typo than a use of implicit int. + // error, do lookahead to try to do better recovery. This never applies + // within a type specifier. Outside of C++, we allow this even if the + // language doesn't "officially" support implicit int -- we support + // implicit int as an extension in C99 and C11. Allegedly, MS also + // supports implicit int in C++ mode. if (DSC != DSC_type_specifier && DSC != DSC_trailing && + (!getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt) && isValidAfterIdentifierInDeclarator(NextToken())) { // If this token is valid for implicit int, e.g. "static x = 4", then // we just avoid eating the identifier, so it will be parsed as the @@ -1651,6 +1652,13 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, return false; } + if (getLangOpts().CPlusPlus && + DS.getStorageClassSpec() == DeclSpec::SCS_auto) { + // Don't require a type specifier if we have the 'auto' storage class + // specifier in C++98 -- we'll promote it to a type specifier. + return false; + } + // Otherwise, if we don't consume this token, we are going to emit an // error anyway. Try to recover from various common problems. Check // to see if this was a reference to a tag name without a tag specified. @@ -1699,6 +1707,47 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, } } + if (DSC != DSC_type_specifier && DSC != DSC_trailing) { + // Look ahead to the next token to try to figure out what this declaration + // was supposed to be. + switch (NextToken().getKind()) { + case tok::comma: + case tok::equal: + case tok::kw_asm: + case tok::l_brace: + case tok::l_square: + case tok::semi: + // This looks like a variable declaration. The type is probably missing. + // We're done parsing decl-specifiers. + return false; + + case tok::l_paren: { + // static x(4); // 'x' is not a type + // x(int n); // 'x' is not a type + // x (*p)[]; // 'x' is a type + // + // Since we're in an error case (or the rare 'implicit int in C++' MS + // extension), we can afford to perform a tentative parse to determine + // which case we're in. + TentativeParsingAction PA(*this); + ConsumeToken(); + TPResult TPR = TryParseDeclarator(/*mayBeAbstract*/false); + PA.Revert(); + if (TPR == TPResult::False()) + return false; + // The identifier is followed by a parenthesized declarator. + // It's supposed to be a type. + break; + } + + default: + // This is probably supposed to be a type. This includes cases like: + // int f(itn); + // struct S { unsinged : 4; }; + break; + } + } + // This is almost certainly an invalid type name. Let the action emit a // diagnostic and attempt to recover. ParsedType T; |