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
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 7ca9e28..dcc96cb 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1638,12 +1638,13 @@
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 @@
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 @@
}
}
+ 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;
diff --git a/test/CXX/class/class.mem/p14.cpp b/test/CXX/class/class.mem/p14.cpp
index 72b232e..3f14099 100644
--- a/test/CXX/class/class.mem/p14.cpp
+++ b/test/CXX/class/class.mem/p14.cpp
@@ -9,8 +9,9 @@
};
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 {
diff --git a/test/Parser/cxx-undeclared-identifier.cpp b/test/Parser/cxx-undeclared-identifier.cpp
index f15deab..6ea2965 100644
--- a/test/Parser/cxx-undeclared-identifier.cpp
+++ b/test/Parser/cxx-undeclared-identifier.cpp
@@ -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'}}
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index b1e8d91..4d6d065 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -190,3 +190,10 @@
};
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'}}
+ };
+}