From c9977d09a2de7f7d2245973413d4caf86c736640 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 16 Mar 2011 17:05:57 +0000 Subject: [PATCH] Make sure that we always pop a function's scope *before* we call ActOnFinishFunctionBody/ActOnBlockStmtExpr. This way, we ensure that we diagnose undefined labels before the jump-scope checker gets run, since the jump-scope checker requires (as its invariant) that all of the GotoStmts be wired up correctly. Fixes PR9495. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127738 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 4 ++-- lib/Parse/ParseCXXInlineMethods.cpp | 5 +++-- lib/Parse/ParseExpr.cpp | 1 + lib/Parse/ParseObjc.cpp | 14 ++++++++------ lib/Parse/ParseStmt.cpp | 22 +++++++++++++++------- lib/Parse/Parser.cpp | 5 +++-- test/SemaCXX/goto.cpp | 25 ++++++++++++++++++++++++- test/SemaObjCXX/goto.mm | 16 ++++++++++++++++ 8 files changed, 72 insertions(+), 20 deletions(-) create mode 100644 test/SemaObjCXX/goto.mm diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index d39fa47cf0..bd39cdb452 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1286,8 +1286,8 @@ private: SourceLocation *DeclEnd = 0); Decl *ParseDeclarationAfterDeclarator(Declarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); - Decl *ParseFunctionStatementBody(Decl *Decl); - Decl *ParseFunctionTryBlock(Decl *Decl); + Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope); + Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope); /// \brief When in code-completion, skip parsing of the function/method body /// unless the body contains the code-completion point. diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 399473840a..baa038ea98 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -261,7 +261,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D); if (Tok.is(tok::kw_try)) { - ParseFunctionTryBlock(LM.D); + ParseFunctionTryBlock(LM.D, FnScope); assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, Tok.getLocation()) && "ParseFunctionTryBlock went over the cached tokens!"); @@ -276,13 +276,14 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { // Error recovery. if (!Tok.is(tok::l_brace)) { + FnScope.Exit(); Actions.ActOnFinishFunctionBody(LM.D, 0); return; } } else Actions.ActOnDefaultCtorInitializers(LM.D); - ParseFunctionStatementBody(LM.D); + ParseFunctionStatementBody(LM.D, FnScope); if (Tok.getLocation() != origLoc) { // Due to parsing error, we either went over the cached tokens or diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 7cb955134a..ecc02ac42e 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1954,6 +1954,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { } StmtResult Stmt(ParseCompoundStatementBody()); + BlockScope.Exit(); if (!Stmt.isInvalid()) Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.take(), getCurScope()); else diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 4b702e0761..d4391ee3e9 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -1724,9 +1724,12 @@ Decl *Parser::ParseObjCMethodDefinition() { // specified Declarator for the method. Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl); - if (PP.isCodeCompletionEnabled()) - if (trySkippingFunctionBodyForCodeCompletion()) + if (PP.isCodeCompletionEnabled()) { + if (trySkippingFunctionBodyForCodeCompletion()) { + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(MDecl, 0); + } + } StmtResult FnBody(ParseCompoundStatementBody()); @@ -1735,12 +1738,11 @@ Decl *Parser::ParseObjCMethodDefinition() { FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc, MultiStmtArg(Actions), false); - // TODO: Pass argument information. - Actions.ActOnFinishFunctionBody(MDecl, FnBody.take()); - // Leave the function body scope. BodyScope.Exit(); - + + // TODO: Pass argument information. + Actions.ActOnFinishFunctionBody(MDecl, FnBody.take()); return MDecl; } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index d7e9070520..cd970ca60f 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1531,14 +1531,17 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, return true; } -Decl *Parser::ParseFunctionStatementBody(Decl *Decl) { +Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { assert(Tok.is(tok::l_brace)); SourceLocation LBraceLoc = Tok.getLocation(); - if (PP.isCodeCompletionEnabled()) - if (trySkippingFunctionBodyForCodeCompletion()) + if (PP.isCodeCompletionEnabled()) { + if (trySkippingFunctionBodyForCodeCompletion()) { + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, 0); - + } + } + PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc, "parsing function body"); @@ -1552,6 +1555,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl) { FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, MultiStmtArg(Actions), false); + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); } @@ -1560,7 +1564,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl) { /// function-try-block: /// 'try' ctor-initializer[opt] compound-statement handler-seq /// -Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { +Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { assert(Tok.is(tok::kw_try) && "Expected 'try'"); SourceLocation TryLoc = ConsumeToken(); @@ -1571,9 +1575,12 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { if (Tok.is(tok::colon)) ParseConstructorInitializer(Decl); - if (PP.isCodeCompletionEnabled()) - if (trySkippingFunctionBodyForCodeCompletion()) + if (PP.isCodeCompletionEnabled()) { + if (trySkippingFunctionBodyForCodeCompletion()) { + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, 0); + } + } SourceLocation LBraceLoc = Tok.getLocation(); StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc)); @@ -1583,6 +1590,7 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, MultiStmtArg(Actions), false); + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index d9b37d2c56..3946fc7208 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -801,7 +801,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, D.getMutableDeclSpec().abort(); if (Tok.is(tok::kw_try)) - return ParseFunctionTryBlock(Res); + return ParseFunctionTryBlock(Res, BodyScope); // If we have a colon, then we're probably parsing a C++ // ctor-initializer. @@ -810,13 +810,14 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // Recover from error. if (!Tok.is(tok::l_brace)) { + BodyScope.Exit(); Actions.ActOnFinishFunctionBody(Res, 0); return Res; } } else Actions.ActOnDefaultCtorInitializers(Res); - return ParseFunctionStatementBody(Res); + return ParseFunctionStatementBody(Res, BodyScope); } /// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides diff --git a/test/SemaCXX/goto.cpp b/test/SemaCXX/goto.cpp index e8b7822c32..8b8379613d 100644 --- a/test/SemaCXX/goto.cpp +++ b/test/SemaCXX/goto.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s + // PR9463 double *end; void f() { @@ -44,3 +45,25 @@ void rdar9135994() X: goto X; } + +namespace PR9495 { + struct NonPOD { NonPOD(); ~NonPOD(); }; + + void f(bool b) { + NonPOD np; + if (b) { + goto undeclared; // expected-error{{use of undeclared label 'undeclared'}} + } + } + + void g() { + (void)^(bool b){ + NonPOD np; + if (b) { + goto undeclared; // expected-error{{use of undeclared label 'undeclared'}} + } + }; + } +} + + diff --git a/test/SemaObjCXX/goto.mm b/test/SemaObjCXX/goto.mm new file mode 100644 index 0000000000..67df1f4c32 --- /dev/null +++ b/test/SemaObjCXX/goto.mm @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// PR9495 +struct NonPOD { NonPOD(); ~NonPOD(); }; + +@interface A +@end + +@implementation A +- (void)method:(bool)b { + NonPOD np; + if (b) { + goto undeclared; // expected-error{{use of undeclared label 'undeclared'}} + } +} +@end -- 2.40.0