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");
|
assert(!DS.hasTypeSpecifier() && "Type specifier checked above");
|
||||||
|
|
||||||
// Since we know that this either implicit int (which is rare) or an
|
// 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
|
// error, do lookahead to try to do better recovery. This never applies
|
||||||
// a type specifier.
|
// within a type specifier. Outside of C++, we allow this even if the
|
||||||
// FIXME: Don't bail out here in languages with no implicit int (like
|
// language doesn't "officially" support implicit int -- we support
|
||||||
// C++ with no -fms-extensions). This is much more likely to be an undeclared
|
// implicit int as an extension in C99 and C11. Allegedly, MS also
|
||||||
// type or typo than a use of implicit int.
|
// supports implicit int in C++ mode.
|
||||||
if (DSC != DSC_type_specifier && DSC != DSC_trailing &&
|
if (DSC != DSC_type_specifier && DSC != DSC_trailing &&
|
||||||
|
(!getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt) &&
|
||||||
isValidAfterIdentifierInDeclarator(NextToken())) {
|
isValidAfterIdentifierInDeclarator(NextToken())) {
|
||||||
// If this token is valid for implicit int, e.g. "static x = 4", then
|
// 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
|
// 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;
|
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
|
// Otherwise, if we don't consume this token, we are going to emit an
|
||||||
// error anyway. Try to recover from various common problems. Check
|
// 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.
|
// 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
|
// This is almost certainly an invalid type name. Let the action emit a
|
||||||
// diagnostic and attempt to recover.
|
// diagnostic and attempt to recover.
|
||||||
ParsedType T;
|
ParsedType T;
|
||||||
|
|
|
@ -9,8 +9,9 @@ struct X0 {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct X1 {
|
struct X1 {
|
||||||
int X1;
|
int X1; // expected-note{{hidden by a non-type declaration of 'X1' here}}
|
||||||
X1(); // expected-error{{declarator requires an identifier}}
|
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 {
|
struct X2 {
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
|
// 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
|
// PR7180
|
||||||
int f(a::b::c); // expected-error {{use of undeclared identifier 'a'}}
|
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'?}}
|
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