Part of PR10101: after a parse error in a declaration, try harder to find the

right place to pick up parsing. In C++, this had a tendency to skip everything
declared within headers if the TU starts with garbage.

llvm-svn: 154530
This commit is contained in:
Richard Smith 2012-04-11 20:59:20 +00:00
parent 63fa02ea89
commit b8caac8e32
4 changed files with 110 additions and 6 deletions

View File

@ -742,6 +742,10 @@ private:
bool SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi = true,
bool DontConsume = false, bool StopAtCodeCompletion = false);
/// SkipMalformedDecl - Read tokens until we get to some likely good stopping
/// point for skipping past a simple-declaration.
void SkipMalformedDecl();
//===--------------------------------------------------------------------===//
// Lexing and parsing of C++ inline methods.

View File

@ -1117,6 +1117,67 @@ bool Parser::MightBeDeclarator(unsigned Context) {
}
}
/// Skip until we reach something which seems like a sensible place to pick
/// up parsing after a malformed declaration. This will sometimes stop sooner
/// than SkipUntil(tok::r_brace) would, but will never stop later.
void Parser::SkipMalformedDecl() {
while (true) {
switch (Tok.getKind()) {
case tok::l_brace:
// Skip until matching }, then stop. We've probably skipped over
// a malformed class or function definition or similar.
ConsumeBrace();
SkipUntil(tok::r_brace, /*StopAtSemi*/false);
if (Tok.is(tok::comma) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try)) {
// This declaration isn't over yet. Keep skipping.
continue;
}
if (Tok.is(tok::semi))
ConsumeToken();
return;
case tok::l_square:
ConsumeBracket();
SkipUntil(tok::r_square, /*StopAtSemi*/false);
continue;
case tok::l_paren:
ConsumeParen();
SkipUntil(tok::r_paren, /*StopAtSemi*/false);
continue;
case tok::r_brace:
return;
case tok::semi:
ConsumeToken();
return;
case tok::kw_inline:
// 'inline namespace' at the start of a line is almost certainly
// a good place to pick back up parsing.
if (Tok.isAtStartOfLine() && NextToken().is(tok::kw_namespace))
return;
break;
case tok::kw_namespace:
// 'namespace' at the start of a line is almost certainly a good
// place to pick back up parsing.
if (Tok.isAtStartOfLine())
return;
break;
case tok::eof:
return;
default:
break;
}
ConsumeAnyToken();
}
}
/// ParseDeclGroup - Having concluded that this is either a function
/// definition or a group of object declarations, actually parse the
/// result.
@ -1131,10 +1192,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// Bail out if the first declarator didn't seem well-formed.
if (!D.hasName() && !D.mayOmitIdentifier()) {
// Skip until ; or }.
SkipUntil(tok::r_brace, true, true);
if (Tok.is(tok::semi))
ConsumeToken();
SkipMalformedDecl();
return DeclGroupPtrTy();
}

View File

@ -0,0 +1,42 @@
// RUN: %clang -cc1 -verify -std=c++11 %s
8gi///===--- recovery.cpp ---===// // expected-error {{unqualified-id}}
namespace Std { // expected-note {{here}}
typedef int Important;
}
/ redeclare as an inline namespace // expected-error {{unqualified-id}}
inline namespace Std { // expected-error {{cannot be reopened as inline}}
Important n;
} / end namespace Std // expected-error {{unqualified-id}}
int x;
Std::Important y;
// FIXME: Recover as if the typo correction were applied.
extenr "C" { // expected-error {{did you mean 'extern'}} expected-error {{unqualified-id}}
void f();
}
void g() {
z = 1; // expected-error {{undeclared}}
f(); // expected-error {{undeclared}}
}
struct S {
int a, b, c;
S();
};
8S::S() : a{ 5 }, b{ 6 }, c{ 2 } { // expected-error {{unqualified-id}}
return;
}
int k;
int l = k;
5int m = { l }, n = m; // expected-error {{unqualified-id}}
namespace N {
int
} // expected-error {{unqualified-id}}
// FIXME: Recover as if the typo correction were applied.
strcut U { // expected-error {{did you mean 'struct'}}
} *u[3]; // expected-error {{expected ';'}}

View File

@ -131,10 +131,10 @@ namespace pr6629 {
bogus<foo<T1,T2> > // expected-error {{unknown template name 'bogus'}} \
// BOGUS expected-error {{expected '{' after base class list}} \
// BOGUS expected-error {{expected ';' after struct}} \
// BOGUS expected-error {{expected unqualified-id}} \
// BOGUS expected-error {{expected unqualified-id}}
{ };
template<> struct foo<unknown,unknown> { // why isn't there an error here?
template<> struct foo<unknown,unknown> { // expected-error {{undeclared identifier 'unknown'}}
template <typename U1, typename U2> struct bar {
typedef bar type;
static const int value = 0;