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
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 5b0db86..380ad94 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -710,3 +710,61 @@
 Expr* ReturnStmt::getRetValue() {
   return cast_or_null<Expr>(RetExpr);
 }
+
+SEHTryStmt::SEHTryStmt(bool IsCXXTry,
+                       SourceLocation TryLoc,
+                       Stmt *TryBlock,
+                       Stmt *Handler)
+  : Stmt(SEHTryStmtClass),
+    IsCXXTry(IsCXXTry),
+    TryLoc(TryLoc)
+{
+  Children[TRY]     = TryBlock;
+  Children[HANDLER] = Handler;
+}
+
+SEHTryStmt* SEHTryStmt::Create(ASTContext &C,
+                               bool IsCXXTry,
+                               SourceLocation TryLoc,
+                               Stmt *TryBlock,
+                               Stmt *Handler) {
+  return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler);
+}
+
+SEHExceptStmt* SEHTryStmt::getExceptHandler() const {
+  return dyn_cast<SEHExceptStmt>(getHandler());
+}
+
+SEHFinallyStmt* SEHTryStmt::getFinallyHandler() const {
+  return dyn_cast<SEHFinallyStmt>(getHandler());
+}
+
+SEHExceptStmt::SEHExceptStmt(SourceLocation Loc,
+                             Expr *FilterExpr,
+                             Stmt *Block)
+  : Stmt(SEHExceptStmtClass),
+    Loc(Loc)
+{
+  Children[FILTER_EXPR] = reinterpret_cast<Stmt*>(FilterExpr);
+  Children[BLOCK]       = Block;
+}
+
+SEHExceptStmt* SEHExceptStmt::Create(ASTContext &C,
+                                     SourceLocation Loc,
+                                     Expr *FilterExpr,
+                                     Stmt *Block) {
+  return new(C) SEHExceptStmt(Loc,FilterExpr,Block);
+}
+
+SEHFinallyStmt::SEHFinallyStmt(SourceLocation Loc,
+                               Stmt *Block)
+  : Stmt(SEHFinallyStmtClass),
+    Loc(Loc),
+    Block(Block)
+{}
+
+SEHFinallyStmt* SEHFinallyStmt::Create(ASTContext &C,
+                                       SourceLocation Loc,
+                                       Stmt *Block) {
+  return new(C)SEHFinallyStmt(Loc,Block);
+}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 62f06db..fa0e091 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -66,6 +66,8 @@
     void PrintRawIfStmt(IfStmt *If);
     void PrintRawCXXCatchStmt(CXXCatchStmt *Catch);
     void PrintCallArgs(CallExpr *E);
+    void PrintRawSEHExceptHandler(SEHExceptStmt *S);
+    void PrintRawSEHFinallyStmt(SEHFinallyStmt *S);
 
     void PrintExpr(Expr *E) {
       if (E)
@@ -473,6 +475,46 @@
   OS << "\n";
 }
 
+void StmtPrinter::VisitSEHTryStmt(SEHTryStmt *Node) {
+  Indent() << (Node->getIsCXXTry() ? "try " : "__try ");
+  PrintRawCompoundStmt(Node->getTryBlock());
+  SEHExceptStmt *E = Node->getExceptHandler();
+  SEHFinallyStmt *F = Node->getFinallyHandler();
+  if(E)
+    PrintRawSEHExceptHandler(E);
+  else {
+    assert(F && "Must have a finally block...");
+    PrintRawSEHFinallyStmt(F);
+  }
+  OS << "\n";
+}
+
+void StmtPrinter::PrintRawSEHFinallyStmt(SEHFinallyStmt *Node) {
+  OS << "__finally ";
+  PrintRawCompoundStmt(Node->getBlock());
+  OS << "\n";
+}
+
+void StmtPrinter::PrintRawSEHExceptHandler(SEHExceptStmt *Node) {
+  OS << "__except (";
+  VisitExpr(Node->getFilterExpr());
+  OS << ")\n";
+  PrintRawCompoundStmt(Node->getBlock());
+  OS << "\n";
+}
+
+void StmtPrinter::VisitSEHExceptStmt(SEHExceptStmt *Node) {
+  Indent();
+  PrintRawSEHExceptHandler(Node);
+  OS << "\n";
+}
+
+void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) {
+  Indent();
+  PrintRawSEHFinallyStmt(Node);
+  OS << "\n";
+}
+
 //===----------------------------------------------------------------------===//
 //  Expr printing methods.
 //===----------------------------------------------------------------------===//
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 7a3fc54..17383c1 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -181,6 +181,18 @@
   VisitStmt(S);
 }
 
+void StmtProfiler::VisitSEHTryStmt(SEHTryStmt *S) {
+  VisitStmt(S);
+}
+
+void StmtProfiler::VisitSEHFinallyStmt(SEHFinallyStmt *S) {
+  VisitStmt(S);
+}
+
+void StmtProfiler::VisitSEHExceptStmt(SEHExceptStmt *S) {
+  VisitStmt(S);
+}
+
 void StmtProfiler::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
   VisitStmt(S);
 }
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 0acedef..99bc3f4 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -72,6 +72,8 @@
   switch (S->getStmtClass()) {
   case Stmt::NoStmtClass:
   case Stmt::CXXCatchStmtClass:
+  case Stmt::SEHExceptStmtClass:
+  case Stmt::SEHFinallyStmtClass:
     llvm_unreachable("invalid statement class to emit generically");
   case Stmt::NullStmtClass:
   case Stmt::CompoundStmtClass:
@@ -155,6 +157,8 @@
     break;
   case Stmt::CXXForRangeStmtClass:
     EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S));
+  case Stmt::SEHTryStmtClass:
+    // FIXME Not yet implemented
     break;
   }
 }
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index f5cdb01..31fd667 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -89,6 +89,7 @@
   // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro.
   // This gets unpoisoned where it is allowed.
   (Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned();
+  SetPoisonReason(Ident__VA_ARGS__,diag::ext_pp_bad_vaargs_use);
 
   // Initialize the pragma handlers.
   PragmaHandlers = new PragmaNamespace(llvm::StringRef());
@@ -96,6 +97,23 @@
 
   // Initialize builtin macros like __LINE__ and friends.
   RegisterBuiltinMacros();
+
+  if(Features.Borland) {
+    Ident__exception_info        = getIdentifierInfo("_exception_info");
+    Ident___exception_info       = getIdentifierInfo("__exception_info");
+    Ident_GetExceptionInfo       = getIdentifierInfo("GetExceptionInformation");
+    Ident__exception_code        = getIdentifierInfo("_exception_code");
+    Ident___exception_code       = getIdentifierInfo("__exception_code");
+    Ident_GetExceptionCode       = getIdentifierInfo("GetExceptionCode");
+    Ident__abnormal_termination  = getIdentifierInfo("_abnormal_termination");
+    Ident___abnormal_termination = getIdentifierInfo("__abnormal_termination");
+    Ident_AbnormalTermination    = getIdentifierInfo("AbnormalTermination");
+  } else {
+    Ident__exception_info = Ident__exception_code = Ident__abnormal_termination = 0;
+    Ident___exception_info = Ident___exception_code = Ident___abnormal_termination = 0;
+    Ident_GetExceptionInfo = Ident_GetExceptionCode = Ident_AbnormalTermination = 0;
+  }
+
 }
 
 Preprocessor::~Preprocessor() {
@@ -399,6 +417,34 @@
   return II;
 }
 
+void Preprocessor::SetPoisonReason(IdentifierInfo *II, unsigned DiagID) {
+  PoisonReasons[II] = DiagID;
+}
+
+void Preprocessor::PoisonSEHIdentifiers(bool Poison) {
+  assert(Ident__exception_code && Ident__exception_info);
+  assert(Ident___exception_code && Ident___exception_info);
+  Ident__exception_code->setIsPoisoned(Poison);
+  Ident___exception_code->setIsPoisoned(Poison);
+  Ident_GetExceptionCode->setIsPoisoned(Poison);
+  Ident__exception_info->setIsPoisoned(Poison);
+  Ident___exception_info->setIsPoisoned(Poison);
+  Ident_GetExceptionInfo->setIsPoisoned(Poison);
+  Ident__abnormal_termination->setIsPoisoned(Poison);
+  Ident___abnormal_termination->setIsPoisoned(Poison);
+  Ident_AbnormalTermination->setIsPoisoned(Poison);
+}
+
+void Preprocessor::HandlePoisonedIdentifier(Token & Identifier) {
+  assert(Identifier.getIdentifierInfo() &&
+         "Can't handle identifiers without identifier info!");
+  llvm::DenseMap<IdentifierInfo*,unsigned>::const_iterator it =
+    PoisonReasons.find(Identifier.getIdentifierInfo());
+  if(it == PoisonReasons.end())
+    Diag(Identifier, diag::err_pp_used_poisoned_id);
+  else
+    Diag(Identifier,it->second) << Identifier.getIdentifierInfo();
+}
 
 /// HandleIdentifier - This callback is invoked when the lexer reads an
 /// identifier.  This callback looks up the identifier in the map and/or
@@ -417,10 +463,7 @@
   // If this identifier was poisoned, and if it was not produced from a macro
   // expansion, emit an error.
   if (II.isPoisoned() && CurPPLexer) {
-    if (&II != Ident__VA_ARGS__)   // We warn about __VA_ARGS__ with poisoning.
-      Diag(Identifier, diag::err_pp_used_poisoned_id);
-    else
-      Diag(Identifier, diag::ext_pp_bad_vaargs_use);
+    HandlePoisonedIdentifier(Identifier);
   }
 
   // If this is a macro to be expanded, do it.
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index f1e1596..65aff0d 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -367,11 +367,7 @@
     // won't be handled by Preprocessor::HandleIdentifier because this is coming
     // from a macro expansion.
     if (II->isPoisoned() && TokenIsFromPaste) {
-      // We warn about __VA_ARGS__ with poisoning.
-      if (II->isStr("__VA_ARGS__"))
-        PP.Diag(Tok, diag::ext_pp_bad_vaargs_use);
-      else
-        PP.Diag(Tok, diag::err_pp_used_poisoned_id);
+      PP.HandlePoisonedIdentifier(Tok);
     }
 
     if (!DisableMacroExpansion && II->isHandleIdentifierCase())
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index c41798e..92cdfff 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1915,6 +1915,8 @@
 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 07cef55..3741ccb 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -40,6 +40,7 @@
 ///         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 @@
 
   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 @@
   // 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 @@
 ///       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 @@
   if (TryBlock.isInvalid())
     return move(TryBlock);
 
-  StmtVector Handlers(Actions);
-  MaybeParseCXX0XAttributes(attrs);
-  ProhibitAttributes(attrs);
+  // 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);
 
-  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());
+    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 ee4ef42..4d08699 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -438,6 +438,32 @@
   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 @@
 ///
 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 583f184..3765f92 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -112,7 +112,31 @@
       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
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 38f3bf9..65cea7a 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -2231,3 +2231,36 @@
   return Owned(CXXTryStmt::Create(Context, TryLoc, TryBlock,
                                   Handlers, NumHandlers));
 }
+
+StmtResult
+Sema::ActOnSEHTryBlock(bool IsCXXTry,
+                       SourceLocation TryLoc,
+                       Stmt *TryBlock,
+                       Stmt *Handler) {
+  assert(TryBlock && Handler);
+
+  getCurFunction()->setHasBranchProtectedScope();
+
+  return Owned(SEHTryStmt::Create(Context,IsCXXTry,TryLoc,TryBlock,Handler));
+}
+
+StmtResult
+Sema::ActOnSEHExceptBlock(SourceLocation Loc,
+                          Expr *FilterExpr,
+                          Stmt *Block) {
+  assert(FilterExpr && Block);
+
+  if(!FilterExpr->getType()->isIntegerType()) {
+    return StmtError(Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral) << FilterExpr->getType());
+  }
+
+  return Owned(SEHExceptStmt::Create(Context,Loc,FilterExpr,Block));
+}
+
+StmtResult
+Sema::ActOnSEHFinallyBlock(SourceLocation Loc,
+                           Stmt *Block) {
+  assert(Block);
+  return Owned(SEHFinallyStmt::Create(Context,Loc,Block));
+}
+
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index f5ec3a2..9f38f2a 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -490,6 +490,9 @@
   QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T);
 #include "clang/AST/TypeLocNodes.def"
 
+  StmtResult
+  TransformSEHHandler(Stmt *Handler);
+
   QualType 
   TransformTemplateSpecializationType(TypeLocBuilder &TLB,
                                       TemplateSpecializationTypeLoc TL,
@@ -1254,6 +1257,24 @@
     return getSema().FinishCXXForRangeStmt(ForRange, Body);
   }
   
+  StmtResult RebuildSEHTryStmt(bool IsCXXTry,
+                               SourceLocation TryLoc,
+                               Stmt *TryBlock,
+                               Stmt *Handler) {
+    return getSema().ActOnSEHTryBlock(IsCXXTry,TryLoc,TryBlock,Handler);
+  }
+
+  StmtResult RebuildSEHExceptStmt(SourceLocation Loc,
+                                  Expr *FilterExpr,
+                                  Stmt *Block) {
+    return getSema().ActOnSEHExceptBlock(Loc,FilterExpr,Block);
+  }
+
+  StmtResult RebuildSEHFinallyStmt(SourceLocation Loc,
+                                   Stmt *Block) {
+    return getSema().ActOnSEHFinallyBlock(Loc,Block);
+  }
+
   /// \brief Build a new expression that references a declaration.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -5471,6 +5492,57 @@
   return FinishCXXForRangeStmt(NewStmt.get(), Body.get());
 }
 
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) {
+  StmtResult TryBlock; //  = getDerived().TransformCompoundStmt(S->getTryBlock());
+  if(TryBlock.isInvalid()) return StmtError();
+
+  StmtResult Handler = getDerived().TransformSEHHandler(S->getHandler());
+  if(!getDerived().AlwaysRebuild() &&
+     TryBlock.get() == S->getTryBlock() &&
+     Handler.get() == S->getHandler())
+    return SemaRef.Owned(S);
+
+  return getDerived().RebuildSEHTryStmt(S->getIsCXXTry(),
+                                        S->getTryLoc(),
+                                        TryBlock.take(),
+                                        Handler.take());
+}
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformSEHFinallyStmt(SEHFinallyStmt *S) {
+  StmtResult Block; //  = getDerived().TransformCompoundStatement(S->getBlock());
+  if(Block.isInvalid()) return StmtError();
+
+  return getDerived().RebuildSEHFinallyStmt(S->getFinallyLoc(),
+                                            Block.take());
+}
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformSEHExceptStmt(SEHExceptStmt *S) {
+  ExprResult FilterExpr = getDerived().TransformExpr(S->getFilterExpr());
+  if(FilterExpr.isInvalid()) return StmtError();
+
+  StmtResult Block; //  = getDerived().TransformCompoundStatement(S->getBlock());
+  if(Block.isInvalid()) return StmtError();
+
+  return getDerived().RebuildSEHExceptStmt(S->getExceptLoc(),
+                                           FilterExpr.take(),
+                                           Block.take());
+}
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformSEHHandler(Stmt *Handler) {
+  if(isa<SEHFinallyStmt>(Handler))
+    return getDerived().TransformSEHFinallyStmt(cast<SEHFinallyStmt>(Handler));
+  else
+    return getDerived().TransformSEHExceptStmt(cast<SEHExceptStmt>(Handler));
+}
+
 //===----------------------------------------------------------------------===//
 // Expression transformation
 //===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 5c1dfb8..657420d 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -442,6 +442,9 @@
     case Stmt::CXXNoexceptExprClass:
     case Stmt::PackExpansionExprClass:
     case Stmt::SubstNonTypeTemplateParmPackExprClass:
+    case Stmt::SEHTryStmtClass:
+    case Stmt::SEHExceptStmtClass:
+    case Stmt::SEHFinallyStmtClass:
     {
       SaveAndRestore<bool> OldSink(Builder->BuildSinks);
       Builder->BuildSinks = true;