[cfe-commits] r159941 - in /cfe/trunk: include/clang/Parse/Parser.h lib/Parse/ParseDecl.cpp lib/Parse/Parser.cpp test/Parser/objc-recover.mm

Jordan Rose jordan_rose at apple.com
Mon Jul 9 09:54:54 PDT 2012


Author: jrose
Date: Mon Jul  9 11:54:53 2012
New Revision: 159941

URL: http://llvm.org/viewvc/llvm-project?rev=159941&view=rev
Log:
Better parser recovery in Objective-C containers.

Previously it was possible to get an infinite-loop-on-invalid with a namespace
decl within @interface. Since 'namespace' is normally a safe place to retry
top-level parsing, we just didn't consume the token.

This adds a flag that tracks whether we have temporarily left Objective-C
scope to parse a C-like declaration, and uses that to better recover from
parse problems by stopping at possible method declarations and at @end. To
fix the original problem, we do /not/ stop at 'namespace' when in an
Objective-C @interface or @protocol context (but still do in @implementation).

Added:
    cfe/trunk/test/Parser/objc-recover.mm
Modified:
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/Parser.cpp

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=159941&r1=159940&r2=159941&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Jul  9 11:54:53 2012
@@ -23,6 +23,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/SaveAndRestore.h"
 #include <stack>
 
 namespace clang {
@@ -83,6 +84,7 @@
   friend class ColonProtectionRAIIObject;
   friend class InMessageExpressionRAIIObject;
   friend class PoisonSEHIdentifiersRAIIObject;
+  friend class ObjCDeclContextSwitch;
   friend class ParenBraceBracketBalancer;
   friend class BalancedDelimiterTracker;
 
@@ -203,6 +205,13 @@
 
   IdentifierInfo *getSEHExceptKeyword();
 
+  /// True if we are within an Objective-C container while parsing C-like decls.
+  ///
+  /// This is necessary because Sema thinks we have left the container
+  /// to parse the C-like decls, meaning Actions.getObjCDeclContext() will
+  /// be NULL.
+  bool ParsingInObjCContainer;
+
   bool SkipFunctionBodies;
 
 public:
@@ -556,9 +565,11 @@
   class ObjCDeclContextSwitch {
     Parser &P;
     Decl *DC;
+    SaveAndRestore<bool> WithinObjCContainer;
   public:
-    explicit ObjCDeclContextSwitch(Parser &p) : P(p),
-               DC(p.getObjCDeclContext()) {
+    explicit ObjCDeclContextSwitch(Parser &p)
+      : P(p), DC(p.getObjCDeclContext()),
+        WithinObjCContainer(P.ParsingInObjCContainer, DC != 0) {
       if (DC)
         P.Actions.ActOnObjCTemporaryExitContainerContext(cast<DeclContext>(DC));
     }

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=159941&r1=159940&r2=159941&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jul  9 11:54:53 2012
@@ -1270,15 +1270,33 @@
 
     case tok::kw_inline:
       // 'inline namespace' at the start of a line is almost certainly
-      // a good place to pick back up parsing.
-      if (Tok.isAtStartOfLine() && NextToken().is(tok::kw_namespace))
+      // a good place to pick back up parsing, except in an Objective-C
+      // @interface context.
+      if (Tok.isAtStartOfLine() && NextToken().is(tok::kw_namespace) &&
+          (!ParsingInObjCContainer || CurParsedObjCImpl))
         return;
       break;
 
     case tok::kw_namespace:
       // 'namespace' at the start of a line is almost certainly a good
-      // place to pick back up parsing.
-      if (Tok.isAtStartOfLine())
+      // place to pick back up parsing, except in an Objective-C
+      // @interface context.
+      if (Tok.isAtStartOfLine() &&
+          (!ParsingInObjCContainer || CurParsedObjCImpl))
+        return;
+      break;
+
+    case tok::at:
+      // @end is very much like } in Objective-C contexts.
+      if (NextToken().isObjCAtKeyword(tok::objc_end) &&
+          ParsingInObjCContainer)
+        return;
+      break;
+
+    case tok::minus:
+    case tok::plus:
+      // - and + probably start new method declarations in Objective-C contexts.
+      if (Tok.isAtStartOfLine() && ParsingInObjCContainer)
         return;
       break;
 

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=159941&r1=159940&r2=159941&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Mon Jul  9 11:54:53 2012
@@ -49,7 +49,7 @@
   : PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
     GreaterThanIsOperator(true), ColonIsSacred(false), 
     InMessageExpression(false), TemplateParameterDepth(0),
-    SkipFunctionBodies(SkipFunctionBodies) {
+    ParsingInObjCContainer(false), SkipFunctionBodies(SkipFunctionBodies) {
   Tok.setKind(tok::eof);
   Actions.CurScope = 0;
   NumCachedScopes = 0;

Added: cfe/trunk/test/Parser/objc-recover.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/objc-recover.mm?rev=159941&view=auto
==============================================================================
--- cfe/trunk/test/Parser/objc-recover.mm (added)
+++ cfe/trunk/test/Parser/objc-recover.mm Mon Jul  9 11:54:53 2012
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+
+ at interface StopAtAtEnd
+// This used to eat the @end
+int 123 // expected-error{{expected unqualified-id}}
+ at end
+
+ at implementation StopAtAtEnd // no-warning
+int 123 // expected-error{{expected unqualified-id}}
+ at end
+
+
+ at interface StopAtMethodDecls
+// This used to eat the method declarations
+int 123 // expected-error{{expected unqualified-id}}
+- (void)foo; // expected-note{{here}}
+int 456 // expected-error{{expected unqualified-id}}
++ (void)bar; // expected-note{{here}}
+ at end
+
+ at implementation StopAtMethodDecls
+int 123 // expected-error{{expected unqualified-id}}
+- (id)foo {} // expected-warning{{conflicting return type}}
+int 456 // expected-error{{expected unqualified-id}}
++ (id)bar {} // expected-warning{{conflicting return type}}
+ at end
+
+
+ at interface EmbeddedNamespace
+// This used to cause an infinite loop.
+namespace NS { // expected-error{{expected unqualified-id}}
+}
+- (id)test; // expected-note{{here}}
+ at end
+
+ at implementation EmbeddedNamespace
+int 123 // expected-error{{expected unqualified-id}}
+// We should still stop here and parse this namespace.
+namespace NS {
+  void foo();
+}
+
+// Make sure the declaration of -test was recognized.
+- (void)test { // expected-warning{{conflicting return type}}
+  // Make sure the declaration of NS::foo was recognized.
+  NS::foo();
+}
+
+ at end
+
+
+ at protocol ProtocolWithEmbeddedNamespace
+namespace NS { // expected-error{{expected unqualified-id}}
+
+}
+- (void)PWEN_foo; // expected-note{{here}}
+ at end
+
+ at interface ImplementPWEN <ProtocolWithEmbeddedNamespace>
+ at end
+
+ at implementation ImplementPWEN
+- (id)PWEN_foo {} // expected-warning{{conflicting return type}}
+ at end





More information about the cfe-commits mailing list