diff options
author | John Wiegley <johnw@boostpro.com> | 2011-04-28 01:08:34 +0000 |
---|---|---|
committer | John Wiegley <johnw@boostpro.com> | 2011-04-28 01:08:34 +0000 |
commit | 28bbe4b8acc338476fe0825769b41fb32b423c72 (patch) | |
tree | 93a24e53fba644d6caa1db0b82cd678ef8fb0f8d /lib/Parse | |
parent | 61d0b6baf47cf411f6c0f6ddb4acffcfeec724f1 (diff) |
Parsing/AST support for Structured Exception Handling
Patch authored by Sohail Somani.
Provide parsing and AST support for Windows structured exception handling.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130366 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 159 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 28 | ||||
-rw-r--r-- | lib/Parse/RAIIObjectsForParser.h | 26 |
4 files changed, 199 insertions, 16 deletions
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index c41798e35e..92cdfffdc0 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1915,6 +1915,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'"); + // Poison the SEH identifiers so they are flagged as illegal in constructor initializers + PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true); SourceLocation ColonLoc = ConsumeToken(); llvm::SmallVector<CXXCtorInitializer*, 4> MemInitializers; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 07cef5597b..3741ccbca1 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -40,6 +40,7 @@ using namespace clang; /// jump-statement /// [C++] declaration-statement /// [C++] try-block +/// [MS] seh-try-block /// [OBC] objc-throw-statement /// [OBC] objc-try-catch-statement /// [OBC] objc-synchronized-statement @@ -272,6 +273,9 @@ Retry: case tok::kw_try: // C++ 15: try-block return ParseCXXTryBlock(attrs); + + case tok::kw___try: + return ParseSEHTryBlock(attrs); } // If we reached this code, the statement must end in a semicolon. @@ -321,7 +325,106 @@ StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) { // Otherwise, eat the semicolon. ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get())); +} +StmtResult Parser::ParseSEHTryBlock(ParsedAttributes & Attrs) { + assert(Tok.is(tok::kw___try) && "Expected '__try'"); + SourceLocation Loc = ConsumeToken(); + return ParseSEHTryBlockCommon(Loc); +} + +/// ParseSEHTryBlockCommon +/// +/// seh-try-block: +/// '__try' compound-statement seh-handler +/// +/// seh-handler: +/// seh-except-block +/// seh-finally-block +/// +StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) { + if(Tok.isNot(tok::l_brace)) + return StmtError(Diag(Tok,diag::err_expected_lbrace)); + + ParsedAttributesWithRange attrs(AttrFactory); + StmtResult TryBlock(ParseCompoundStatement(attrs)); + if(TryBlock.isInvalid()) + return move(TryBlock); + + StmtResult Handler; + if(Tok.is(tok::kw___except)) { + SourceLocation Loc = ConsumeToken(); + Handler = ParseSEHExceptBlock(Loc); + } else if (Tok.is(tok::kw___finally)) { + SourceLocation Loc = ConsumeToken(); + Handler = ParseSEHFinallyBlock(Loc); + } else { + return StmtError(Diag(Tok,diag::err_seh_expected_handler)); + } + + if(Handler.isInvalid()) + return move(Handler); + + return Actions.ActOnSEHTryBlock(false /* IsCXXTry */, + TryLoc, + TryBlock.take(), + Handler.take()); +} + +/// ParseSEHExceptBlock - Handle __except +/// +/// seh-except-block: +/// '__except' '(' seh-filter-expression ')' compound-statement +/// +StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { + PoisonIdentifierRAIIObject raii(Ident__exception_code, false), + raii2(Ident___exception_code, false), + raii3(Ident_GetExceptionCode, false); + + if(ExpectAndConsume(tok::l_paren,diag::err_expected_lparen)) + return StmtError(); + + ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope); + + Ident__exception_info->setIsPoisoned(false); + Ident___exception_info->setIsPoisoned(false); + Ident_GetExceptionInfo->setIsPoisoned(false); + ExprResult FilterExpr(ParseExpression()); + Ident__exception_info->setIsPoisoned(true); + Ident___exception_info->setIsPoisoned(true); + Ident_GetExceptionInfo->setIsPoisoned(true); + + if(FilterExpr.isInvalid()) + return StmtError(); + + if(ExpectAndConsume(tok::r_paren,diag::err_expected_rparen)) + return StmtError(); + + ParsedAttributesWithRange attrs(AttrFactory); + StmtResult Block(ParseCompoundStatement(attrs)); + + if(Block.isInvalid()) + return move(Block); + + return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.take(), Block.take()); +} + +/// ParseSEHFinallyBlock - Handle __finally +/// +/// seh-finally-block: +/// '__finally' compound-statement +/// +StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) { + PoisonIdentifierRAIIObject raii(Ident__abnormal_termination, false), + raii2(Ident___abnormal_termination, false), + raii3(Ident_AbnormalTermination, false); + + ParsedAttributesWithRange attrs(AttrFactory); + StmtResult Block(ParseCompoundStatement(attrs)); + if(Block.isInvalid()) + return move(Block); + + return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.take()); } /// ParseLabeledStatement - We have an identifier and a ':' after it. @@ -1786,6 +1889,10 @@ StmtResult Parser::ParseCXXTryBlock(ParsedAttributes &attrs) { /// handler-seq: /// handler handler-seq[opt] /// +/// [Borland] try-block: +/// 'try' compound-statement seh-except-block +/// 'try' compound-statment seh-finally-block +/// StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); @@ -1795,23 +1902,45 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (TryBlock.isInvalid()) return move(TryBlock); - StmtVector Handlers(Actions); - MaybeParseCXX0XAttributes(attrs); - ProhibitAttributes(attrs); - - if (Tok.isNot(tok::kw_catch)) - return StmtError(Diag(Tok, diag::err_expected_catch)); - while (Tok.is(tok::kw_catch)) { - StmtResult Handler(ParseCXXCatchBlock()); - if (!Handler.isInvalid()) - Handlers.push_back(Handler.release()); + // Borland allows SEH-handlers with 'try' + if(Tok.is(tok::kw___except) || Tok.is(tok::kw___finally)) { + // TODO: Factor into common return ParseSEHHandlerCommon(...) + StmtResult Handler; + if(Tok.is(tok::kw___except)) { + SourceLocation Loc = ConsumeToken(); + Handler = ParseSEHExceptBlock(Loc); + } + else { + SourceLocation Loc = ConsumeToken(); + Handler = ParseSEHFinallyBlock(Loc); + } + if(Handler.isInvalid()) + return move(Handler); + + return Actions.ActOnSEHTryBlock(true /* IsCXXTry */, + TryLoc, + TryBlock.take(), + Handler.take()); } - // Don't bother creating the full statement if we don't have any usable - // handlers. - if (Handlers.empty()) - return StmtError(); + else { + StmtVector Handlers(Actions); + MaybeParseCXX0XAttributes(attrs); + ProhibitAttributes(attrs); - return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), move_arg(Handlers)); + if (Tok.isNot(tok::kw_catch)) + return StmtError(Diag(Tok, diag::err_expected_catch)); + while (Tok.is(tok::kw_catch)) { + StmtResult Handler(ParseCXXCatchBlock()); + if (!Handler.isInvalid()) + Handlers.push_back(Handler.release()); + } + // Don't bother creating the full statement if we don't have any usable + // handlers. + if (Handlers.empty()) + return StmtError(); + + return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), move_arg(Handlers)); + } } /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index ee4ef4263a..4d08699bdd 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -438,6 +438,32 @@ void Parser::Initialize() { Ident_deprecated = 0; Ident_obsoleted = 0; Ident_unavailable = 0; + + Ident__exception_code = Ident__exception_info = Ident__abnormal_termination = 0; + Ident___exception_code = Ident___exception_info = Ident___abnormal_termination = 0; + Ident_GetExceptionCode = Ident_GetExceptionInfo = Ident_AbnormalTermination = 0; + + if(getLang().Borland) { + Ident__exception_info = PP.getIdentifierInfo("_exception_info"); + Ident___exception_info = PP.getIdentifierInfo("__exception_info"); + Ident_GetExceptionInfo = PP.getIdentifierInfo("GetExceptionInformation"); + Ident__exception_code = PP.getIdentifierInfo("_exception_code"); + Ident___exception_code = PP.getIdentifierInfo("__exception_code"); + Ident_GetExceptionCode = PP.getIdentifierInfo("GetExceptionCode"); + Ident__abnormal_termination = PP.getIdentifierInfo("_abnormal_termination"); + Ident___abnormal_termination = PP.getIdentifierInfo("__abnormal_termination"); + Ident_AbnormalTermination = PP.getIdentifierInfo("AbnormalTermination"); + + PP.SetPoisonReason(Ident__exception_code,diag::err_seh___except_block); + PP.SetPoisonReason(Ident___exception_code,diag::err_seh___except_block); + PP.SetPoisonReason(Ident_GetExceptionCode,diag::err_seh___except_block); + PP.SetPoisonReason(Ident__exception_info,diag::err_seh___except_filter); + PP.SetPoisonReason(Ident___exception_info,diag::err_seh___except_filter); + PP.SetPoisonReason(Ident_GetExceptionInfo,diag::err_seh___except_filter); + PP.SetPoisonReason(Ident__abnormal_termination,diag::err_seh___finally_block); + PP.SetPoisonReason(Ident___abnormal_termination,diag::err_seh___finally_block); + PP.SetPoisonReason(Ident_AbnormalTermination,diag::err_seh___finally_block); + } } /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the @@ -766,6 +792,8 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs, /// Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo) { + // Poison the SEH identifiers so they are flagged as illegal in function bodies + PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true); const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); // If this is C90 and the declspecs were completely missing, fudge in an diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h index 583f18428d..3765f92348 100644 --- a/lib/Parse/RAIIObjectsForParser.h +++ b/lib/Parse/RAIIObjectsForParser.h @@ -112,7 +112,31 @@ namespace clang { P.BraceCount = BraceCount; } }; - + + class PoisonSEHIdentifiersRAIIObject { + PoisonIdentifierRAIIObject Ident_AbnormalTermination; + PoisonIdentifierRAIIObject Ident_GetExceptionCode; + PoisonIdentifierRAIIObject Ident_GetExceptionInfo; + PoisonIdentifierRAIIObject Ident__abnormal_termination; + PoisonIdentifierRAIIObject Ident__exception_code; + PoisonIdentifierRAIIObject Ident__exception_info; + PoisonIdentifierRAIIObject Ident___abnormal_termination; + PoisonIdentifierRAIIObject Ident___exception_code; + PoisonIdentifierRAIIObject Ident___exception_info; + public: + PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue) + : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue), + Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue), + Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue), + Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue), + Ident__exception_code(Self.Ident__exception_code, NewValue), + Ident__exception_info(Self.Ident__exception_info, NewValue), + Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue), + Ident___exception_code(Self.Ident___exception_code, NewValue), + Ident___exception_info(Self.Ident___exception_info, NewValue) { + } + }; + } // end namespace clang #endif |