r226760 - Initial support for Win64 SEH IR emission

Reid Kleckner reid at kleckner.net
Wed Jan 21 17:36:17 PST 2015


Author: rnk
Date: Wed Jan 21 19:36:17 2015
New Revision: 226760

URL: http://llvm.org/viewvc/llvm-project?rev=226760&view=rev
Log:
Initial support for Win64 SEH IR emission

The lowering looks a lot like normal EH lowering, with the exception
that the exceptions are caught by executing filter expression code
instead of matching typeinfo globals. The filter expressions are
outlined into functions which are used in landingpad clauses where
typeinfo would normally go.

Major aspects that still need work:
- Non-call exceptions in __try bodies won't work yet. The plan is to
  outline the __try block in the frontend to keep things simple.
- Filter expressions cannot use local variables until capturing is
  implemented.
- __finally blocks will not run after exceptions. Fixing this requires
  work in the LLVM SEH preparation pass.

The IR lowering looks like this:

// C code:
bool safe_div(int n, int d, int *r) {
  __try {
    *r = normal_div(n, d);
  } __except(_exception_code() == EXCEPTION_INT_DIVIDE_BY_ZERO) {
    return false;
  }
  return true;
}

; LLVM IR:
define i32 @filter(i8* %e, i8* %fp) {
  %ehptrs = bitcast i8* %e to i32**
  %ehrec = load i32** %ehptrs
  %code = load i32* %ehrec
  %matches = icmp eq i32 %code, i32 u0xC0000094
  %matches.i32 = zext i1 %matches to i32
  ret i32 %matches.i32
}

define i1 zeroext @safe_div(i32 %n, i32 %d, i32* %r) {
  %rr = invoke i32 @normal_div(i32 %n, i32 %d)
      to label %normal unwind to label %lpad

normal:
  store i32 %rr, i32* %r
  ret i1 1

lpad:
  %ehvals = landingpad {i8*, i32} personality i32 (...)* @__C_specific_handler
      catch i8* bitcast (i32 (i8*, i8*)* @filter to i8*)
  %ehptr = extractvalue {i8*, i32} %ehvals, i32 0
  %sel = extractvalue {i8*, i32} %ehvals, i32 1
  %filter_sel = call i32 @llvm.eh.seh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @filter to i8*))
  %matches = icmp eq i32 %sel, %filter_sel
  br i1 %matches, label %eh.except, label %eh.resume

eh.except:
  ret i1 false

eh.resume:
  resume
}

Reviewers: rjmccall, rsmith, majnemer

Differential Revision: http://reviews.llvm.org/D5607

Added:
    cfe/trunk/test/CodeGen/exceptions-seh-finally.c
    cfe/trunk/test/CodeGen/exceptions-seh-leave.c
      - copied, changed from r226759, cfe/trunk/test/CodeGen/exceptions-seh.c
    cfe/trunk/test/SemaCXX/exceptions-seh.cpp
Modified:
    cfe/trunk/include/clang/AST/Mangle.h
    cfe/trunk/include/clang/Basic/Builtins.def
    cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Sema/Scope.h
    cfe/trunk/lib/AST/ItaniumMangle.cpp
    cfe/trunk/lib/AST/MicrosoftMangle.cpp
    cfe/trunk/lib/CodeGen/CGBuiltin.cpp
    cfe/trunk/lib/CodeGen/CGException.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/Parse/ParseStmt.cpp
    cfe/trunk/lib/Sema/JumpDiagnostics.cpp
    cfe/trunk/lib/Sema/Scope.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/CodeGen/exceptions-seh.c
    cfe/trunk/test/OpenMP/parallel_codegen.cpp
    cfe/trunk/test/Sema/__try.c

Modified: cfe/trunk/include/clang/AST/Mangle.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Mangle.h (original)
+++ cfe/trunk/include/clang/AST/Mangle.h Wed Jan 21 19:36:17 2015
@@ -132,6 +132,9 @@ public:
   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

Modified: cfe/trunk/include/clang/Basic/Builtins.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.def?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Builtins.def (original)
+++ cfe/trunk/include/clang/Basic/Builtins.def Wed Jan 21 19:36:17 2015
@@ -692,11 +692,15 @@ BUILTIN(__builtin_index, "c*cC*i", "Fn")
 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)

Modified: cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td Wed Jan 21 19:36:17 2015
@@ -112,6 +112,16 @@ def ext_integer_literal_too_large_for_si
   "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">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Wed Jan 21 19:36:17 2015
@@ -949,18 +949,6 @@ def warn_pragma_expected_enable_disable
 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;

Modified: cfe/trunk/include/clang/Sema/Scope.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Scope.h?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Scope.h (original)
+++ cfe/trunk/include/clang/Sema/Scope.h Wed Jan 21 19:36:17 2015
@@ -115,8 +115,14 @@ public:
     /// 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,
+
+    /// We are currently in the filter expression of an SEH except block.
+    SEHFilterScope = 0x200000,
   };
 private:
   /// The parent scope for this scope.  This is null for the translation-unit
@@ -407,6 +413,9 @@ public:
   /// \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;

Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Wed Jan 21 19:36:17 2015
@@ -156,6 +156,8 @@ public:
   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;
@@ -3845,6 +3847,16 @@ void ItaniumMangleContextImpl::mangleDyn
     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>

Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Wed Jan 21 19:36:17 2015
@@ -89,6 +89,7 @@ class MicrosoftMangleContextImpl : publi
   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 @@ public:
   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.
@@ -2318,6 +2321,17 @@ void MicrosoftMangleContextImpl::mangleC
   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@";
+  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.

Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Wed Jan 21 19:36:17 2015
@@ -1650,6 +1650,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(
         Builder.CreateAlignedLoad(IntToPtr, /*Align=*/4, /*isVolatile=*/true);
     return RValue::get(Load);
   }
+
+  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());
   }
 
   // If this is an alias for a lib function (e.g. __builtin_sin), emit

Modified: cfe/trunk/lib/CodeGen/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Wed Jan 21 19:36:17 2015
@@ -16,6 +16,7 @@
 #include "CGCleanup.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"
@@ -98,9 +99,10 @@ static llvm::Constant *getTerminateFn(Co
   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
@@ -137,6 +139,8 @@ namespace {
     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;
   };
 }
 
@@ -159,6 +163,10 @@ const EHPersonality
 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_handler3", nullptr };
+const EHPersonality
+EHPersonality::MSVC_C_specific_handler = { "__C_specific_handler", nullptr };
 
 /// On Win64, use libgcc's SEH personality function. We fall back to dwarf on
 /// other platforms, unless the user asked for SjLj exceptions.
@@ -231,9 +239,37 @@ static const EHPersonality &getObjCXXPer
   llvm_unreachable("bad runtime kind");
 }
 
+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(T, L);
   else if (L.CPlusPlus)
@@ -1642,7 +1678,218 @@ llvm::BasicBlock *CodeGenFunction::getEH
 }
 
 void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
-  CGM.ErrorUnsupported(&S, "SEH __try");
+  // FIXME: Implement SEH on other architectures.
+  const llvm::Triple &T = CGM.getTarget().getTriple();
+  if (T.getArch() != llvm::Triple::x86_64 ||
+      !T.isKnownWindowsMSVCEnvironment()) {
+    ErrorUnsupported(&S, "__try statement");
+    return;
+  }
+
+  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 {
+    // FIXME: Don't double-emit LabelDecls.
+    CGF.EmitStmt(Block);
+  }
+};
+}
+
+/// Create a stub filter function that will ultimately hold the code of the
+/// filter expression. The EH preparation passes in LLVM will outline the code
+/// from the main function body into this stub.
+llvm::Function *
+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()) {
+    // FIXME: Unreachable with Rafael's changes?
+    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, convert to i32, and return.
+  llvm::Value *R = EmitScalarExpr(FilterExpr);
+  R = Builder.CreateIntCast(R, CGM.IntTy,
+                            FilterExpr->getType()->isSignedIntegerType());
+  Builder.CreateStore(R, ReturnValue);
+
+  FinishFunction(FilterExpr->getLocEnd());
+
+  for (const auto &DeclPtrs : ParentCGF.LocalDeclMap) {
+    const Decl *VD = DeclPtrs.first;
+    auto *Alloca = cast<llvm::AllocaInst>(LocalDeclMap[VD]);
+    if (Alloca->hasNUses(0)) {
+      Alloca->eraseFromParent();
+      continue;
+    }
+    ErrorUnsupported(FilterExpr,
+                     "SEH filter expression local variable capture");
+  }
+
+  return Fn;
+}
+
+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);
+  // FIXME: Change landing pads to produce {i32, i32} and make the exception
+  // slot an i32.
+  Code = Builder.CreateIntToPtr(Code, CGM.VoidPtrTy);
+  Builder.CreateStore(Code, getExceptionSlot());
+}
+
+llvm::Value *CodeGenFunction::EmitSEHExceptionInfo() {
+  // Sema should diagnose calling this builtin outside of a filter context, but
+  // don't crash if we screw up.
+  if (!SEHPointersDecl)
+    return llvm::UndefValue::get(Int8PtrTy);
+  return Builder.CreateLoad(GetAddrOfLocalVar(SEHPointersDecl));
+}
+
+llvm::Value *CodeGenFunction::EmitSEHExceptionCode() {
+  // If we're in a landing pad or filter function, the exception slot contains
+  // the code.
+  assert(ExceptionSlot);
+  llvm::Value *Code =
+      Builder.CreatePtrToInt(getExceptionFromSlot(), CGM.IntPtrTy);
+  return Builder.CreateTrunc(Code, CGM.Int32Ty);
+}
+
+void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
+  if (SEHFinallyStmt *Finally = S.getFinallyHandler()) {
+    // Push a cleanup for __finally blocks.
+    EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup,
+                                           Finally->getBlock());
+    return;
+  }
+
+  // Otherwise, we must have an __except block.
+  SEHExceptStmt *Except = S.getExceptHandler();
+  assert(Except);
+  EHCatchScope *CatchScope = EHStack.pushCatch(1);
+  CodeGenFunction FilterCGF(CGM, /*suppressNewContext=*/true);
+  llvm::Function *FilterFunc =
+      FilterCGF.GenerateSEHFilterFunction(*this, *Except);
+  llvm::Constant *OpaqueFunc =
+      llvm::ConstantExpr::getBitCast(FilterFunc, Int8PtrTy);
+  CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except"));
+}
+
+void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
+  // Just pop the cleanup if it's a __finally block.
+  if (S.getFinallyHandler()) {
+    PopCleanupBlock();
+    return;
+  }
+
+  // Otherwise, we must have an __except block.
+  SEHExceptStmt *Except = S.getExceptHandler();
+  assert(Except && "__try must have __finally xor __except");
+  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);
+
+  // Emit the __except body.
+  EmitStmt(Except->getBlock());
+
+  Builder.CreateBr(ContBB);
+
+  EmitBlock(ContBB);
 }
 
 void CodeGenFunction::EmitSEHLeaveStmt(const SEHLeaveStmt &S) {

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Wed Jan 21 19:36:17 2015
@@ -43,7 +43,7 @@ CodeGenFunction::CodeGenFunction(CodeGen
       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),

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Jan 21 19:36:17 2015
@@ -305,6 +305,10 @@ public:
   /// 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();
 
@@ -1990,6 +1994,16 @@ public:
   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::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
+                                            const SEHExceptStmt &Except);
+
+  void EmitSEHExceptionCodeSave();
+  llvm::Value *EmitSEHExceptionCode();
+  llvm::Value *EmitSEHExceptionInfo();
+
   void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
                            ArrayRef<const Attr *> Attrs = None);
 

Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Wed Jan 21 19:36:17 2015
@@ -466,14 +466,21 @@ StmtResult Parser::ParseSEHExceptBlock(S
   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);
     Ident___exception_info->setIsPoisoned(false);
     Ident_GetExceptionInfo->setIsPoisoned(false);
   }
-  ExprResult FilterExpr(ParseExpression());
+
+  ExprResult FilterExpr;
+  {
+    ParseScopeFlags FilterScope(this, getCurScope()->getFlags() |
+                                          Scope::SEHFilterScope);
+    FilterExpr = ParseExpression();
+  }
 
   if (getLangOpts().Borland) {
     Ident__exception_info->setIsPoisoned(true);

Modified: cfe/trunk/lib/Sema/JumpDiagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/JumpDiagnostics.cpp?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/JumpDiagnostics.cpp (original)
+++ cfe/trunk/lib/Sema/JumpDiagnostics.cpp Wed Jan 21 19:36:17 2015
@@ -338,6 +338,10 @@ void JumpScopeChecker::BuildScopeInforma
     return;
   }
 
+  case Stmt::SEHTryStmtClass:
+    // FIXME: Implement jump diagnostics for bad SEH jumps.
+    break;
+
   default:
     break;
   }

Modified: cfe/trunk/lib/Sema/Scope.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Scope.cpp?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Scope.cpp (original)
+++ cfe/trunk/lib/Sema/Scope.cpp Wed Jan 21 19:36:17 2015
@@ -185,6 +185,9 @@ void Scope::dumpImpl(raw_ostream &OS) co
     } else if (Flags & SEHTryScope) {
       OS << "SEHTryScope";
       Flags &= ~SEHTryScope;
+    } else if (Flags & SEHExceptScope) {
+      OS << "SEHExceptScope";
+      Flags &= ~SEHExceptScope;
     } else if (Flags & OpenMPDirectiveScope) {
       OS << "OpenMPDirectiveScope";
       Flags &= ~OpenMPDirectiveScope;

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Jan 21 19:36:17 2015
@@ -202,6 +202,28 @@ static bool SemaBuiltinCallWithStaticCha
   return false;
 }
 
+static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall,
+                                     Scope::ScopeFlags NeededScopeFlags,
+                                     unsigned DiagID) {
+  // Scopes aren't available during instantiation. Fortunately, builtin
+  // functions cannot be template args so they cannot be formed through template
+  // instantiation. Therefore checking once during the parse is sufficient.
+  if (!SemaRef.ActiveTemplateInstantiations.empty())
+    return false;
+
+  Scope *S = SemaRef.getCurScope();
+  while (S && !S->isSEHExceptScope())
+    S = S->getParent();
+  if (!S || !(S->getFlags() & NeededScopeFlags)) {
+    auto *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+    SemaRef.Diag(TheCall->getExprLoc(), DiagID)
+        << DRE->getDecl()->getIdentifier();
+    return true;
+  }
+
+  return false;
+}
+
 ExprResult
 Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
                                CallExpr *TheCall) {
@@ -461,6 +483,22 @@ Sema::CheckBuiltinFunctionCall(FunctionD
     if (SemaBuiltinCallWithStaticChain(*this, TheCall))
       return ExprError();
     break;
+
+  case Builtin::BI__exception_code:
+  case Builtin::BI_exception_code: {
+    if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHExceptScope,
+                                 diag::err_seh___except_block))
+      return ExprError();
+    break;
+  }
+  case Builtin::BI__exception_info:
+  case Builtin::BI_exception_info: {
+    if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHFilterScope,
+                                 diag::err_seh___except_filter))
+      return ExprError();
+    break;
+  }
+
   }
 
   // Since the target specific builtins for each arch overlap, only check those

Added: cfe/trunk/test/CodeGen/exceptions-seh-finally.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh-finally.c?rev=226760&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/exceptions-seh-finally.c (added)
+++ cfe/trunk/test/CodeGen/exceptions-seh-finally.c Wed Jan 21 19:36:17 2015
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fexceptions -fms-extensions -emit-llvm -o - | FileCheck %s
+
+void might_crash(void);
+void cleanup(void);
+int check_condition(void);
+void basic_finally(void) {
+  __try {
+    might_crash();
+  } __finally {
+    cleanup();
+  }
+}
+
+// CHECK-LABEL: define void @basic_finally()
+// CHECK: invoke void @might_crash()
+// CHECK: call void @cleanup()
+//
+// CHECK: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: invoke void @cleanup()
+//
+// CHECK: landingpad
+// CHECK-NEXT: catch i8* null
+// CHECK: call void @abort()
+
+// FIXME: This crashes.
+#if 0
+void basic_finally(void) {
+  __try {
+    might_crash();
+  } __finally {
+l:
+    cleanup();
+    if (check_condition())
+      goto l;
+  }
+}
+#endif

Copied: cfe/trunk/test/CodeGen/exceptions-seh-leave.c (from r226759, cfe/trunk/test/CodeGen/exceptions-seh.c)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh-leave.c?p2=cfe/trunk/test/CodeGen/exceptions-seh-leave.c&p1=cfe/trunk/test/CodeGen/exceptions-seh.c&r1=226759&r2=226760&rev=226760&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/exceptions-seh.c (original)
+++ cfe/trunk/test/CodeGen/exceptions-seh-leave.c Wed Jan 21 19:36:17 2015
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -triple i686-pc-win32 -fexceptions -fms-extensions -emit-llvm -o - %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple x86_64-pc-win32 -fexceptions -fms-extensions -emit-llvm -o - %s 2>&1 | FileCheck %s
 
 // This is a codegen test because we only emit the diagnostic when we start
 // generating code.
@@ -15,5 +15,5 @@ int SaveDiv(int numerator, int denominat
   return 1;
 }
 // CHECK-NOT: error:
-// CHECK: error: cannot compile this SEH __try yet
+// CHECK: error: cannot compile this SEH __leave yet
 // CHECK-NOT: error:

Modified: cfe/trunk/test/CodeGen/exceptions-seh.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh.c?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/exceptions-seh.c (original)
+++ cfe/trunk/test/CodeGen/exceptions-seh.c Wed Jan 21 19:36:17 2015
@@ -1,19 +1,154 @@
-// 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.
+// 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 SaveDiv(int numerator, int denominator, int *res) {
+int safe_div(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 = -42;
   }
   *res = myres;
-  return 1;
+  return success;
+}
+// CHECK-LABEL: define i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res)
+// CHECK: invoke void @try_body(i32 %{{.*}}, i32 %{{.*}}, i32* %{{.*}})
+// CHECK:       to label %{{.*}} unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[lpad]]
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK: %[[sel:[^ ]*]] = load i32*
+// CHECK: %[[filt_id:[^ ]*]] = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0 at 0@safe_div@@" to i8*))
+// CHECK: %[[matches:[^ ]*]] = icmp eq i32 %[[sel]], %[[filt_id]]
+// CHECK: br i1 %[[matches]], label %[[except_bb:[^ ]*]], label %{{.*}}
+//
+// CHECK: [[except_bb]]
+// CHECK: store i32 -42, i32* %[[success:[^ ]*]]
+//
+// CHECK: %[[res:[^ ]*]] = load i32* %[[success]]
+// CHECK: ret i32 %[[res]]
+
+void j(void);
+
+// FIXME: Implement local variable captures in filter expressions.
+int filter_expr_capture() {
+  int r = 42;
+  __try {
+    j();
+  } __except(/*r =*/ -1) {
+    r = 13;
+  }
+  return r;
+}
+
+// CHECK-LABEL: define i32 @filter_expr_capture()
+// FIXMECHECK: %[[captures]] = call i8* @llvm.frameallocate(i32 4)
+// CHECK: store i32 42, i32* %[[r:[^ ,]*]]
+// CHECK: invoke void @j()
+//
+// CHECK: landingpad
+// CHECK-NEXT: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0 at 0@filter_expr_capture@@" to i8*)
+// CHECK: store i32 13, i32* %[[r]]
+//
+// CHECK: %[[rv:[^ ]*]] = load i32* %[[r]]
+// CHECK: ret i32 %[[rv]]
+
+// CHECK-LABEL: define internal i32 @"\01?filt$0 at 0@filter_expr_capture@@"(i8* %exception_pointers, i8* %frame_pointer)
+// FIXMECHECK: %[[captures]] = call i8* @llvm.framerecover(i8* bitcast (i32 ()* @filter_expr_capture, i8* %frame_pointer)
+// FIXMECHECK: store i32 -1, i32* %{{.*}}
+// CHECK: ret i32 -1
+
+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 at 0@nested_try@@" to i8*)
+// CHECK: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0 at 0@nested_try@@" to i8*)
+// CHECK: store i8* %{{.*}}, i8** %[[ehptr_slot:[^ ]*]]
+// CHECK: store i32 %{{.*}}, i32* %[[sel_slot:[^ ]*]]
+//
+// CHECK: load i32* %[[sel_slot]]
+// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @"\01?filt$1 at 0@nested_try@@" to i8*))
+// CHECK: icmp eq i32
+// CHECK: br i1
+//
+// CHECK: load i32* %[[sel_slot]]
+// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0 at 0@nested_try@@" to i8*))
+// CHECK: icmp eq i32
+// 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

Modified: cfe/trunk/test/OpenMP/parallel_codegen.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_codegen.cpp?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/parallel_codegen.cpp (original)
+++ cfe/trunk/test/OpenMP/parallel_codegen.cpp Wed Jan 21 19:36:17 2015
@@ -70,7 +70,7 @@ int main (int argc, char **argv) {
 // 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 @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
@@ -82,7 +82,7 @@ int main (int argc, char **argv) {
 // 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 @@ int main (int argc, char **argv) {
 // 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 @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
@@ -135,7 +135,7 @@ int main (int argc, char **argv) {
 // 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:  }
 

Modified: cfe/trunk/test/Sema/__try.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/__try.c?rev=226760&r1=226759&r2=226760&view=diff
==============================================================================
--- cfe/trunk/test/Sema/__try.c (original)
+++ cfe/trunk/test/Sema/__try.c Wed Jan 21 19:36:17 2015
@@ -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 @@ typedef int DWORD;
 
 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,7 +146,11 @@ void TEST() {
   __except( function_scope ? 1 : -1 ) {}
 }
 
+#ifdef BORLAND
 void TEST() {
+  (void)__abnormal_termination(); // expected-error{{only allowed in __finally block}}
+  (void)AbnormalTermination();  // expected-error{{only allowed in __finally block}}
+
   __try {
     (void)AbnormalTermination;  // expected-error{{only allowed in __finally block}}
     (void)__abnormal_termination; // expected-error{{only allowed in __finally block}}
@@ -160,15 +167,27 @@ void TEST() {
     __abnormal_termination();
   }
 }
+#endif
 
 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)__exception_info();       // expected-error{{only allowed in __except filter expression}}
   (void)GetExceptionInformation(); // expected-error{{only allowed in __except filter expression}}
-  (void)AbnormalTermination();  // expected-error{{only allowed in __finally block}}
+}
+
+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() {
+  __try {
+  } __except(1) {
+    GetExceptionCode(); // valid
+    GetExceptionInformation(); // expected-error{{only allowed in __except filter expression}}
+  }
 }
 
 void test_seh_leave_stmt() {
@@ -188,4 +207,3 @@ void test_seh_leave_stmt() {
   }
   __leave; // expected-error{{'__leave' statement not in __try block}}
 }
-

Added: cfe/trunk/test/SemaCXX/exceptions-seh.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/exceptions-seh.cpp?rev=226760&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/exceptions-seh.cpp (added)
+++ cfe/trunk/test/SemaCXX/exceptions-seh.cpp Wed Jan 21 19:36:17 2015
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -fsyntax-only -verify %s
+
+// Basic usage should work.
+int safe_div(int n, int d) {
+  int r;
+  __try {
+    r = n / d;
+  } __except(_exception_code() == 0xC0000094) {
+    r = 0;
+  }
+  return r;
+}
+
+void might_crash();
+
+// Diagnose obvious builtin mis-usage.
+void bad_builtin_scope() {
+  __try {
+    might_crash();
+  } __except(1) {
+  }
+  _exception_code(); // expected-error {{'_exception_code' only allowed in __except block or filter expression}}
+  _exception_info(); // expected-error {{'_exception_info' only allowed in __except filter expression}}
+}
+
+// Diagnose obvious builtin misusage in a template.
+template <void FN()>
+void bad_builtin_scope_template() {
+  __try {
+    FN();
+  } __except(1) {
+  }
+  _exception_code(); // expected-error {{'_exception_code' only allowed in __except block or filter expression}}
+  _exception_info(); // expected-error {{'_exception_info' only allowed in __except filter expression}}
+}
+void instantiate_bad_scope_tmpl() {
+  bad_builtin_scope_template<might_crash>();
+}
+
+// FIXME: Diagnose this case. For now we produce undef in codegen.
+template <typename T, T FN()>
+T func_template() {
+  return FN();
+}
+void inject_builtins() {
+  func_template<void *, __exception_info>();
+  func_template<unsigned long, __exception_code>();
+}





More information about the cfe-commits mailing list