Hi rjmccall, rsmith, majnemer,

Most of the complexity here is emitting filter expressions as standalone
LLVM functions. The filter functions are used in catch clauses in place
of type_info globals, and LLVM does the rest of the lowering.

Major aspects that still need work:
- __try body outlining with noinline and optnone.
- Cleanup support for __finally and destructors. LLVM won't be able to
  lower the current IR to anything useful.
- Local variable access in filter expressions.
- Don't use TLS to figure out which filter function fired. This requires
  work in LLVM.

http://reviews.llvm.org/D5607

Files:
  include/clang/AST/Decl.h
  include/clang/AST/Mangle.h
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticCommonKinds.td
  include/clang/Basic/DiagnosticParseKinds.td
  include/clang/Sema/Scope.h
  lib/AST/ItaniumMangle.cpp
  lib/AST/MicrosoftMangle.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/CodeGen/CGException.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Parse/ParseStmt.cpp
  lib/Sema/JumpDiagnostics.cpp
  lib/Sema/Scope.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/exceptions-seh-leave.c
  test/CodeGen/exceptions-seh.c
  test/OpenMP/parallel_codegen.cpp
  test/Sema/__try.c
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -1477,6 +1477,7 @@
   bool HasImplicitReturnZero : 1;
   bool IsLateTemplateParsed : 1;
   bool IsConstexpr : 1;
+  bool HasSEHTry : 1;
 
   /// \brief Indicates if the function was a definition but its body was
   /// skipped.
@@ -1566,8 +1567,8 @@
       HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
       IsDefaulted(false), IsExplicitlyDefaulted(false),
       HasImplicitReturnZero(false), IsLateTemplateParsed(false),
-      IsConstexpr(isConstexprSpecified), HasSkippedBody(false),
-      EndRangeLoc(NameInfo.getEndLoc()),
+      IsConstexpr(isConstexprSpecified), HasSEHTry(false),
+      HasSkippedBody(false), EndRangeLoc(NameInfo.getEndLoc()),
       TemplateOrSpecialization(),
       DNLoc(NameInfo.getInfo()) {}
 
Index: include/clang/AST/Mangle.h
===================================================================
--- include/clang/AST/Mangle.h
+++ include/clang/AST/Mangle.h
@@ -132,6 +132,9 @@
   virtual void mangleDynamicAtExitDestructor(const VarDecl *D,
                                              raw_ostream &) = 0;
 
+  virtual void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
+                                         raw_ostream &Out) = 0;
+
   /// Generates a unique string for an externally visible type for use with TBAA
   /// or type uniquing.
   /// TODO: Extend this to internal types by generating names that are unique
Index: include/clang/Basic/Builtins.def
===================================================================
--- include/clang/Basic/Builtins.def
+++ include/clang/Basic/Builtins.def
@@ -691,11 +691,15 @@
 BUILTIN(__builtin_rindex, "c*cC*i", "Fn")
 
 // Microsoft builtins.  These are only active with -fms-extensions.
-LANGBUILTIN(_alloca,      "v*z", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(__assume,     "vb",  "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(__noop,       "i.",  "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(__debugbreak, "v",   "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(__va_start,   "vc**.", "nt", ALL_MS_LANGUAGES)
+LANGBUILTIN(_alloca,          "v*z", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__assume,         "vb",  "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_exception_code,  "ULi", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__exception_code, "ULi", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_exception_info,  "v*",  "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__exception_info, "v*",  "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__noop,           "i.",  "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__debugbreak,     "v",   "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__va_start,       "vc**.", "nt", ALL_MS_LANGUAGES)
 LANGBUILTIN(_InterlockedCompareExchange, "LiLiD*LiLi", "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
Index: include/clang/Basic/DiagnosticCommonKinds.td
===================================================================
--- include/clang/Basic/DiagnosticCommonKinds.td
+++ include/clang/Basic/DiagnosticCommonKinds.td
@@ -112,6 +112,16 @@
   "interpreting as unsigned">,
   InGroup<DiagGroup<"implicitly-unsigned-literal">>;
 
+// SEH
+def err_seh_expected_handler : Error<
+  "expected '__except' or '__finally' block">;
+def err_seh___except_block : Error<
+  "%0 only allowed in __except block or filter expression">;
+def err_seh___except_filter : Error<
+  "%0 only allowed in __except filter expression">;
+def err_seh___finally_block : Error<
+  "%0 only allowed in __finally block">;
+
 // Sema && AST
 def note_invalid_subexpr_in_const_expr : Note<
   "subexpression not valid in a constant expression">;
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -916,18 +916,6 @@
 def warn_pragma_unknown_extension : Warning<
   "unknown OpenCL extension %0 - ignoring">, InGroup<IgnoredPragmas>;
 
-def err_seh_expected_handler : Error<
-  "expected '__except' or '__finally' block">;
-
-def err_seh___except_block : Error<
-  "%0 only allowed in __except block">;
-
-def err_seh___except_filter : Error<
-  "%0 only allowed in __except filter expression">;
-
-def err_seh___finally_block : Error<
-  "%0 only allowed in __finally block">;
-
 // OpenMP support.
 def warn_pragma_omp_ignored : Warning<
   "unexpected '#pragma omp ...' in program">, InGroup<SourceUsesOpenMP>, DefaultIgnore;
Index: include/clang/Sema/Scope.h
===================================================================
--- include/clang/Sema/Scope.h
+++ include/clang/Sema/Scope.h
@@ -115,8 +115,11 @@
     /// This scope corresponds to an enum.
     EnumScope = 0x40000,
 
-    /// This scope corresponds to a SEH try.
+    /// This scope corresponds to an SEH try.
     SEHTryScope = 0x80000,
+
+    /// This scope corresponds to an SEH except.
+    SEHExceptScope = 0x100000,
   };
 private:
   /// The parent scope for this scope.  This is null for the translation-unit
@@ -407,6 +410,9 @@
   /// \brief Determine whether this scope is a SEH '__try' block.
   bool isSEHTryScope() const { return getFlags() & Scope::SEHTryScope; }
 
+  /// \brief Determine whether this scope is a SEH '__except' block.
+  bool isSEHExceptScope() const { return getFlags() & Scope::SEHExceptScope; }
+
   /// containedInPrototypeScope - Return true if this or a parent scope
   /// is a FunctionPrototypeScope.
   bool containedInPrototypeScope() const;
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -156,6 +156,8 @@
   void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
   void mangleDynamicAtExitDestructor(const VarDecl *D,
                                      raw_ostream &Out) override;
+  void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
+                                 raw_ostream &Out) override;
   void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override;
   void mangleItaniumThreadLocalWrapper(const VarDecl *D,
                                        raw_ostream &) override;
@@ -3817,6 +3819,16 @@
     Mangler.getStream() << D->getName();
 }
 
+void ItaniumMangleContextImpl::mangleSEHFilterExpression(
+    const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+  CXXNameMangler Mangler(*this, Out);
+  Mangler.getStream() << "__filt_";
+  if (shouldMangleDeclName(EnclosingDecl))
+    Mangler.mangle(EnclosingDecl);
+  else
+    Mangler.getStream() << EnclosingDecl->getName();
+}
+
 void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D,
                                                             raw_ostream &Out) {
   //  <special-name> ::= TH <object name>
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -89,6 +89,7 @@
   llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
   llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
   llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
+  llvm::DenseMap<const NamedDecl *, unsigned> SEHFilterIds;
 
 public:
   MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
@@ -134,6 +135,8 @@
   void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
   void mangleDynamicAtExitDestructor(const VarDecl *D,
                                      raw_ostream &Out) override;
+  void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
+                                 raw_ostream &Out) override;
   void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
   bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
     // Lambda closure types are already numbered.
@@ -2316,6 +2319,18 @@
   Mangler.getStream() << '@';
 }
 
+void MicrosoftMangleContextImpl::mangleSEHFilterExpression(
+    const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+  MicrosoftCXXNameMangler Mangler(*this, Out);
+  // The function body is in the same comdat as the function with the handler,
+  // so the numbering here doesn't have to be the same across TUs.
+  //
+  // <mangled-name> ::= ?filt$ <filter-number> @0
+  Mangler.getStream() << "\01?filt$" << SEHFilterIds[EnclosingDecl]++ << "@0@";
+  // FIXME
+  Mangler.mangleName(EnclosingDecl);
+}
+
 void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
   // This is just a made up unique string for the purposes of tbaa.  undname
   // does *not* know how to demangle it.
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -1624,6 +1624,15 @@
     RMWI->setVolatile(true);
     return RValue::get(RMWI);
   }
+
+  case Builtin::BI__exception_code:
+  case Builtin::BI_exception_code: {
+    return RValue::get(EmitSEHExceptionCode());
+  }
+  case Builtin::BI__exception_info:
+  case Builtin::BI_exception_info: {
+    return RValue::get(EmitSEHExceptionInfo(E));
+  }
   }
 
   // If this is an alias for a lib function (e.g. __builtin_sin), emit
Index: lib/CodeGen/CGException.cpp
===================================================================
--- lib/CodeGen/CGException.cpp
+++ lib/CodeGen/CGException.cpp
@@ -13,8 +13,10 @@
 
 #include "CodeGenFunction.h"
 #include "CGCleanup.h"
+#include "CGCXXABI.h"
 #include "CGObjCRuntime.h"
 #include "TargetInfo.h"
+#include "clang/AST/Mangle.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/StmtObjC.h"
 #include "llvm/IR/CallSite.h"
@@ -106,9 +108,10 @@
   StringRef name;
 
   // In C++, use std::terminate().
-  if (CGM.getLangOpts().CPlusPlus)
-    name = "_ZSt9terminatev"; // FIXME: mangling!
-  else if (CGM.getLangOpts().ObjC1 &&
+  if (CGM.getLangOpts().CPlusPlus &&
+      CGM.getTarget().getCXXABI().isItaniumFamily()) {
+    name = "_ZSt9terminatev";
+  } else if (CGM.getLangOpts().ObjC1 &&
            CGM.getLangOpts().ObjCRuntime.hasTerminate())
     name = "objc_terminate";
   else
@@ -134,7 +137,7 @@
     // This function must have prototype void(void*).
     const char *CatchallRethrowFn;
 
-    static const EHPersonality &get(const LangOptions &Lang);
+    static const EHPersonality &get(CodeGenModule &CGM);
     static const EHPersonality GNU_C;
     static const EHPersonality GNU_C_SJLJ;
     static const EHPersonality GNU_C_SEH;
@@ -145,6 +148,8 @@
     static const EHPersonality GNU_CPlusPlus;
     static const EHPersonality GNU_CPlusPlus_SJLJ;
     static const EHPersonality GNU_CPlusPlus_SEH;
+    static const EHPersonality MSVC_except_handler;
+    static const EHPersonality MSVC_C_specific_handler;
   };
 }
 
@@ -167,6 +172,10 @@
 EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", nullptr };
 const EHPersonality
 EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", nullptr };
+const EHPersonality
+EHPersonality::MSVC_except_handler = { "_except_handler4", nullptr };
+const EHPersonality
+EHPersonality::MSVC_C_specific_handler = { "__C_specific_handler", nullptr };
 
 static const EHPersonality &getCPersonality(const LangOptions &L) {
   if (L.SjLjExceptions)
@@ -230,7 +239,37 @@
   llvm_unreachable("bad runtime kind");
 }
 
-const EHPersonality &EHPersonality::get(const LangOptions &L) {
+static const EHPersonality &getCPersonalityMSVC(const llvm::Triple &T,
+                                                const LangOptions &L) {
+  if (L.SjLjExceptions)
+    return EHPersonality::GNU_C_SJLJ;
+
+  if (T.getArch() == llvm::Triple::x86)
+    return EHPersonality::MSVC_except_handler;
+  return EHPersonality::MSVC_C_specific_handler;
+}
+
+static const EHPersonality &getCXXPersonalityMSVC(const llvm::Triple &T,
+                                                  const LangOptions &L) {
+  if (L.SjLjExceptions)
+    return EHPersonality::GNU_CPlusPlus_SJLJ;
+  // FIXME: Implement C++ exceptions.
+  return getCPersonalityMSVC(T, L);
+}
+
+const EHPersonality &EHPersonality::get(CodeGenModule &CGM) {
+  const llvm::Triple &T = CGM.getTarget().getTriple();
+  const LangOptions &L = CGM.getLangOpts();
+  // Try to pick a personality function that is compatible with MSVC if we're
+  // not compiling Obj-C. Obj-C users better have an Obj-C runtime that supports
+  // the GCC-style personality function.
+  if (T.isWindowsMSVCEnvironment() && !L.ObjC1) {
+    if (L.CPlusPlus)
+      return getCXXPersonalityMSVC(T, L);
+    else
+      return getCPersonalityMSVC(T, L);
+  }
+
   if (L.CPlusPlus && L.ObjC1)
     return getObjCXXPersonality(L);
   else if (L.CPlusPlus)
@@ -315,7 +354,7 @@
   if (!LangOpts.ObjCRuntime.isNeXTFamily())
     return;
 
-  const EHPersonality &ObjCXX = EHPersonality::get(LangOpts);
+  const EHPersonality &ObjCXX = EHPersonality::get(*this);
   const EHPersonality &CXX = getCXXPersonality(LangOpts);
   if (&ObjCXX == &CXX)
     return;
@@ -391,15 +430,26 @@
   CGF.DeactivateCleanupBlock(cleanup, cast<llvm::Instruction>(typedAddr));
 }
 
+/// Returns true if this landing pad is using filter functions to select catches
+/// instead of RTTI.
+static bool EHUsesFilterFunctions(CodeGenModule &CGM) {
+  const EHPersonality &P = EHPersonality::get(CGM);
+  return StringRef("__C_specific_handler") == P.PersonalityFn;
+}
+
 llvm::Value *CodeGenFunction::getExceptionSlot() {
   if (!ExceptionSlot)
     ExceptionSlot = CreateTempAlloca(Int8PtrTy, "exn.slot");
   return ExceptionSlot;
 }
 
 llvm::Value *CodeGenFunction::getEHSelectorSlot() {
-  if (!EHSelectorSlot)
-    EHSelectorSlot = CreateTempAlloca(Int32Ty, "ehselector.slot");
+  if (!EHSelectorSlot) {
+    if (EHUsesFilterFunctions(CGM))
+      EHSelectorSlot = CreateTempAlloca(VoidPtrTy, "ehselector.slot");
+    else
+      EHSelectorSlot = CreateTempAlloca(Int32Ty, "ehselector.slot");
+  }
   return EHSelectorSlot;
 }
 
@@ -712,6 +762,26 @@
   return LP;
 }
 
+/// Return a linkonce_odr __clang_seh_filter_id thread local global. This global
+/// is used to return information from SEH filter functions to landing pads when
+/// using the __C_specific_handler personality function.
+/// FIXME: Communicate through frame_pointer instead.
+static llvm::GlobalValue *getFilterFuncTLS(CodeGenModule &CGM) {
+  llvm::GlobalValue *Entry = CGM.GetGlobalValue("__clang_seh_filter_id");
+  if (Entry) {
+    assert(isa<llvm::GlobalVariable>(Entry));
+    assert(Entry->getType() == CGM.VoidPtrTy->getPointerTo());
+    assert(Entry->isThreadLocal());
+    return Entry;
+  }
+  Entry = new llvm::GlobalVariable(
+      CGM.getModule(), CGM.VoidPtrTy, /*isConstant=*/false,
+      llvm::GlobalValue::LinkOnceODRLinkage,
+      llvm::Constant::getNullValue(CGM.VoidPtrTy), "__clang_seh_filter_id");
+  Entry->setThreadLocalMode(llvm::GlobalValue::LocalDynamicTLSModel);
+  return Entry;
+}
+
 llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
   assert(EHStack.requiresLandingPad());
 
@@ -733,7 +803,7 @@
   if (CGDebugInfo *DI = getDebugInfo())
     DI->EmitLocation(Builder, CurEHLocation);
 
-  const EHPersonality &personality = EHPersonality::get(getLangOpts());
+  const EHPersonality &personality = EHPersonality::get(CGM);
 
   // Create and configure the landing pad.
   llvm::BasicBlock *lpad = createBasicBlock("lpad");
@@ -745,7 +815,11 @@
 
   llvm::Value *LPadExn = Builder.CreateExtractValue(LPadInst, 0);
   Builder.CreateStore(LPadExn, getExceptionSlot());
-  llvm::Value *LPadSel = Builder.CreateExtractValue(LPadInst, 1);
+  llvm::Value *LPadSel = nullptr;
+  if (EHUsesFilterFunctions(CGM))
+    LPadSel = Builder.CreateLoad(getFilterFuncTLS(CGM));
+  else
+    LPadSel = Builder.CreateExtractValue(LPadInst, 1);
   Builder.CreateStore(LPadSel, getEHSelectorSlot());
 
   // Save the exception pointer.  It's safe to use a single exception
@@ -1167,13 +1241,17 @@
       nextIsEnd = false;
     }
 
-    // Figure out the catch type's index in the LSDA's type table.
-    llvm::CallInst *typeIndex =
-      CGF.Builder.CreateCall(llvm_eh_typeid_for, typeValue);
-    typeIndex->setDoesNotThrow();
+    llvm::Value *IdValue = typeValue;
+    if (!EHUsesFilterFunctions(CGF.CGM)) {
+      // Figure out the catch type's index in the LSDA's type table.
+      llvm::CallInst *typeIndex =
+        CGF.Builder.CreateCall(llvm_eh_typeid_for, typeValue);
+      typeIndex->setDoesNotThrow();
+      IdValue = typeIndex;
+    }
 
     llvm::Value *matchesTypeIndex =
-      CGF.Builder.CreateICmpEQ(selector, typeIndex, "matches");
+      CGF.Builder.CreateICmpEQ(selector, IdValue, "matches");
     CGF.Builder.CreateCondBr(matchesTypeIndex, handler.Block, nextBlock);
 
     // If the next handler is a catch-all, we're completely done.
@@ -1550,7 +1628,7 @@
   Builder.SetInsertPoint(TerminateLandingPad);
 
   // Tell the backend that this is a landing pad.
-  const EHPersonality &Personality = EHPersonality::get(CGM.getLangOpts());
+  const EHPersonality &Personality = EHPersonality::get(CGM);
   llvm::LandingPadInst *LPadInst =
     Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty, NULL),
                              getOpaquePersonalityFn(CGM, Personality), 0);
@@ -1609,7 +1687,7 @@
   EHResumeBlock = createBasicBlock("eh.resume");
   Builder.SetInsertPoint(EHResumeBlock);
 
-  const EHPersonality &Personality = EHPersonality::get(CGM.getLangOpts());
+  const EHPersonality &Personality = EHPersonality::get(CGM);
 
   // This can always be a call because we necessarily didn't find
   // anything on the EH stack which needs our help.
@@ -1639,7 +1717,216 @@
 }
 
 void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
-  CGM.ErrorUnsupported(&S, "SEH __try");
+  EnterSEHTryStmt(S);
+  EmitStmt(S.getTryBlock());
+  ExitSEHTryStmt(S);
+}
+
+namespace {
+struct PerformSEHFinally : EHScopeStack::Cleanup  {
+  Stmt *Block;
+  PerformSEHFinally(Stmt *Block) : Block(Block) {}
+  void Emit(CodeGenFunction &CGF, Flags F) override { CGF.EmitStmt(Block); }
+};
+}
+
+llvm::Constant *
+CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, 
+                                           const SEHExceptStmt &Except) {
+  const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
+  llvm::Function *ParentFn = ParentCGF.CurFn;
+
+  Expr *FilterExpr = Except.getFilterExpr();
+
+  // Get the mangled function name.
+  SmallString<128> Name;
+  {
+    llvm::raw_svector_ostream OS(Name);
+    const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
+    assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
+    CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS);
+  }
+
+  // Arrange a function with the declaration:
+  // int filt(EXCEPTION_POINTERS *exception_pointers, void *frame_pointer)
+  QualType RetTy = getContext().IntTy;
+  FunctionArgList Args;
+  SEHPointersDecl = ImplicitParamDecl::Create(
+      getContext(), nullptr, FilterExpr->getLocStart(),
+      &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
+  Args.push_back(SEHPointersDecl);
+  Args.push_back(ImplicitParamDecl::Create(
+      getContext(), nullptr, FilterExpr->getLocStart(),
+      &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
+  const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration(
+      RetTy, Args, FunctionType::ExtInfo(), /*isVariadic=*/false);
+  llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
+  llvm::Function *Fn = llvm::Function::Create(FnTy, ParentFn->getLinkage(),
+                                              Name.str(), &CGM.getModule());
+
+  // The filter is either in the same comdat as the function, or it's internal.
+  if (llvm::Comdat *C = ParentFn->getComdat()) {
+    Fn->setComdat(C);
+  } else if (ParentFn->hasWeakLinkage() || ParentFn->hasLinkOnceLinkage()) {
+    llvm::Comdat *C = CGM.getModule().getOrInsertComdat(ParentFn->getName());
+    ParentFn->setComdat(C);
+    Fn->setComdat(C);
+  } else {
+    Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
+  }
+
+  StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,
+                FilterExpr->getLocStart(), FilterExpr->getLocStart());
+
+  EmitSEHExceptionCodeSave();
+
+  // Insert dummy allocas for every local variable in scope. We'll initialize
+  // them and prune the unused ones after we find out which ones were
+  // referenced.
+  for (const auto &DeclPtrs : ParentCGF.LocalDeclMap) {
+    const Decl *VD = DeclPtrs.first;
+    llvm::Value *Ptr = DeclPtrs.second;
+    auto *ValTy = cast<llvm::PointerType>(Ptr->getType())->getElementType();
+    LocalDeclMap[VD] = CreateTempAlloca(ValTy, Ptr->getName() + ".filt");
+  }
+
+  // Emit the original filter expression.
+  llvm::Value *R = EmitScalarExpr(FilterExpr);
+  R = Builder.CreateIntCast(R, CGM.IntTy,
+                            FilterExpr->getType()->isSignedIntegerType());
+  Builder.CreateStore(R, ReturnValue);
+
+  // Remember if the filter fired and store it to TLS.
+  // __clang_seh_filter_id = Result ? Fn : nullptr;
+  // FIXME: LLVM should figure out which filter fired even with the SEH
+  // personality functions.
+  llvm::Constant *VoidPtrFn = llvm::ConstantExpr::getBitCast(CurFn, Int8PtrTy);
+  llvm::Value *Cond =
+      Builder.CreateICmpEQ(R, llvm::ConstantInt::get(CGM.IntTy, 1));
+  llvm::Value *Id = Builder.CreateSelect(
+      Cond, VoidPtrFn, llvm::Constant::getNullValue(Int8PtrTy));
+  Builder.CreateStore(Id, getFilterFuncTLS(CGM));
+
+  FinishFunction(FilterExpr->getLocEnd());
+
+  // Prune unused local references to locals from the parent function, and
+  // diagnose the remaining uses until we can rewrite them to point into the
+  // parent frame.
+  // FIXME: We can use the frame_pointer parameter to write to the parent
+  // function's local stack variables instead, but probably need intrinsics to
+  // make that work.
+  for (const auto &DeclPtrs : ParentCGF.LocalDeclMap) {
+    const Decl *VD = DeclPtrs.first;
+    auto *Alloca = cast<llvm::AllocaInst>(LocalDeclMap[VD]);
+    if (Alloca->hasNUses(0)) {
+      Alloca->eraseFromParent();
+    } else {
+      ErrorUnsupported(FilterExpr,
+                       "local variable reference in SEH filter expression");
+      Alloca->replaceAllUsesWith(llvm::UndefValue::get(Alloca->getType()));
+      Alloca->eraseFromParent();
+    }
+  }
+
+  return VoidPtrFn;
+}
+
+void CodeGenFunction::EmitSEHExceptionCodeSave() {
+  // Save the exception code in the exception slot to unify exception access in
+  // the filter function and the landing pad.
+  // struct EXCEPTION_POINTERS {
+  //   EXCEPTION_RECORD *ExceptionRecord;
+  //   CONTEXT *ContextRecord;
+  // };
+  // void *exn.slot =
+  //     (void *)(uintptr_t)exception_pointers->ExceptionRecord->ExceptionCode;
+  llvm::Value *Ptrs = Builder.CreateLoad(GetAddrOfLocalVar(SEHPointersDecl));
+  llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo();
+  llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy, nullptr);
+  Ptrs = Builder.CreateBitCast(Ptrs, PtrsTy->getPointerTo());
+  llvm::Value *Rec = Builder.CreateStructGEP(Ptrs, 0);
+  Rec = Builder.CreateLoad(Rec);
+  llvm::Value *Code = Builder.CreateLoad(Rec);
+  Code = Builder.CreateZExt(Code, CGM.IntPtrTy);
+  Code = Builder.CreateIntToPtr(Code, CGM.VoidPtrTy);
+  Builder.CreateStore(Code, getExceptionSlot());
+}
+
+llvm::Value *CodeGenFunction::EmitSEHExceptionCode() {
+  // If we're in a landing pad or filter function, exn.slot will point to the
+  // EXCEPTION_RECORD. The first field of the EXCEPTION_RECORD is always
+  // "DWORD ExceptionCode", so load an int.
+  assert(ExceptionSlot);
+  llvm::Value *Code =
+      Builder.CreatePtrToInt(getExceptionFromSlot(), CGM.IntPtrTy);
+  return Builder.CreateTrunc(Code, CGM.Int32Ty);
+}
+
+llvm::Value *CodeGenFunction::EmitSEHExceptionInfo(const CallExpr *E) {
+  if (!SEHPointersDecl) {
+    // FIXME: Diagnose earlier.
+    unsigned DiagID = CGM.getDiags().getCustomDiagID(
+        DiagnosticsEngine::Error,
+        "cannot use _exception_info outside of filter expressions");
+    CGM.getDiags().Report(E->getLocStart(), DiagID) << E->getSourceRange();
+    return llvm::Constant::getNullValue(CGM.VoidPtrTy);
+  }
+  return Builder.CreateLoad(GetAddrOfLocalVar(SEHPointersDecl));
+}
+
+void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
+  if (SEHExceptStmt *Except = S.getExceptHandler()) {
+    EHCatchScope *CatchScope = EHStack.pushCatch(1);
+    CodeGenFunction FilterCGF(CGM, /*suppressNewContext=*/true);
+    llvm::Constant *FilterFuncPtr =
+        FilterCGF.GenerateSEHFilterFunction(*this, *Except);
+    llvm::BasicBlock *ExceptBB = createBasicBlock("__except");
+    CatchScope->setHandler(0, FilterFuncPtr, ExceptBB);
+  }
+
+  if (SEHFinallyStmt *Finally = S.getFinallyHandler()) {
+    // SEH cleanups should be simple.
+    EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup,
+                                           Finally->getBlock());
+  }
+}
+
+void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
+  if (SEHExceptStmt *Except = S.getExceptHandler()) {
+    EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin());
+
+    // Don't emit the __except block if the __try block lacked invokes.
+    // TODO: Model unwind edges from instructions, either with iload / istore or
+    // a try body function.
+    if (!CatchScope.hasEHBranches()) {
+      CatchScope.clearHandlerBlocks();
+      EHStack.popCatch();
+      return;
+    }
+
+    // The fall-through block.
+    llvm::BasicBlock *ContBB = createBasicBlock("__try.cont");
+
+    // We just emitted the body of the __try; jump to the continue block.
+    if (HaveInsertPoint())
+      Builder.CreateBr(ContBB);
+
+    // Check if our filter function returned true.
+    emitCatchDispatchBlock(*this, CatchScope);
+
+    // Grab the block before we pop the handler.
+    llvm::BasicBlock *ExceptBB = CatchScope.getHandler(0).Block;
+    EHStack.popCatch();
+
+    EmitBlockAfterUses(ExceptBB);
+    EmitStmt(Except->getBlock());
+    Builder.CreateBr(ContBB);
+    EmitBlock(ContBB);
+  }
+
+  if (SEHFinallyStmt *Finally = S.getFinallyHandler()) {
+    PopCleanupBlock();
+  }
 }
 
 void CodeGenFunction::EmitSEHLeaveStmt(const SEHLeaveStmt &S) {
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -42,7 +42,7 @@
       SawAsmBlock(false), BlockInfo(nullptr), BlockPointer(nullptr),
       LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr),
       NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr),
-      ExceptionSlot(nullptr), EHSelectorSlot(nullptr),
+      ExceptionSlot(nullptr), EHSelectorSlot(nullptr), SEHPointersDecl(nullptr),
       DebugInfo(CGM.getModuleDebugInfo()), DisableDebugInfo(false),
       DidCallStackSave(false), IndirectBranch(nullptr), PGO(cgm),
       SwitchInsn(nullptr), SwitchWeights(nullptr), CaseRangeBlock(nullptr),
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -312,6 +312,10 @@
   /// write the current selector value into this alloca.
   llvm::AllocaInst *EHSelectorSlot;
 
+  /// The implicit parameter to SEH filter functions of type
+  /// 'EXCEPTION_POINTERS*'.
+  ImplicitParamDecl *SEHPointersDecl;
+
   /// Emits a landing pad for the current EH stack.
   llvm::BasicBlock *EmitLandingPad();
 
@@ -1987,6 +1991,16 @@
   void EmitCXXTryStmt(const CXXTryStmt &S);
   void EmitSEHTryStmt(const SEHTryStmt &S);
   void EmitSEHLeaveStmt(const SEHLeaveStmt &S);
+  void EnterSEHTryStmt(const SEHTryStmt &S);
+  void ExitSEHTryStmt(const SEHTryStmt &S);
+
+  llvm::Constant *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
+                                            const SEHExceptStmt &S);
+
+  void EmitSEHExceptionCodeSave();
+  llvm::Value *EmitSEHExceptionCode();
+  llvm::Value *EmitSEHExceptionInfo(const CallExpr *E);
+
   void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
                            ArrayRef<const Attr *> Attrs = None);
 
Index: lib/Parse/ParseStmt.cpp
===================================================================
--- lib/Parse/ParseStmt.cpp
+++ lib/Parse/ParseStmt.cpp
@@ -466,7 +466,8 @@
   if (ExpectAndConsume(tok::l_paren))
     return StmtError();
 
-  ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope);
+  ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope |
+                                   Scope::SEHExceptScope);
 
   if (getLangOpts().Borland) {
     Ident__exception_info->setIsPoisoned(false);
Index: lib/Sema/JumpDiagnostics.cpp
===================================================================
--- lib/Sema/JumpDiagnostics.cpp
+++ lib/Sema/JumpDiagnostics.cpp
@@ -338,6 +338,10 @@
     return;
   }
 
+  case Stmt::SEHTryStmtClass:
+    // FIXME: Implement jump diagnostics for bad SEH jumps.
+    break;
+
   default:
     break;
   }
Index: lib/Sema/Scope.cpp
===================================================================
--- lib/Sema/Scope.cpp
+++ lib/Sema/Scope.cpp
@@ -185,6 +185,9 @@
     } else if (Flags & SEHTryScope) {
       OS << "SEHTryScope";
       Flags &= ~SEHTryScope;
+    } else if (Flags & SEHExceptScope) {
+      OS << "SEHExceptScope";
+      Flags &= ~SEHExceptScope;
     } else if (Flags & OpenMPDirectiveScope) {
       OS << "OpenMPDirectiveScope";
       Flags &= ~OpenMPDirectiveScope;
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -393,6 +393,36 @@
   case Builtin::BI__builtin___vsnprintf_chk:
     SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3);
     break;
+
+  case Builtin::BI__exception_code:
+  case Builtin::BI_exception_code: {
+    Scope *S = getCurScope();
+    while (S && !S->isSEHExceptScope())
+      S = S->getParent();
+    if (!S || !S->isSEHExceptScope()) {
+      auto *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+      Diag(TheCall->getExprLoc(), diag::err_seh___except_block)
+          << DRE->getDecl()->getIdentifier();
+      return ExprError();
+    }
+    break;
+  }
+
+  case Builtin::BI__exception_info:
+  case Builtin::BI_exception_info: {
+    // FIXME: Diagnose if this is used in the __except block.
+    Scope *S = getCurScope();
+    while (S && !S->isSEHExceptScope())
+      S = S->getParent();
+    if (!S || !S->isSEHExceptScope()) {
+      auto *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+      Diag(TheCall->getExprLoc(), diag::err_seh___except_filter)
+          << DRE->getDecl()->getIdentifier();
+      return ExprError();
+    }
+    break;
+  }
+
   }
 
   // Since the target specific builtins for each arch overlap, only check those
Index: test/CodeGen/exceptions-seh-leave.c
===================================================================
--- test/CodeGen/exceptions-seh-leave.c
+++ test/CodeGen/exceptions-seh-leave.c
@@ -15,5 +15,5 @@
   return 1;
 }
 // CHECK-NOT: error:
-// CHECK: error: cannot compile this SEH __try yet
+// CHECK: error: cannot compile this SEH __leave yet
 // CHECK-NOT: error:
Index: test/CodeGen/exceptions-seh.c
===================================================================
--- test/CodeGen/exceptions-seh.c
+++ test/CodeGen/exceptions-seh.c
@@ -1,19 +1,118 @@
-// RUN: not %clang_cc1 -triple i686-pc-win32 -fexceptions -fms-extensions -emit-llvm -o - %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fexceptions -fms-extensions -emit-llvm -o - | FileCheck %s
 
-// This is a codegen test because we only emit the diagnostic when we start
-// generating code.
+// CHECK: @__clang_seh_filter_id = linkonce_odr thread_local(localdynamic) global i8* null
 
-int SaveDiv(int numerator, int denominator, int *res) {
+// FIXME: Perform this outlining automatically CodeGen.
+void try_body(int numerator, int denominator, int *myres) {
+  *myres = numerator / denominator;
+}
+// CHECK-LABEL: define void @try_body(i32 %numerator, i32 %denominator, i32* %myres)
+// CHECK: sdiv i32
+// CHECK: store i32 %{{.*}}, i32*
+// CHECK: ret void
+
+int SafeDiv(int numerator, int denominator, int *res) {
   int myres = 0;
+  int success = 1;
   __try {
-    myres = numerator / denominator;
-    __leave;
+    try_body(numerator, denominator, &myres);
   } __except (1) {
-    return 0;
+    success = 0;
   }
   *res = myres;
-  return 1;
+  return success;
+}
+// CHECK-LABEL: define i32 @SafeDiv(i32 %numerator, i32 %denominator, i32* %res)
+// CHECK: invoke void @try_body(i32 %{{.*}}, i32 %{{.*}}, i32* %{{.*}})
+// CHECK:       to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+// CHECK: [[lpad]]
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@SafeDiv@@" to i8*)
+// CHECK: load i8** @__clang_seh_filter_id
+// CHECK: icmp eq i8* %{{.*}}, bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@SafeDiv@@" to i8*)
+// CHECK: [[cont]]
+// CHECK: %[[myres:[^ ]*]] = load i32*
+// CHECK: store i32 %[[myres]], i32*
+
+void j(void);
+
+int nested_try() {
+  int r = 42;
+  __try {
+    __try {
+      j();
+      r = 0;
+    } __except(_exception_code() == 123) {
+      r = 123;
+    }
+  } __except(_exception_code() == 456) {
+    r = 456;
+  }
+  return r;
+}
+// CHECK-LABEL: define i32 @nested_try()
+// CHECK: store i32 42, i32* %[[r:[^ ,]*]]
+// CHECK: invoke void @j()
+// CHECK:       to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[cont]]
+// CHECK: store i32 0, i32* %[[r]]
+// CHECK: br label %[[inner_try_cont:[^ ]*]]
+//
+// CHECK: [[lpad]]
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$1@0@nested_try@@" to i8*)
+// CHECK: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@nested_try@@" to i8*)
+// CHECK: load i8** @__clang_seh_filter_id
+//
+// CHECK: icmp eq i8* %{{.*}}, bitcast (i32 (i8*, i8*)* @"\01?filt$1@0@nested_try@@" to i8*)
+// CHECK: br i1
+//
+// CHECK: icmp eq i8* %{{.*}}, bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@nested_try@@" to i8*)
+// CHECK: br i1
+//
+// CHECK: store i32 456, i32* %[[r]]
+// CHECK: br label %[[outer_try_cont:[^ ]*]]
+//
+// CHECK: [[outer_try_cont]]
+// CHECK: %[[r_load:[^ ]*]] = load i32* %[[r]]
+// CHECK: ret i32 %[[r_load]]
+//
+// CHECK: store i32 123, i32* %[[r]]
+// CHECK: br label %[[inner_try_cont]]
+//
+// CHECK: [[inner_try_cont]]
+// CHECK: br label %[[outer_try_cont]]
+
+// FIXME: This lowering of __finally can't actually work, it will have to
+// change.
+static unsigned g = 0;
+void basic_finally() {
+  ++g;
+  __try {
+    j();
+  } __finally {
+    --g;
+  }
 }
-// CHECK-NOT: error:
-// CHECK: error: cannot compile this SEH __try yet
-// CHECK-NOT: error:
+// CHECK-LABEL: define void @basic_finally()
+// CHECK: load i32* @g
+// CHECK: add i32 %{{.*}}, 1
+// CHECK: store i32 %{{.*}}, i32* @g
+//
+// CHECK: invoke void @j()
+// CHECK:       to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[cont]]
+// CHECK: load i32* @g
+// CHECK: add i32 %{{.*}}, -1
+// CHECK: store i32 %{{.*}}, i32* @g
+// CHECK: ret void
+//
+// CHECK: [[lpad]]
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK-NEXT: cleanup
+// CHECK: load i32* @g
+// CHECK: add i32 %{{.*}}, -1
+// CHECK: store i32 %{{.*}}, i32* @g
+// CHECK: resume
Index: test/OpenMP/parallel_codegen.cpp
===================================================================
--- test/OpenMP/parallel_codegen.cpp
+++ test/OpenMP/parallel_codegen.cpp
@@ -70,7 +70,7 @@
 // CHECK-NEXT:  [[ARGC:%.+]] = load i32* [[ARGC_REF]]
 // CHECK-NEXT:  invoke void [[FOO:@.+foo.+]](i32{{[ ]?[a-z]*}} [[ARGC]])
 // CHECK:       ret void
-// CHECK:       call void @{{.+terminate.*}}(
+// CHECK:       call void @{{.+terminate.*|abort}}(
 // CHECK-NEXT:  unreachable
 // CHECK-NEXT:  }
 // CHECK-DEBUG-LABEL: define internal void @__captured_stmt(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
@@ -82,7 +82,7 @@
 // CHECK-DEBUG-NEXT:  [[ARGC:%.+]] = load i32* [[ARGC_REF]]
 // CHECK-DEBUG-NEXT:  invoke void [[FOO:@.+foo.+]](i32 [[ARGC]])
 // CHECK-DEBUG:       ret void
-// CHECK-DEBUG:       call void @{{.+terminate.*}}(
+// CHECK-DEBUG:       call void @{{.+terminate.*|abort}}(
 // CHECK-DEBUG-NEXT:  unreachable
 // CHECK-DEBUG-NEXT:  }
 
@@ -123,7 +123,7 @@
 // CHECK-NEXT:  [[ARGC:%.+]] = load i8*** [[ARGC_REF]]
 // CHECK-NEXT:  invoke void [[FOO1:@.+foo.+]](i8** [[ARGC]])
 // CHECK:       ret void
-// CHECK:       call void @{{.+terminate.*}}(
+// CHECK:       call void @{{.+terminate.*|abort}}(
 // CHECK-NEXT:  unreachable
 // CHECK-NEXT:  }
 // CHECK-DEBUG-LABEL: define internal void @__captured_stmt1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
@@ -135,7 +135,7 @@
 // CHECK-DEBUG-NEXT:  [[ARGC:%.+]] = load i8*** [[ARGC_REF]]
 // CHECK-DEBUG-NEXT:  invoke void [[FOO1:@.+foo.+]](i8** [[ARGC]])
 // CHECK-DEBUG:       ret void
-// CHECK-DEBUG:       call void @{{.+terminate.*}}(
+// CHECK-DEBUG:       call void @{{.+terminate.*|abort}}(
 // CHECK-DEBUG-NEXT:  unreachable
 // CHECK-DEBUG-NEXT:  }
 
Index: test/Sema/__try.c
===================================================================
--- test/Sema/__try.c
+++ test/Sema/__try.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fborland-extensions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fborland-extensions -DBORLAND -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s
 
 #define JOIN2(x,y) x ## y
 #define JOIN(x,y) JOIN2(x,y)
@@ -10,8 +11,10 @@
 
 struct EXCEPTION_INFO{};
 
-int __exception_code();
+unsigned long __exception_code();
+#ifdef BORLAND
 struct EXCEPTION_INFO* __exception_info();
+#endif
 void __abnormal_termination();
 
 #define GetExceptionCode __exception_code
@@ -143,6 +146,7 @@
   __except( function_scope ? 1 : -1 ) {}
 }
 
+#ifdef BORLAND
 void TEST() {
   __try {
     (void)AbnormalTermination;  // expected-error{{only allowed in __finally block}}
@@ -162,14 +166,21 @@
 }
 
 void TEST() {
-  (void)__exception_code;       // expected-error{{only allowed in __except block}}
   (void)__exception_info;       // expected-error{{only allowed in __except filter expression}}
   (void)__abnormal_termination; // expected-error{{only allowed in __finally block}}
 
-  (void)GetExceptionCode();     // expected-error{{only allowed in __except block}}
   (void)GetExceptionInformation(); // expected-error{{only allowed in __except filter expression}}
   (void)AbnormalTermination();  // expected-error{{only allowed in __finally block}}
 }
+#endif
+
+void TEST() {
+#ifndef BORLAND
+  (void)__exception_code;     // expected-error{{builtin functions must be directly called}}
+#endif
+  (void)__exception_code();     // expected-error{{only allowed in __except block or filter expression}}
+  (void)GetExceptionCode();     // expected-error{{only allowed in __except block or filter expression}}
+}
 
 void test_seh_leave_stmt() {
   __leave; // expected-error{{'__leave' statement not in __try block}}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to