From: Richard Smith Date: Sat, 9 Nov 2013 04:52:51 +0000 (+0000) Subject: Try to recover a bit better if a close brace is missing from the end of a class X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b310439121c875937d78cc49cc969bc1197fc025;p=clang 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 1df1713972..f4b6cb81f8 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -464,6 +464,10 @@ def err_expected_member_or_base_name : Error< "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; diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index d314087ddf..1b26bba875 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -2084,6 +2084,8 @@ private: isCXX11AttributeSpecifier(bool Disambiguate = false, bool OuterMightBeMessageSend = false); + void DiagnoseUnexpectedNamespace(DeclContext *Context); + Decl *ParseNamespace(unsigned Context, SourceLocation &DeclEnd, SourceLocation InlineLoc = SourceLocation()); void ParseInnerNamespace(std::vector& IdentLoc, diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 8cd16b3ee0..3c534f7f27 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1953,12 +1953,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, 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 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, /// assignment-expression /// braced-init-list /// -/// defaulted/deleted function-definition: +/// defaulted/deleted function-definition: /// '=' 'default' /// '=' 'delete' /// @@ -2625,6 +2625,12 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, continue; } + // If we see a namespace here, a close brace was missing somewhere. + if (Tok.is(tok::kw_namespace)) { + DiagnoseUnexpectedNamespace(cast(TagDecl)); + break; + } + AccessSpecifier AS = getAccessSpecifierIfPresent(); if (AS != AS_none) { // Current token is a C++ access specifier. @@ -2666,8 +2672,6 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, 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 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, 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(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 ac1be6a571..54e1b0adf2 100644 --- a/test/Parser/recovery.cpp +++ b/test/Parser/recovery.cpp @@ -35,6 +35,17 @@ constexpr int foo(); 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}}