From 5be92de217a1940d0e109abd0f401df4480c1a4b Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Sun, 2 Sep 2012 03:45:41 +0000 Subject: [PATCH] Implemented parsing and AST support for the MS __leave exception statement. Also a minor fix to __except printing in StmtPrinter.cpp. Thanks to Aaron Ballman for review. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163083 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/RecursiveASTVisitor.h | 1 + include/clang/AST/Stmt.h | 28 +++++++++++++++++++++ include/clang/Basic/DiagnosticParseKinds.td | 3 +++ include/clang/Basic/StmtNodes.td | 1 + include/clang/Sema/Scope.h | 8 +++++- include/clang/Sema/Sema.h | 2 ++ include/clang/Serialization/ASTBitCodes.h | 1 + lib/AST/Stmt.cpp | 11 ++++++++ lib/AST/StmtPrinter.cpp | 7 +++++- lib/AST/StmtProfile.cpp | 4 +++ lib/CodeGen/CGStmt.cpp | 1 + lib/Parse/ParseStmt.cpp | 17 ++++++++++++- lib/Sema/SemaStmt.cpp | 6 +++++ lib/Sema/TreeTransform.h | 10 ++++++++ lib/Serialization/ASTReaderStmt.cpp | 8 ++++++ lib/Serialization/ASTWriterStmt.cpp | 6 +++++ lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 + test/Parser/MicrosoftExtensions.c | 6 +++++ tools/libclang/RecursiveASTVisitor.h | 1 + 19 files changed, 119 insertions(+), 3 deletions(-) diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index ae4ff4b1f8..46585d64cd 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -2202,6 +2202,7 @@ DEF_TRAVERSE_STMT(UnresolvedMemberExpr, { }) DEF_TRAVERSE_STMT(SEHTryStmt, {}) +DEF_TRAVERSE_STMT(SEHLeaveStmt, {}) DEF_TRAVERSE_STMT(SEHExceptStmt, {}) DEF_TRAVERSE_STMT(SEHFinallyStmt,{}) diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 042c513552..e43a6f93fc 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -1889,6 +1889,34 @@ public: static bool classof(SEHTryStmt *) { return true; } }; +class SEHLeaveStmt : public Stmt { + SourceLocation LeaveLoc; + + SEHLeaveStmt(SourceLocation LeaveLoc); + + friend class ASTReader; + friend class ASTStmtReader; + explicit SEHLeaveStmt(EmptyShell E) : Stmt(SEHLeaveStmtClass, E) { } + +public: + static SEHLeaveStmt* Create(ASTContext &C, + SourceLocation LeaveLoc); + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getLeaveLoc()); + } + + SourceLocation getLeaveLoc() const { return LeaveLoc; } + + child_range children() { return child_range(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SEHLeaveStmtClass; + } + + static bool classof(SEHLeaveStmt *) { return true; } +}; + } // end namespace clang #endif diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index e4e339aefc..5608fa8755 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -740,6 +740,9 @@ def err_seh___except_filter : Error< def err_seh___finally_block : Error< "%0 only allowed in __finally block">; + +def err_seh___try_block : Error< + "%0 only allowed in __try block">; } // end of Parse Issue category. diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 06da94708f..46ae07f7a6 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -164,6 +164,7 @@ def OpaqueValueExpr : DStmt; // Microsoft Extensions. def CXXUuidofExpr : DStmt; def SEHTryStmt : Stmt; +def SEHLeaveStmt : Stmt; def SEHExceptStmt : Stmt; def SEHFinallyStmt : Stmt; def MSDependentExistsStmt : Stmt; diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h index b78556e65a..201b2e7a40 100644 --- a/include/clang/Sema/Scope.h +++ b/include/clang/Sema/Scope.h @@ -82,7 +82,10 @@ public: SwitchScope = 0x800, /// TryScope - This is the scope of a C++ try statement. - TryScope = 0x1000 + TryScope = 0x1000, + + /// SEHTryScope - This is scope of a Microsoft SEH try statement. + SEHTryScope = 0x2000 }; private: /// The parent scope for this scope. This is null for the translation-unit @@ -292,6 +295,9 @@ public: /// \brief Determine whether this scope is a C++ 'try' block. bool isTryScope() const { return getFlags() & Scope::TryScope; } + /// \brief Determine whether this scope is a MS SEH 'try' block. + bool isSEHTryScope() const { return getFlags() & Scope::SEHTryScope; } + /// containedInPrototypeScope - Return true if this or a parent scope /// is a FunctionPrototypeScope. bool containedInPrototypeScope() const; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 5fdb09caea..fd0cd9c397 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2622,6 +2622,8 @@ public: Stmt *TryBlock, Stmt *Handler); + StmtResult ActOnSEHLeaveStmt(SourceLocation LeaveLoc); + StmtResult ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, Stmt *Block); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index f2134134ae..25303efcf2 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -1204,6 +1204,7 @@ namespace clang { STMT_SEH_EXCEPT, // SEHExceptStmt STMT_SEH_FINALLY, // SEHFinallyStmt STMT_SEH_TRY, // SEHTryStmt + STMT_SEH_LEAVE, // SEHLeaveStmt // ARC EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index ddd47bf5ab..dfe61f2429 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -1006,6 +1006,17 @@ SEHFinallyStmt* SEHTryStmt::getFinallyHandler() const { return dyn_cast(getHandler()); } +SEHLeaveStmt::SEHLeaveStmt(SourceLocation LeaveLoc) + : Stmt(SEHLeaveStmtClass), + LeaveLoc(LeaveLoc) +{ +} + +SEHLeaveStmt* SEHLeaveStmt::Create(ASTContext &C, + SourceLocation LeaveLoc) { + return new(C) SEHLeaveStmt(LeaveLoc); +} + SEHExceptStmt::SEHExceptStmt(SourceLocation Loc, Expr *FilterExpr, Stmt *Block) diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 0cf3aaf558..ea8878ebbb 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -537,6 +537,11 @@ void StmtPrinter::VisitSEHTryStmt(SEHTryStmt *Node) { OS << "\n"; } +void StmtPrinter::VisitSEHLeaveStmt(SEHLeaveStmt *Node) { + Indent() << "__leave;"; + OS << "\n"; +} + void StmtPrinter::PrintRawSEHFinallyStmt(SEHFinallyStmt *Node) { OS << "__finally "; PrintRawCompoundStmt(Node->getBlock()); @@ -546,7 +551,7 @@ void StmtPrinter::PrintRawSEHFinallyStmt(SEHFinallyStmt *Node) { void StmtPrinter::PrintRawSEHExceptHandler(SEHExceptStmt *Node) { OS << "__except ("; VisitExpr(Node->getFilterExpr()); - OS << ")\n"; + OS << ") "; PrintRawCompoundStmt(Node->getBlock()); OS << "\n"; } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 5d7f9f8ede..1ab789e83c 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -215,6 +215,10 @@ void StmtProfiler::VisitSEHExceptStmt(const SEHExceptStmt *S) { VisitStmt(S); } +void StmtProfiler::VisitSEHLeaveStmt(const SEHLeaveStmt *S) { + VisitStmt(S); +} + void StmtProfiler::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { VisitStmt(S); } diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 465fb968b7..c535ec41a7 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -163,6 +163,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::CXXForRangeStmtClass: EmitCXXForRangeStmt(cast(*S)); case Stmt::SEHTryStmtClass: + case Stmt::SEHLeaveStmtClass: // FIXME Not yet implemented break; } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index f58f90d56c..f46ccb255a 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -183,6 +183,19 @@ Retry: return ParseExprStatement(); } + + case tok::kw___leave: { + Token LeaveTok = Tok; + ConsumeToken(); + if (getCurScope()->isSEHTryScope()) { + Res = Actions.ActOnSEHLeaveStmt(LeaveTok.getLocation()); + } else { + Diag(LeaveTok, diag::err_seh___try_block) + << LeaveTok.getIdentifierInfo()->getName(); + Res = StmtError(); + } + break; + } case tok::kw_case: // C99 6.8.1: labeled-statement return ParseCaseStatement(); @@ -322,7 +335,9 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) { if(Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok,diag::err_expected_lbrace)); - StmtResult TryBlock(ParseCompoundStatement()); + // Use the SEHTryScope to handle __leave as a statement. + unsigned ScopeFlags = Scope::DeclScope | Scope::SEHTryScope; + StmtResult TryBlock(ParseCompoundStatement(false /*isStmtExpr*/, ScopeFlags)); if(TryBlock.isInvalid()) return TryBlock; diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 76410e20ac..e9866ffb3b 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -2745,6 +2745,12 @@ Sema::ActOnSEHTryBlock(bool IsCXXTry, return Owned(SEHTryStmt::Create(Context,IsCXXTry,TryLoc,TryBlock,Handler)); } +StmtResult +Sema::ActOnSEHLeaveStmt(SourceLocation LeaveLoc) +{ + return Owned(SEHLeaveStmt::Create(Context, LeaveLoc)); +} + StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 19636f4143..10eb52a890 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1361,6 +1361,10 @@ public: return getSema().ActOnSEHTryBlock(IsCXXTry,TryLoc,TryBlock,Handler); } + StmtResult RebuildSEHLeaveStmt(SourceLocation LeaveLoc) { + return getSema().ActOnSEHLeaveStmt(LeaveLoc); + } + StmtResult RebuildSEHExceptStmt(SourceLocation Loc, Expr *FilterExpr, Stmt *Block) { @@ -5999,6 +6003,12 @@ TreeTransform::TransformSEHTryStmt(SEHTryStmt *S) { Handler.take()); } +template +StmtResult +TreeTransform::TransformSEHLeaveStmt(SEHLeaveStmt *S) { + return getDerived().RebuildSEHLeaveStmt(S->getLeaveLoc()); +} + template StmtResult TreeTransform::TransformSEHFinallyStmt(SEHFinallyStmt *S) { diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 6ca450b9fb..3252c7db58 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1516,6 +1516,11 @@ void ASTStmtReader::VisitSEHTryStmt(SEHTryStmt *S) { S->Children[SEHTryStmt::HANDLER] = Reader.ReadSubStmt(); } +void ASTStmtReader::VisitSEHLeaveStmt(SEHLeaveStmt *S) { + VisitStmt(S); + S->LeaveLoc = ReadSourceLocation(Record, Idx); +} + //===----------------------------------------------------------------------===// // CUDA Expressions and Statements //===----------------------------------------------------------------------===// @@ -1986,6 +1991,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { case STMT_SEH_TRY: S = new (Context) SEHTryStmt(Empty); break; + case STMT_SEH_LEAVE: + S = new (Context) SEHLeaveStmt(Empty); + break; case STMT_CXX_CATCH: S = new (Context) CXXCatchStmt(Empty); break; diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 5fa08d256c..9d626d1b59 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1554,6 +1554,12 @@ void ASTStmtWriter::VisitSEHTryStmt(SEHTryStmt *S) { Code = serialization::STMT_SEH_TRY; } +void ASTStmtWriter::VisitSEHLeaveStmt(SEHLeaveStmt *S) { + VisitStmt(S); + Writer.AddSourceLocation(S->getLeaveLoc(), Record); + Code = serialization::STMT_SEH_LEAVE; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 4225c67dc7..5c4492a48c 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -527,6 +527,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::PackExpansionExprClass: case Stmt::SubstNonTypeTemplateParmPackExprClass: case Stmt::SEHTryStmtClass: + case Stmt::SEHLeaveStmtClass: case Stmt::SEHExceptStmtClass: case Stmt::LambdaExprClass: case Stmt::SEHFinallyStmtClass: { diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c index 7703999d67..57eee04c23 100644 --- a/test/Parser/MicrosoftExtensions.c +++ b/test/Parser/MicrosoftExtensions.c @@ -102,3 +102,9 @@ __declspec() void quux( void ) { struct S7 s; int i = s.t; /* expected-warning {{'t' is deprecated}} */ } + +void SEH() { + __try { __leave; } __except (0) {} + __try { } __except (0) { __leave; } // expected-error {{__leave only allowed in __try block}} + __try { } __finally { __leave; } // expected-error {{__leave only allowed in __try block}} +} \ No newline at end of file diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h index ab96f36205..6642d81d61 100644 --- a/tools/libclang/RecursiveASTVisitor.h +++ b/tools/libclang/RecursiveASTVisitor.h @@ -2122,6 +2122,7 @@ DEF_TRAVERSE_STMT(UnresolvedMemberExpr, { }) DEF_TRAVERSE_STMT(SEHTryStmt, {}) +DEF_TRAVERSE_STMT(SEHLeaveStmt, {}) DEF_TRAVERSE_STMT(SEHExceptStmt, {}) DEF_TRAVERSE_STMT(SEHFinallyStmt,{}) -- 2.50.1