When a type-id is unexpectedly given a name, assume that the name is unrelated

syntax unless we have a reason to think otherwise.

This improves error recovery in a couple of cases.

llvm-svn: 303398
This commit is contained in:
Richard Smith 2017-05-19 01:54:59 +00:00
parent 8f1d87a79a
commit 74639b1900
5 changed files with 27 additions and 42 deletions

View File

@ -1999,41 +1999,6 @@ public:
llvm_unreachable("unknown context kind!");
}
/// diagnoseIdentifier - Return true if the identifier is prohibited and
/// should be diagnosed (because it cannot be anything else).
bool diagnoseIdentifier() const {
switch (Context) {
case FileContext:
case KNRTypeListContext:
case MemberContext:
case BlockContext:
case ForContext:
case InitStmtContext:
case ConditionContext:
case PrototypeContext:
case LambdaExprParameterContext:
case TemplateParamContext:
case CXXCatchContext:
case ObjCCatchContext:
case TypeNameContext:
case FunctionalCastContext:
case ConversionIdContext:
case ObjCParameterContext:
case ObjCResultContext:
case BlockLiteralContext:
case CXXNewContext:
case LambdaExprContext:
return false;
case AliasDeclContext:
case AliasTemplateContext:
case TemplateTypeArgContext:
case TrailingReturnContext:
return true;
}
llvm_unreachable("unknown context kind!");
}
/// Return true if the context permits a C++17 decomposition declarator.
bool mayHaveDecompositionDeclarator() const {
switch (Context) {

View File

@ -5542,11 +5542,28 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
D.SetRangeEnd(Tok.getLocation());
ConsumeToken();
goto PastIdentifier;
} else if (Tok.is(tok::identifier) && D.diagnoseIdentifier()) {
// A virt-specifier isn't treated as an identifier if it appears after a
// trailing-return-type.
if (D.getContext() != Declarator::TrailingReturnContext ||
!isCXX11VirtSpecifier(Tok)) {
} else if (Tok.is(tok::identifier) && !D.mayHaveIdentifier()) {
// We're not allowed an identifier here, but we got one. Try to figure out
// if the user was trying to attach a name to the type, or whether the name
// is some unrelated trailing syntax.
bool DiagnoseIdentifier = false;
if (D.hasGroupingParens())
// An identifier within parens is unlikely to be intended to be anything
// other than a name being "declared".
DiagnoseIdentifier = true;
else if (D.getContext() == Declarator::TemplateTypeArgContext)
// T<int N> is an accidental identifier; T<int N indicates a missing '>'.
DiagnoseIdentifier =
NextToken().isOneOf(tok::comma, tok::greater, tok::greatergreater);
else if (D.getContext() == Declarator::AliasDeclContext ||
D.getContext() == Declarator::AliasTemplateContext)
// The most likely error is that the ';' was forgotten.
DiagnoseIdentifier = NextToken().isOneOf(tok::comma, tok::semi);
else if (D.getContext() == Declarator::TrailingReturnContext &&
!isCXX11VirtSpecifier(Tok))
DiagnoseIdentifier = NextToken().isOneOf(
tok::comma, tok::semi, tok::equal, tok::l_brace, tok::kw_try);
if (DiagnoseIdentifier) {
Diag(Tok.getLocation(), diag::err_unexpected_unqualified_id)
<< FixItHint::CreateRemoval(Tok.getLocation());
D.SetIdentifier(nullptr, Tok.getLocation());

View File

@ -10,7 +10,7 @@ template<typename T> struct A {};
// Check for template argument lists followed by junk
// FIXME: The diagnostics here aren't great...
A<int+> int x; // expected-error {{expected '>'}} expected-error {{expected unqualified-id}}
A<int x; // expected-error {{type-id cannot have a name}} expected-error {{expected '>'}}
A<int x; // expected-error {{expected '>'}}
// PR8912
template <bool> struct S {};

View File

@ -137,6 +137,9 @@ namespace AliasDeclEndLocation {
>\
> // expected-error {{expected ';' after alias declaration}}
;
using D = AliasDeclEndLocation::A<int
> // expected-error {{expected ';' after alias declaration}}
B something_else;
}
struct Base { virtual void f() = 0; virtual void g() = 0; virtual void h() = 0; };

View File

@ -37,7 +37,7 @@ void f0() {
// rdar://problem/8962770
void test4() {
int (^f)() = ^((x)) { }; // expected-error {{expected ')'}} expected-warning {{type specifier missing}} expected-note {{to match this}}
int (^f)() = ^((x)) { }; // expected-warning {{type specifier missing}} expected-error {{type-id cannot have a name}}
}
// rdar://problem/9170609