]> granicus.if.org Git - clang/commitdiff
Try to recover a bit better if a close brace is missing from the end of a class
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 9 Nov 2013 04:52:51 +0000 (04:52 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 9 Nov 2013 04:52:51 +0000 (04:52 +0000)
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

include/clang/Basic/DiagnosticParseKinds.td
include/clang/Parse/Parser.h
lib/Parse/ParseDeclCXX.cpp
test/Parser/recovery.cpp

index 1df1713972af42863d19086d3a58731e0736ec8c..f4b6cb81f8c3e78b9befdaf2faeef1805bd6b2fc 100644 (file)
@@ -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<Microsoft>;
index d314087ddffd3b9231c8c0ee7532e354ca2146f6..1b26bba875a3e5fcf82f1496c5248696a1b11711 100644 (file)
@@ -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<SourceLocation>& IdentLoc,
index 8cd16b3ee099872043c223fd796fb6e0a6a32cce..3c534f7f2755a8a6e596431084b2e8e598fb0c10 100644 (file)
@@ -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<DeclContext>(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<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
index ac1be6a571661a88c55cfa64e75f7b6cc87eecbb..54e1b0adf2ed8e8b0ba8453fa78c827fd20eaea7 100644 (file)
@@ -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}}