From: Douglas Gregor Date: Sat, 18 Sep 2010 01:28:11 +0000 (+0000) Subject: Continue parsing more postfix expressions, even after semantic X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ac5fd8404fa8ecfae28be76f98fd0d926350354c;p=clang Continue parsing more postfix expressions, even after semantic errors. Improves code completion in yet another case. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@114255 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 4164f0e15a..1ef14a2284 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4313,7 +4313,7 @@ public: void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, SourceLocation OpLoc, bool IsArrow); - void CodeCompletePostfixExpression(Scope *S, Expr *LHS); + void CodeCompletePostfixExpression(Scope *S, ExprResult LHS); void CodeCompleteTag(Scope *S, unsigned TagSpec); void CodeCompleteTypeQualifiers(DeclSpec &DS); void CodeCompleteCase(Scope *S); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index ec2c5d6b95..e04e62bcb2 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -242,8 +242,7 @@ Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, ExprResult R = ParseObjCMessageExpressionBody(LBracLoc, SuperLoc, ReceiverType, ReceiverExpr); - if (R.isInvalid()) return move(R); - R = ParsePostfixExpressionSuffix(R.take()); + R = ParsePostfixExpressionSuffix(R); return ParseRHSOfBinaryExpression(R, prec::Assignment); } @@ -576,8 +575,6 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, TypeOfCast, CastTy, RParenLoc); - if (Res.isInvalid()) - return move(Res); } switch (ParenExprType) { @@ -1012,8 +1009,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, } // These can be followed by postfix-expr pieces. - if (Res.isInvalid()) return move(Res); - return ParsePostfixExpressionSuffix(Res.get()); + return ParsePostfixExpressionSuffix(Res); } /// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression @@ -1045,7 +1041,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (InMessageExpression) return move(LHS); - Actions.CodeCompletePostfixExpression(getCurScope(), LHS.take()); + Actions.CodeCompletePostfixExpression(getCurScope(), LHS); ConsumeCodeCompletionToken(); LHS = ExprError(); break; @@ -1099,12 +1095,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { CommaLocsTy CommaLocs; Loc = ConsumeParen(); - - if (LHS.isInvalid()) { - SkipUntil(tok::r_paren); - return ExprError(); - } - + if (Tok.is(tok::code_completion)) { Actions.CodeCompleteCall(getCurScope(), LHS.get(), 0, 0); ConsumeCodeCompletionToken(); @@ -1114,24 +1105,25 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (ParseExpressionList(ArgExprs, CommaLocs, &Sema::CodeCompleteCall, LHS.get())) { SkipUntil(tok::r_paren); - return ExprError(); + LHS = ExprError(); } } // Match the ')'. - if (Tok.isNot(tok::r_paren)) { + if (LHS.isInvalid()) { + SkipUntil(tok::r_paren); + } else if (Tok.isNot(tok::r_paren)) { MatchRHSPunctuation(tok::r_paren, Loc); - return ExprError(); - } - - if (!LHS.isInvalid()) { - assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&& + LHS = ExprError(); + } else { + assert((ArgExprs.size() == 0 || + ArgExprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); LHS = Actions.ActOnCallExpr(getCurScope(), LHS.take(), Loc, move_arg(ArgExprs), Tok.getLocation()); + ConsumeParen(); } - ConsumeParen(); break; } case tok::arrow: @@ -1183,7 +1175,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /*AllowConstructorName=*/false, ObjectType, Name)) - return ExprError(); + LHS = ExprError(); if (!LHS.isInvalid()) LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.take(), OpLoc, @@ -1363,21 +1355,18 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { default: assert(0 && "Not a builtin primary expression!"); case tok::kw___builtin_va_arg: { ExprResult Expr(ParseAssignmentExpression()); - if (Expr.isInvalid()) { - SkipUntil(tok::r_paren); - return ExprError(); - } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) - return ExprError(); + Expr = ExprError(); TypeResult Ty = ParseTypeName(); if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); - return ExprError(); + Expr = ExprError(); } - if (Ty.isInvalid()) + + if (Expr.isInvalid() || Ty.isInvalid()) Res = ExprError(); else Res = Actions.ActOnVAArg(StartLoc, Expr.take(), Ty.get(), ConsumeParen()); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index e305172e51..371921ca11 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2757,9 +2757,11 @@ void Sema::CodeCompleteExpression(Scope *S, Results.data(),Results.size()); } -void Sema::CodeCompletePostfixExpression(Scope *S, Expr *E) { - if (getLangOptions().ObjC1) - CodeCompleteObjCInstanceMessage(S, E, 0, 0, false); +void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) { + if (E.isInvalid()) + CodeCompleteOrdinaryName(S, PCC_RecoveryInFunction); + else if (getLangOptions().ObjC1) + CodeCompleteObjCInstanceMessage(S, E.take(), 0, 0, false); } static void AddObjCProperties(ObjCContainerDecl *Container, diff --git a/test/Index/complete-recovery.m b/test/Index/complete-recovery.m index 5141a533ae..0b558f81ab 100644 --- a/test/Index/complete-recovery.m +++ b/test/Index/complete-recovery.m @@ -11,6 +11,7 @@ A *a2; z = [a2 method:1]; blah ? blech : [a2 method:1]; + (a * a2)([a2 method:1]); } @end @@ -29,3 +30,4 @@ // RUN: c-index-test -code-completion-at=%s:12:11 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s // CHECK-CC3: ObjCInstanceMethodDecl:{ResultType void}{TypedText method:}{Placeholder (int)} (17) // RUN: c-index-test -code-completion-at=%s:13:22 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s +// RUN: c-index-test -code-completion-at=%s:14:16 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s diff --git a/test/SemaCXX/copy-assignment.cpp b/test/SemaCXX/copy-assignment.cpp index 5730b2af8f..f3dadc4450 100644 --- a/test/SemaCXX/copy-assignment.cpp +++ b/test/SemaCXX/copy-assignment.cpp @@ -99,13 +99,15 @@ void test() { // : Don't crash // FIXME: the recovery here is really bad. -namespace test1 { - template class A : public unknown::X { // expected-error {{undeclared identifier 'unknown'}} expected-error {{expected class name}} - A(UndeclaredType n) : X(n) {} // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{undeclared identifier 'n'}} expected-error {{expected ';' at end}} expected-error {{field has incomplete type}} +namespace test1 { // expected-note{{to match this '{'}} + template class A : public unknown::X { // expected-error {{undeclared identifier 'unknown'}} expected-error {{expected class name}} \ + // expected-note{{template parameter is declared here}} + A(UndeclaredType n) : X(n) {} // expected-error{{expected ')'}} expected-note{{to match this '('}} \ + // expected-error{{use of undeclared identifier 'n'}} }; - template class B : public A { + template class B : public A { // expected-error{{declaration of 'T' shadows template parameter}} virtual void foo() {} }; - extern template class A; // expected-note {{in instantiation}} expected-note {{not complete}} - extern template class B; -} + extern template class A; // expected-error{{expected member name or ';' after declaration specifiers}} + extern template class B; // expected-error{{expected member name or ';' after declaration specifiers}} +} // expected-error{{expected ';' after class}} // expected-error{{expected '}'}}