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:
parent
63fa02ea89
commit
b8caac8e32
|
@ -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.
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ';'}}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue