[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