forked from OSchip/llvm-project
Don't use the implicit int rule for error recovery in C++. Instead, try to
disambiguate whether the type name was forgotten or mistyped. llvm-svn: 156854
This commit is contained in:
parent
9295df0569
commit
a952ebbcee
|
@ -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;
|
||||
|
|
|
@ -9,8 +9,9 @@ struct X0 {
|
|||
};
|
||||
|
||||
struct X1 {
|
||||
int X1;
|
||||
X1(); // expected-error{{declarator requires an identifier}}
|
||||
int X1; // expected-note{{hidden by a non-type declaration of 'X1' here}}
|
||||
X1(); // expected-error{{must use 'struct' tag to refer to type 'X1' in this scope}} \
|
||||
// expected-error{{expected member name or ';' after declaration specifiers}}
|
||||
};
|
||||
|
||||
struct X2 {
|
||||
|
|
|
@ -1,5 +1,17 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
|
||||
|
||||
namespace ImplicitInt {
|
||||
static a(4); // expected-error {{requires a type specifier}}
|
||||
b(int n); // expected-error {{requires a type specifier}}
|
||||
c (*p)[]; // expected-error {{unknown type name 'c'}}
|
||||
itn f(char *p, *q); // expected-error {{unknown type name 'itn'}} expected-error {{requires a type specifier}}
|
||||
|
||||
struct S {
|
||||
void f();
|
||||
};
|
||||
S::f() {} // expected-error {{requires a type specifier}}
|
||||
}
|
||||
|
||||
// PR7180
|
||||
int f(a::b::c); // expected-error {{use of undeclared identifier 'a'}}
|
||||
|
||||
|
|
|
@ -190,3 +190,10 @@ namespace test1 {
|
|||
};
|
||||
test1::FooBar *b; // expected-error{{no type named 'FooBar' in namespace 'test1'; did you mean 'Foobar'?}}
|
||||
}
|
||||
|
||||
namespace ImplicitInt {
|
||||
void f(int, unsinged); // expected-error{{did you mean 'unsigned'}}
|
||||
struct S {
|
||||
unsinged : 4; // expected-error{{did you mean 'unsigned'}}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue