Try to recover a bit better if a close brace is missing from the end of a class
definition. If we see something that looks like a namespace definition inside a
class, that strongly indicates that a close brace was missing somewhere.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@194319 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 1df1713..f4b6cb8 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -464,6 +464,10 @@
"expected class member or base class name">;
def err_expected_lbrace_after_base_specifiers : Error<
"expected '{' after base class list">;
+def err_missing_end_of_definition : Error<
+ "missing '}' at end of definition of %0">;
+def note_missing_end_of_definition_before : Note<
+ "still within definition of %0 here">;
def ext_ellipsis_exception_spec : Extension<
"exception specification of '...' is a Microsoft extension">,
InGroup<Microsoft>;
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index d314087..1b26bba 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -2084,6 +2084,8 @@
isCXX11AttributeSpecifier(bool Disambiguate = false,
bool OuterMightBeMessageSend = false);
+ void DiagnoseUnexpectedNamespace(DeclContext *Context);
+
Decl *ParseNamespace(unsigned Context, SourceLocation &DeclEnd,
SourceLocation InlineLoc = SourceLocation());
void ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 8cd16b3..3c534f7 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1953,12 +1953,12 @@
Diag(Tok, diag::err_at_defs_cxx);
else
Diag(Tok, diag::err_at_in_class);
-
+
ConsumeToken();
SkipUntil(tok::r_brace);
return;
}
-
+
// Access declarations.
bool MalformedTypeSpec = false;
if (!TemplateInfo.Kind &&
@@ -2421,7 +2421,7 @@
/// assignment-expression
/// braced-init-list
///
-/// defaulted/deleted function-definition:
+/// defaulted/deleted function-definition:
/// '=' 'default'
/// '=' 'delete'
///
@@ -2625,6 +2625,12 @@
continue;
}
+ // If we see a namespace here, a close brace was missing somewhere.
+ if (Tok.is(tok::kw_namespace)) {
+ DiagnoseUnexpectedNamespace(cast<DeclContext>(TagDecl));
+ break;
+ }
+
AccessSpecifier AS = getAccessSpecifierIfPresent();
if (AS != AS_none) {
// Current token is a C++ access specifier.
@@ -2666,8 +2672,6 @@
continue;
}
- // FIXME: Make sure we don't have a template here.
-
// Parse all the comma separated declarators.
ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList());
}
@@ -2718,6 +2722,27 @@
ClassScope.Exit();
}
+void Parser::DiagnoseUnexpectedNamespace(DeclContext *Ctx) {
+ assert(Tok.is(tok::kw_namespace));
+
+ // FIXME: Suggest where the close brace should have gone by looking
+ // at indentation changes within the definition body.
+ Diag(cast<Decl>(Ctx)->getLocation(),
+ diag::err_missing_end_of_definition) << Ctx;
+ Diag(Tok.getLocation(),
+ diag::note_missing_end_of_definition_before) << Ctx;
+
+ // Push '};' onto the token stream to recover.
+ PP.EnterToken(Tok);
+
+ Tok.startToken();
+ Tok.setLocation(PP.getLocForEndOfToken(PrevTokLocation));
+ Tok.setKind(tok::semi);
+ PP.EnterToken(Tok);
+
+ Tok.setKind(tok::r_brace);
+}
+
/// ParseConstructorInitializer - Parse a C++ constructor initializer,
/// which explicitly initializes the members or base classes of a
/// class (C++ [class.base.init]). For example, the three initializers
diff --git a/test/Parser/recovery.cpp b/test/Parser/recovery.cpp
index ac1be6a..54e1b0a 100644
--- a/test/Parser/recovery.cpp
+++ b/test/Parser/recovery.cpp
@@ -35,6 +35,17 @@
5int m = { l }, n = m; // expected-error {{unqualified-id}}
+namespace MissingBrace {
+ struct S { // expected-error {{missing '}' at end of definition of 'MissingBrace::S'}}
+ int f();
+ // };
+
+ namespace N { int g(); } // expected-note {{still within definition of 'MissingBrace::S' here}}
+
+ int k1 = S().h(); // expected-error {{no member named 'h' in 'MissingBrace::S'}}
+ int k2 = S().f() + N::g();
+}
+
namespace N {
int
} // expected-error {{unqualified-id}}