r234787 - Revert r234786, it contained a bunch of stuff I did not mean to commit.

Nico Weber nicolasweber at gmx.de
Mon Apr 13 13:03:03 PDT 2015


Author: nico
Date: Mon Apr 13 15:03:03 2015
New Revision: 234787

URL: http://llvm.org/viewvc/llvm-project?rev=234787&view=rev
Log:
Revert r234786, it contained a bunch of stuff I did not mean to commit.

Modified:
    cfe/trunk/include/clang/AST/Mangle.h
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/AttributeList.h
    cfe/trunk/lib/AST/ItaniumMangle.cpp
    cfe/trunk/lib/AST/MicrosoftMangle.cpp
    cfe/trunk/lib/CodeGen/CGException.cpp
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/Driver/SanitizerArgs.cpp
    cfe/trunk/test/CodeGen/exceptions-seh-finally.c
    cfe/trunk/test/CodeGen/exceptions-seh-leave.c
    cfe/trunk/test/CodeGen/exceptions-seh.c
    cfe/trunk/test/CodeGenCXX/exceptions-seh.cpp
    cfe/trunk/test/SemaCXX/switch-implicit-fallthrough.cpp

Modified: cfe/trunk/include/clang/AST/Mangle.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Mangle.h (original)
+++ cfe/trunk/include/clang/AST/Mangle.h Mon Apr 13 15:03:03 2015
@@ -135,6 +135,9 @@ public:
   virtual void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
                                          raw_ostream &Out) = 0;
 
+  virtual void mangleSEHFinallyBlock(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/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Mon Apr 13 15:03:03 2015
@@ -106,8 +106,6 @@ def SharedVar : SubsetSubject<Var,
 def GlobalVar : SubsetSubject<Var,
                              [{S->hasGlobalStorage()}]>;
 
-def NotAllowedOnDecls : SubsetSubject<Var, [{false}]>;
-
 // FIXME: this hack is needed because DeclNodes.td defines the base Decl node
 // type to be a class, not a definition. This makes it impossible to create an
 // attribute subject which accepts a Decl. Normally, this is not a problem,
@@ -692,8 +690,7 @@ def ExtVectorType : Attr {
 
 def FallThrough : Attr {
   let Spellings = [CXX11<"clang", "fallthrough">];
-  let Subjects = SubjectList<[NotAllowedOnDecls], ErrorDiag,
-                             "ExpectedEmptyStatement">;
+//  let Subjects = [NullStmt];
   let Documentation = [FallthroughDocs];
 }
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Apr 13 15:03:03 2015
@@ -2266,7 +2266,7 @@ def warn_attribute_wrong_decl_type : War
   "Objective-C instance methods|init methods of interface or class extension declarations|"
   "variables, functions and classes|Objective-C protocols|"
   "functions and global variables|structs, unions, and typedefs|structs and typedefs|"
-  "interface or protocol declarations|kernel functions|empty statements}1">,
+  "interface or protocol declarations|kernel functions}1">,
   InGroup<IgnoredAttributes>;
 def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
 def warn_type_attribute_wrong_type : Warning<

Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Mon Apr 13 15:03:03 2015
@@ -846,8 +846,7 @@ enum AttributeDeclKind {
   ExpectedStructOrUnionOrTypedef,
   ExpectedStructOrTypedef,
   ExpectedObjectiveCInterfaceOrProtocol,
-  ExpectedKernelFunction,
-  ExpectedEmptyStatement
+  ExpectedKernelFunction
 };
 
 }  // end namespace clang

Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Mon Apr 13 15:03:03 2015
@@ -166,6 +166,8 @@ public:
                                      raw_ostream &Out) override;
   void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
                                  raw_ostream &Out) override;
+  void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
+                             raw_ostream &Out) override;
   void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override;
   void mangleItaniumThreadLocalWrapper(const VarDecl *D,
                                        raw_ostream &) override;
@@ -3964,6 +3966,16 @@ void ItaniumMangleContextImpl::mangleSEH
   if (shouldMangleDeclName(EnclosingDecl))
     Mangler.mangle(EnclosingDecl);
   else
+    Mangler.getStream() << EnclosingDecl->getName();
+}
+
+void ItaniumMangleContextImpl::mangleSEHFinallyBlock(
+    const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+  CXXNameMangler Mangler(*this, Out);
+  Mangler.getStream() << "__fin_";
+  if (shouldMangleDeclName(EnclosingDecl))
+    Mangler.mangle(EnclosingDecl);
+  else
     Mangler.getStream() << EnclosingDecl->getName();
 }
 

Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Mon Apr 13 15:03:03 2015
@@ -94,6 +94,7 @@ class MicrosoftMangleContextImpl : publi
   llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
   llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
   llvm::DenseMap<const NamedDecl *, unsigned> SEHFilterIds;
+  llvm::DenseMap<const NamedDecl *, unsigned> SEHFinallyIds;
 
 public:
   MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
@@ -151,6 +152,8 @@ public:
                                      raw_ostream &Out) override;
   void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
                                  raw_ostream &Out) override;
+  void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
+                             raw_ostream &Out) override;
   void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
   void mangleCXXVTableBitSet(const CXXRecordDecl *RD,
                              raw_ostream &Out) override;
@@ -2469,6 +2472,17 @@ void MicrosoftMangleContextImpl::mangleS
   Mangler.mangleName(EnclosingDecl);
 }
 
+void MicrosoftMangleContextImpl::mangleSEHFinallyBlock(
+    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> ::= ?fin$ <filter-number> @0
+  Mangler.getStream() << "\01?fin$" << SEHFinallyIds[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/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Mon Apr 13 15:03:03 2015
@@ -23,6 +23,7 @@
 #include "llvm/IR/CallSite.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/IntrinsicInst.h"
+#include "llvm/Support/SaveAndRestore.h"
 
 using namespace clang;
 using namespace CodeGen;
@@ -408,13 +409,6 @@ llvm::Value *CodeGenFunction::getSelecto
   return Builder.CreateLoad(getEHSelectorSlot(), "sel");
 }
 
-llvm::Value *CodeGenFunction::getAbnormalTerminationSlot() {
-  if (!AbnormalTerminationSlot)
-    AbnormalTerminationSlot =
-        CreateTempAlloca(Int8Ty, "abnormal.termination.slot");
-  return AbnormalTerminationSlot;
-}
-
 void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,
                                        bool KeepInsertionPoint) {
   if (const Expr *SubExpr = E->getSubExpr()) {
@@ -1287,8 +1281,7 @@ void CodeGenFunction::EmitSEHTryStmt(con
     return;
   }
 
-  SEHFinallyInfo FI;
-  EnterSEHTryStmt(S, FI);
+  EnterSEHTryStmt(S);
   {
     JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");
 
@@ -1301,42 +1294,36 @@ void CodeGenFunction::EmitSEHTryStmt(con
     else
       delete TryExit.getBlock();
   }
-  ExitSEHTryStmt(S, FI);
+  ExitSEHTryStmt(S);
 }
 
 namespace {
-struct PerformSEHFinally : EHScopeStack::Cleanup  {
-  CodeGenFunction::SEHFinallyInfo *FI;
-  PerformSEHFinally(CodeGenFunction::SEHFinallyInfo *FI) : FI(FI) {}
+struct PerformSEHFinally : EHScopeStack::Cleanup {
+  llvm::Function *OutlinedFinally;
+  PerformSEHFinally(llvm::Function *OutlinedFinally)
+      : OutlinedFinally(OutlinedFinally) {}
 
   void Emit(CodeGenFunction &CGF, Flags F) override {
-    // Cleanups are emitted at most twice: once for normal control flow and once
-    // for exception control flow. Branch into the finally block, and remember
-    // the continuation block so we can branch out later.
-    if (!FI->FinallyBB) {
-      FI->FinallyBB = CGF.createBasicBlock("__finally");
-      FI->FinallyBB->insertInto(CGF.CurFn);
-      FI->FinallyBB->moveAfter(CGF.Builder.GetInsertBlock());
-    }
-
-    // Set the termination status and branch in.
-    CGF.Builder.CreateStore(
-        llvm::ConstantInt::get(CGF.Int8Ty, F.isForEHCleanup()),
-        CGF.getAbnormalTerminationSlot());
-    CGF.Builder.CreateBr(FI->FinallyBB);
-
-    // Create a continuation block for normal or exceptional control.
-    if (F.isForEHCleanup()) {
-      assert(!FI->ResumeBB && "double emission for EH");
-      FI->ResumeBB = CGF.createBasicBlock("__finally.resume");
-      CGF.EmitBlock(FI->ResumeBB);
-    } else {
-      assert(F.isForNormalCleanup() && !FI->ContBB && "double normal emission");
-      FI->ContBB = CGF.createBasicBlock("__finally.cont");
-      CGF.EmitBlock(FI->ContBB);
-      // Try to keep source order.
-      FI->ContBB->moveAfter(FI->FinallyBB);
-    }
+    ASTContext &Context = CGF.getContext();
+    QualType ArgTys[2] = {Context.BoolTy, Context.VoidPtrTy};
+    FunctionProtoType::ExtProtoInfo EPI;
+    const auto *FTP = cast<FunctionType>(
+        Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
+
+    CallArgList Args;
+    llvm::Value *IsForEH =
+        llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());
+    Args.add(RValue::get(IsForEH), ArgTys[0]);
+
+    CodeGenModule &CGM = CGF.CGM;
+    llvm::Value *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0);
+    llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress);
+    llvm::Value *FP = CGF.Builder.CreateCall(FrameAddr, Zero);
+    Args.add(RValue::get(FP), ArgTys[1]);
+
+    const CGFunctionInfo &FnInfo =
+        CGM.getTypes().arrangeFreeFunctionCall(Args, FTP, /*chainCall=*/false);
+    CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
   }
 };
 }
@@ -1354,7 +1341,8 @@ struct CaptureFinder : ConstStmtVisitor<
     // See if this is a capture, then recurse.
     ConstStmtVisitor<CaptureFinder>::Visit(S);
     for (const Stmt *Child : S->children())
-      Visit(Child);
+      if (Child)
+        Visit(Child);
   }
 
   void VisitDeclRefExpr(const DeclRefExpr *E) {
@@ -1403,12 +1391,16 @@ void CodeGenFunction::EmitCapturedLocals
       CGM.ErrorUnsupported(VD, "VLA captured by SEH");
       continue;
     }
-
     assert((isa<ImplicitParamDecl>(VD) || VD->isLocalVarDeclOrParm()) &&
            "captured non-local variable");
 
-    llvm::Value *ParentVar = ParentCGF.LocalDeclMap[VD];
-    assert(ParentVar && "capture was not a local decl");
+    // If this decl hasn't been declared yet, it will be declared in the
+    // OutlinedStmt.
+    auto I = ParentCGF.LocalDeclMap.find(VD);
+    if (I == ParentCGF.LocalDeclMap.end())
+      continue;
+    llvm::Value *ParentVar = I->second;
+
     llvm::CallInst *RecoverCall = nullptr;
     CGBuilderTy Builder(AllocaInsertPt);
     if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar)) {
@@ -1445,47 +1437,24 @@ void CodeGenFunction::EmitCapturedLocals
   }
 }
 
-/// 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;
+/// Arrange a function prototype that can be called by Windows exception
+/// handling personalities. On Win64, the prototype looks like:
+/// RetTy func(void *EHPtrs, void *ParentFP);
+void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
+                                             StringRef Name, QualType RetTy,
+                                             FunctionArgList &Args,
+                                             const Stmt *OutlinedStmt) {
   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());
+  llvm::Function *Fn = llvm::Function::Create(
+      FnTy, llvm::GlobalValue::InternalLinkage, 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);
@@ -1493,14 +1462,55 @@ CodeGenFunction::GenerateSEHFilterFuncti
     Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
   }
 
+  IsOutlinedSEHHelper = true;
+
   StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,
-                FilterExpr->getLocStart(), FilterExpr->getLocStart());
+                OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart());
 
-  EmitSEHExceptionCodeSave();
+  CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn);
 
   auto AI = Fn->arg_begin();
   ++AI;
-  EmitCapturedLocals(ParentCGF, FilterExpr, &*AI);
+  EmitCapturedLocals(ParentCGF, OutlinedStmt, &*AI);
+}
+
+/// 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 Expr *FilterExpr = Except.getFilterExpr();
+  SourceLocation StartLoc = FilterExpr->getLocStart();
+
+  SEHPointersDecl = ImplicitParamDecl::Create(
+      getContext(), nullptr, StartLoc,
+      &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
+  FunctionArgList Args;
+  Args.push_back(SEHPointersDecl);
+  Args.push_back(ImplicitParamDecl::Create(
+      getContext(), nullptr, StartLoc,
+      &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
+
+  // Get the mangled function name.
+  SmallString<128> Name;
+  {
+    llvm::raw_svector_ostream OS(Name);
+    const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
+    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);
+  }
+
+  startOutlinedSEHHelper(ParentCGF, Name, getContext().IntTy, Args, FilterExpr);
+
+  // Mark finally block calls as nounwind and noinline to make LLVM's job a
+  // little easier.
+  // FIXME: Remove these restrictions in the future.
+  CurFn->addFnAttr(llvm::Attribute::NoUnwind);
+  CurFn->addFnAttr(llvm::Attribute::NoInline);
+
+  EmitSEHExceptionCodeSave();
 
   // Emit the original filter expression, convert to i32, and return.
   llvm::Value *R = EmitScalarExpr(FilterExpr);
@@ -1510,7 +1520,42 @@ CodeGenFunction::GenerateSEHFilterFuncti
 
   FinishFunction(FilterExpr->getLocEnd());
 
-  return Fn;
+  return CurFn;
+}
+
+llvm::Function *
+CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
+                                            const SEHFinallyStmt &Finally) {
+  const Stmt *FinallyBlock = Finally.getBlock();
+  SourceLocation StartLoc = FinallyBlock->getLocStart();
+
+  FunctionArgList Args;
+  Args.push_back(ImplicitParamDecl::Create(
+      getContext(), nullptr, StartLoc,
+      &getContext().Idents.get("abnormal_termination"), getContext().BoolTy));
+  Args.push_back(ImplicitParamDecl::Create(
+      getContext(), nullptr, StartLoc,
+      &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
+
+  // Get the mangled function name.
+  SmallString<128> Name;
+  {
+    llvm::raw_svector_ostream OS(Name);
+    const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
+    const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
+    assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
+    CGM.getCXXABI().getMangleContext().mangleSEHFinallyBlock(Parent, OS);
+  }
+
+  startOutlinedSEHHelper(ParentCGF, Name, getContext().VoidTy, Args,
+                         FinallyBlock);
+
+  // Emit the original filter expression, convert to i32, and return.
+  EmitStmt(FinallyBlock);
+
+  FinishFunction(FinallyBlock->getLocEnd());
+
+  return CurFn;
 }
 
 void CodeGenFunction::EmitSEHExceptionCodeSave() {
@@ -1554,21 +1599,24 @@ llvm::Value *CodeGenFunction::EmitSEHExc
 }
 
 llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
-  // Load from the abnormal termination slot. It will be uninitialized outside
-  // of __finally blocks, which we should warn or error on.
-  llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot());
-  return Builder.CreateZExt(IsEH, Int32Ty);
+  // Abnormal termination is just the first parameter to the outlined finally
+  // helper.
+  auto AI = CurFn->arg_begin();
+  return Builder.CreateZExt(&*AI, Int32Ty);
 }
 
-void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
-  if (S.getFinallyHandler()) {
+void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
+  CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
+  if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
     // Push a cleanup for __finally blocks.
-    EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, &FI);
+    llvm::Function *FinallyFunc =
+        HelperCGF.GenerateSEHFinallyFunction(*this, *Finally);
+    EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);
     return;
   }
 
   // Otherwise, we must have an __except block.
-  SEHExceptStmt *Except = S.getExceptHandler();
+  const SEHExceptStmt *Except = S.getExceptHandler();
   assert(Except);
   EHCatchScope *CatchScope = EHStack.pushCatch(1);
 
@@ -1583,40 +1631,17 @@ void CodeGenFunction::EnterSEHTryStmt(co
 
   // In general, we have to emit an outlined filter function. Use the function
   // in place of the RTTI typeinfo global that C++ EH uses.
-  CodeGenFunction FilterCGF(CGM, /*suppressNewContext=*/true);
   llvm::Function *FilterFunc =
-      FilterCGF.GenerateSEHFilterFunction(*this, *Except);
+      HelperCGF.GenerateSEHFilterFunction(*this, *Except);
   llvm::Constant *OpaqueFunc =
       llvm::ConstantExpr::getBitCast(FilterFunc, Int8PtrTy);
   CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except"));
 }
 
-void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
+void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
   // Just pop the cleanup if it's a __finally block.
-  if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
+  if (S.getFinallyHandler()) {
     PopCleanupBlock();
-    assert(FI.ContBB && "did not emit normal cleanup");
-
-    // Emit the code into FinallyBB.
-    CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();
-    Builder.SetInsertPoint(FI.FinallyBB);
-    EmitStmt(Finally->getBlock());
-
-    if (HaveInsertPoint()) {
-      if (FI.ResumeBB) {
-        llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(),
-                                               "abnormal.termination");
-        IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0));
-        Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB);
-      } else {
-        // There was nothing exceptional in the try body, so we only have normal
-        // control flow.
-        Builder.CreateBr(FI.ContBB);
-      }
-    }
-
-    Builder.restoreIP(SavedIP);
-
     return;
   }
 
@@ -1666,7 +1691,13 @@ void CodeGenFunction::EmitSEHLeaveStmt(c
   if (HaveInsertPoint())
     EmitStopPoint(&S);
 
-  assert(!SEHTryEpilogueStack.empty() &&
-         "sema should have rejected this __leave");
+  // This must be a __leave from a __finally block, which we warn on and is UB.
+  // Just emit unreachable.
+  if (!isSEHTryScope()) {
+    Builder.CreateUnreachable();
+    Builder.ClearInsertionPoint();
+    return;
+  }
+
   EmitBranchThroughCleanup(*SEHTryEpilogueStack.back());
 }

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Mon Apr 13 15:03:03 2015
@@ -1021,6 +1021,12 @@ void CodeGenFunction::EmitReturnOfRValue
 /// if the function returns void, or may be missing one if the function returns
 /// non-void.  Fun stuff :).
 void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
+  // Returning from an outlined SEH helper is UB, and we already warn on it.
+  if (IsOutlinedSEHHelper) {
+    Builder.CreateUnreachable();
+    Builder.ClearInsertionPoint();
+  }
+
   // Emit the result value, even if unused, to evalute the side effects.
   const Expr *RV = S.getRetValue();
 

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Mon Apr 13 15:03:03 2015
@@ -40,7 +40,7 @@ CodeGenFunction::CodeGenFunction(CodeGen
       CurFn(nullptr), CapturedStmtInfo(nullptr),
       SanOpts(CGM.getLangOpts().Sanitize), IsSanitizerScope(false),
       CurFuncIsThunk(false), AutoreleaseResult(false), SawAsmBlock(false),
-      BlockInfo(nullptr), BlockPointer(nullptr),
+      IsOutlinedSEHHelper(false), BlockInfo(nullptr), BlockPointer(nullptr),
       LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr),
       NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr),
       ExceptionSlot(nullptr), EHSelectorSlot(nullptr),

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Mon Apr 13 15:03:03 2015
@@ -263,6 +263,10 @@ public:
   /// potentially set the return value.
   bool SawAsmBlock;
 
+  /// True if the current function is an outlined SEH helper. This can be a
+  /// finally block or filter expression.
+  bool IsOutlinedSEHHelper;
+
   const CodeGen::CGBlockInfo *BlockInfo;
   llvm::Value *BlockPointer;
 
@@ -351,17 +355,6 @@ public:
     void exit(CodeGenFunction &CGF);
   };
 
-  /// Cleanups can be emitted for two reasons: normal control leaving a region
-  /// exceptional control flow leaving a region.
-  struct SEHFinallyInfo {
-    SEHFinallyInfo()
-        : FinallyBB(nullptr), ContBB(nullptr), ResumeBB(nullptr) {}
-
-    llvm::BasicBlock *FinallyBB;
-    llvm::BasicBlock *ContBB;
-    llvm::BasicBlock *ResumeBB;
-  };
-
   /// Returns true inside SEH __try blocks.
   bool isSEHTryScope() const { return !SEHTryEpilogueStack.empty(); }
 
@@ -1052,10 +1045,6 @@ public:
   llvm::Value *getExceptionSlot();
   llvm::Value *getEHSelectorSlot();
 
-  /// Stack slot that contains whether a __finally block is being executed as an
-  /// EH cleanup or as a normal cleanup.
-  llvm::Value *getAbnormalTerminationSlot();
-
   /// Returns the contents of the function's exception object and selector
   /// slots.
   llvm::Value *getExceptionFromSlot();
@@ -2000,12 +1989,19 @@ public:
   void EmitCXXTryStmt(const CXXTryStmt &S);
   void EmitSEHTryStmt(const SEHTryStmt &S);
   void EmitSEHLeaveStmt(const SEHLeaveStmt &S);
-  void EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI);
-  void ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI);
+  void EnterSEHTryStmt(const SEHTryStmt &S);
+  void ExitSEHTryStmt(const SEHTryStmt &S);
+
+  void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, StringRef Name,
+                              QualType RetTy, FunctionArgList &Args,
+                              const Stmt *OutlinedStmt);
 
   llvm::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
                                             const SEHExceptStmt &Except);
 
+  llvm::Function *GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
+                                             const SEHFinallyStmt &Finally);
+
   void EmitSEHExceptionCodeSave();
   llvm::Value *EmitSEHExceptionCode();
   llvm::Value *EmitSEHExceptionInfo();

Modified: cfe/trunk/lib/Driver/SanitizerArgs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/SanitizerArgs.cpp?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/SanitizerArgs.cpp (original)
+++ cfe/trunk/lib/Driver/SanitizerArgs.cpp Mon Apr 13 15:03:03 2015
@@ -387,8 +387,7 @@ SanitizerArgs::SanitizerArgs(const ToolC
         StringRef S = A->getValue();
         if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
             MsanTrackOrigins > 2) {
-          D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args)
-                                                     << S;
+          D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
         }
       }
     }

Modified: cfe/trunk/test/CodeGen/exceptions-seh-finally.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh-finally.c?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/exceptions-seh-finally.c (original)
+++ cfe/trunk/test/CodeGen/exceptions-seh-finally.c Mon Apr 13 15:03:03 2015
@@ -17,30 +17,20 @@ void basic_finally(void) {
 // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[invoke_cont]]
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK: call void @cleanup()
-// CHECK: load i8, i8* %[[abnormal]]
-// CHECK: icmp eq
-// CHECK: br i1 %{{.*}}, label %[[finallycont:[^ ]*]], label %[[resumecont:[^ ]*]]
-//
-// CHECK: [[finallycont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@basic_finally@@"(i1 zeroext false, i8* %[[fp]])
 // CHECK-NEXT: ret void
 //
 // CHECK: [[lpad]]
 // CHECK-NEXT: landingpad
 // CHECK-NEXT: cleanup
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK: br label %[[finally]]
-//
-// CHECK: [[resumecont]]
-// CHECK: br label %[[ehresume:[^ ]*]]
-//
-// CHECK: [[ehresume]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@basic_finally@@"(i1 zeroext true, i8* %[[fp]])
 // CHECK: resume { i8*, i32 }
 
+// CHECK: define internal void @"\01?fin$0 at 0@basic_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @cleanup()
+
 // Mostly check that we don't double emit 'r' which would crash.
 void decl_in_finally(void) {
   __try {
@@ -67,10 +57,11 @@ l:
 // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[invoke_cont]]
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@label_in_finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
+
+// CHECK: define internal void @"\01?fin$0 at 0@label_in_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
 // CHECK: br label %[[l:[^ ]*]]
 //
 // CHECK: [[l]]
@@ -93,32 +84,22 @@ void use_abnormal_termination(void) {
 // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[invoke_cont]]
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK: load i8, i8* %[[abnormal]]
-// CHECK: zext i8 %{{.*}} to i32
-// CHECK: store i32 %{{.*}}, i32* @crashed
-// CHECK: load i8, i8* %[[abnormal]]
-// CHECK: icmp eq
-// CHECK: br i1 %{{.*}}, label %[[finallycont:[^ ]*]], label %[[resumecont:[^ ]*]]
-//
-// CHECK: [[finallycont]]
-// CHECK-NEXT: ret void
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@use_abnormal_termination@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
 //
 // CHECK: [[lpad]]
 // CHECK-NEXT: landingpad
 // CHECK-NEXT: cleanup
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK: br label %[[finally]]
-//
-// CHECK: [[resumecont]]
-// CHECK: br label %[[ehresume:[^ ]*]]
-//
-// CHECK: [[ehresume]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@use_abnormal_termination@@"(i1 zeroext true, i8* %[[fp]])
 // CHECK: resume { i8*, i32 }
 
+// CHECK: define internal void @"\01?fin$0 at 0@use_abnormal_termination@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: %[[abnormal_zext:[^ ]*]] = zext i1 %abnormal_termination to i32
+// CHECK: store i32 %[[abnormal_zext]], i32* @crashed
+// CHECK-NEXT: ret void
+
 void noreturn_noop_finally() {
   __try {
     __noop();
@@ -128,12 +109,13 @@ void noreturn_noop_finally() {
 }
 
 // CHECK-LABEL: define void @noreturn_noop_finally()
-// CHECK: store i8 0, i8* %
-// CHECK: br label %[[finally:[^ ]*]]
-// CHECK: [[finally]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@noreturn_noop_finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
+
+// CHECK: define internal void @"\01?fin$0 at 0@noreturn_noop_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
 // CHECK: call void @abort()
-// CHECK-NEXT: unreachable
-// CHECK-NOT: load
+// CHECK: unreachable
 
 void noreturn_finally() {
   __try {
@@ -148,18 +130,20 @@ void noreturn_finally() {
 // CHECK:     to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[cont]]
-// CHECK: store i8 0, i8* %
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK: call void @abort()
-// CHECK-NEXT: unreachable
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@noreturn_finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
 //
 // CHECK: [[lpad]]
 // CHECK: landingpad
 // CHECK-NEXT: cleanup
-// CHECK: store i8 1, i8* %
-// CHECK: br label %[[finally]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@noreturn_finally@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK: resume { i8*, i32 }
+
+// CHECK: define internal void @"\01?fin$0 at 0@noreturn_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @abort()
+// CHECK: unreachable
 
 int finally_with_return() {
   __try {
@@ -168,15 +152,15 @@ int finally_with_return() {
   }
 }
 // CHECK-LABEL: define i32 @finally_with_return()
-// CHECK: store i8 0, i8* %
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK-NEXT: br label %[[finallycont:[^ ]*]]
-//
-// CHECK: [[finallycont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@finally_with_return@@"(i1 zeroext false, i8* %[[fp]])
 // CHECK-NEXT: ret i32 42
 
+// CHECK: define internal void @"\01?fin$0 at 0@finally_with_return@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK-NOT: br i1
+// CHECK-NOT: br label
+// CHECK: ret void
+
 int nested___finally___finally() {
   __try {
     __try {
@@ -188,38 +172,28 @@ int nested___finally___finally() {
   }
   return 0;
 }
+
 // CHECK-LABEL: define i32 @nested___finally___finally
-// CHECK: store i8 0, i8* %
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: invoke void @"\01?fin$1 at 0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK:          to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[outercont]]
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK-NEXT: ret i32 0
 //
-// CHECK: [[finally]]
-// CHECK-NEXT: store i32 1, i32* %
-// CHECK-NEXT: store i32 1, i32* %
-// CHECK-NEXT: br label %[[cleanup:[^ ]*]]
-//
-// The finally's unreachable continuation block:
-// CHECK: store i32 0, i32* %
-// CHECK-NEXT: br label %[[cleanup]]
-//
-// CHECK: [[cleanup]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]
-//
-// CHECK: [[outerfinally]]
-// CHECK-NEXT: br label %[[finallycont:[^ ]*]]
-//
-// CHECK: [[finallycont]]
-// CHECK-NEXT: %[[dest:[^ ]*]] = load i32, i32* %
-// CHECK-NEXT: switch i32 %[[dest]]
-// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]]
-//
-// CHECK: [[cleanupcont]]
-// CHECK-NEXT: store i32 0, i32* %
-// CHECK-NEXT: br label %[[return:[^ ]*]]
-//
-// CHECK: [[return]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = load i32, i32* %
-// CHECK-NEXT: ret i32 %[[reg]]
+// CHECK: [[lpad]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]])
+
+// CHECK-LABEL: define internal void @"\01?fin$0 at 0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
+
+// CHECK-LABEL: define internal void @"\01?fin$1 at 0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: unreachable
 
 int nested___finally___finally_with_eh_edge() {
   __try {
@@ -234,58 +208,35 @@ int nested___finally___finally_with_eh_e
   return 912;
 }
 // CHECK-LABEL: define i32 @nested___finally___finally_with_eh_edge
-// CHECK: invoke void @might_crash() #3
-// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
-//
-// CHECK: [[invokecont]]
-// CHECK-NEXT: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
-
-// CHECK: [[finally]]
-// CHECK-NEXT: store i32 899, i32* %
-// CHECK-NEXT: store i32 1, i32* %
-// CHECK-NEXT: br label %[[cleanup:[^ ]*]]
-//
-// The inner finally's unreachable continuation block:
-// CHECK: store i32 0, i32* %
-// CHECK-NEXT: br label %[[cleanup]]
-//
-// CHECK: [[cleanup]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]
-//
-// CHECK: [[outerfinally]]
-// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0
-// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]
-//
-// CHECK: [[finallycont]]
-// CHECK-NEXT: %[[dest:[^ ]*]] = load i32, i32* %
-// CHECK-NEXT: switch i32 %[[dest]]
-// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]]
-//
-// CHECK: [[cleanupcont]]
-// CHECK-NEXT: store i32 912, i32* %
-// CHECK-NEXT: br label %[[return:[^ ]*]]
+// CHECK: invoke void @might_crash()
+// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]]
 //
+// [[invokecont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: invoke void @"\01?fin$1 at 0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK:          to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]]
+//
+// CHECK: [[outercont]]
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK-NEXT: ret i32 912
 //
-// CHECK: [[lpad]]
+// CHECK: [[lpad1]]
 // CHECK-NEXT: landingpad
 // CHECK-NEXT: cleanup
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK: br label %[[finally]]
-//
-// The inner finally's unreachable resume block:
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[outerfinally]]
-//
-// CHECK: [[finallyresume]]
-// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
-//
-// CHECK: [[return]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = load i32, i32* %
-// CHECK-NEXT: ret i32 %[[reg]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: invoke void @"\01?fin$1 at 0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK:          to label %[[outercont:[^ ]*]] unwind label %[[lpad2]]
 //
-// The ehresume block, not reachable either.
-// CHECK: [[ehresume]]
+// CHECK: [[lpad2]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]])
 // CHECK: resume
+
+// CHECK-LABEL: define internal void @"\01?fin$0 at 0@nested___finally___finally_with_eh_edge@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
+
+// CHECK-LABEL: define internal void @"\01?fin$1 at 0@nested___finally___finally_with_eh_edge@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: unreachable

Modified: cfe/trunk/test/CodeGen/exceptions-seh-leave.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh-leave.c?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/exceptions-seh-leave.c (original)
+++ cfe/trunk/test/CodeGen/exceptions-seh-leave.c Mon Apr 13 15:03:03 2015
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
 
-void g();
+void g(void);
 
 //////////////////////////////////////////////////////////////////////////////
 // __leave with __except
@@ -38,7 +38,7 @@ int __leave_with___except() {
   return 1;
 }
 // CHECK-LABEL: define i32 @__leave_with___except()
-// CHECK: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK: invoke void @g()
 // CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}}
 // For __excepts, instead of an explicit __try.__leave label, we could use
 // use invoke.cont as __leave jump target instead.  However, not doing this
@@ -74,8 +74,8 @@ int __leave_with___finally_simple() {
 // CHECK-NEXT: br label %[[tryleave:[^ ]*]]
 // CHECK-NOT: store i32 23
 // CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@__leave_with___finally_simple@@"(i1 zeroext false, i8* %[[fp]])
 
 // __finally block doesn't return, __finally.cont doesn't exist.
 int __leave_with___finally_noreturn() {
@@ -94,8 +94,8 @@ int __leave_with___finally_noreturn() {
 // CHECK-NEXT: br label %[[tryleave:[^ ]*]]
 // CHECK-NOT: store i32 23
 // CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@__leave_with___finally_noreturn@@"(i1 zeroext false, i8* %[[fp]])
 
 // The "normal" case.
 int __leave_with___finally() {
@@ -110,7 +110,7 @@ int __leave_with___finally() {
   return 1;
 }
 // CHECK-LABEL: define i32 @__leave_with___finally()
-// CHECK: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK: invoke void @g()
 // CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}}
 // For __finally, there needs to be an explicit __try.__leave, because
 // abnormal.termination.slot needs to be set there.
@@ -118,8 +118,8 @@ int __leave_with___finally() {
 // CHECK-NEXT: br label %[[tryleave:[^ ]*]]
 // CHECK-NOT: store i32 23
 // CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@__leave_with___finally@@"(i1 zeroext false, i8* %[[fp]])
 
 
 //////////////////////////////////////////////////////////////////////////////
@@ -142,45 +142,37 @@ int nested___except___finally() {
   }
   return 1;
 }
-// The order of basic blocks in the below doesn't matter.
 // CHECK-LABEL: define i32 @nested___except___finally()
 
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
-// CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
-
-// CHECK: [[g1_cont]]
-// CHECK-NEXT: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
+// CHECK-LABEL: invoke void @g()
+// CHECK-NEXT:       to label %[[g1_cont1:.*]] unwind label %[[g1_lpad:.*]]
 
-// CHECK: [[finally]]
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)()
-// CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
-
-// CHECK: [[g2_cont]]
-// CHECK-NEXT: br label %[[tryleave:[^ ]*]]
-// CHECK-NOT: store i32 23
+// CHECK: [[g1_cont1]]
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: invoke void @"\01?fin$0 at 0@nested___except___finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK-NEXT:       to label %[[fin_cont:.*]] unwind label %[[g2_lpad:.*]]
 
-// Unused __finally continuation block
+// CHECK: [[fin_cont]]
 // CHECK: store i32 51, i32* %
-// CHECK-NEXT: br label %[[tryleave]]
-
-// CHECK: [[tryleave]]
 // CHECK-NEXT: br label %[[trycont:[^ ]*]]
 
 // CHECK: [[g1_lpad]]
-// CHECK: store i8 1, i8* %
-// CHECK-NEXT:  br label %[[finally]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: catch i8* null
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: invoke void @"\01?fin$0 at 0@nested___except___finally@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK-NEXT:       to label %[[g1_resume:.*]] unwind label %[[g2_lpad]]
 
 // CHECK: [[g2_lpad]]
-// CHECK-NOT: %[[abnormal]]
-// CHECK: br label %[[except:[^ ]*]]
-
-// CHECK: [[except]]
-// CHECK-NEXT: br label %[[trycont]]
+// CHECK: br label %[[trycont]]
 
 // CHECK: [[trycont]]
 // CHECK-NEXT: ret i32 1
 
+// CHECK-LABEL: define internal void @"\01?fin$0 at 0@nested___except___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @g()
+// CHECK: unreachable
+
 int nested___except___except() {
   int myres = 0;
   __try {
@@ -202,7 +194,7 @@ int nested___except___except() {
 // The order of basic blocks in the below doesn't matter.
 // CHECK-LABEL: define i32 @nested___except___except()
 
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-LABEL: invoke void @g()
 // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
 
 // CHECK: [[g1_cont]]
@@ -213,7 +205,7 @@ int nested___except___except() {
 // CHECK:  br label %[[except:[^ ]*]]
 
 // CHECK: [[except]]
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3
+// CHECK-NEXT: invoke void @g()
 // CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
 
 // CHECK: [[g2_cont]]
@@ -256,7 +248,7 @@ int nested___finally___except() {
 // The order of basic blocks in the below doesn't matter.
 // CHECK-LABEL: define i32 @nested___finally___except()
 
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-LABEL: invoke void @g()
 // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
 
 // CHECK: [[g1_cont]]
@@ -266,7 +258,7 @@ int nested___finally___except() {
 // CHECK:  br label %[[except:[^ ]*]]
 
 // CHECK: [[except]]
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-NEXT: invoke void @g()
 // CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
 
 // CHECK: [[g2_cont]]
@@ -274,31 +266,25 @@ int nested___finally___except() {
 // CHECK-NOT: 23
 
 // CHECK: [[g2_lpad]]
-// CHECK: store i8 1, i8* %[[abnormal:[^ ]*]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___except@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
 
 // CHECK: [[trycont]]
 // CHECK: store i32 51, i32* %
 // CHECK-NEXT: br label %[[tryleave]]
 
 // CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
-
-// CHECK: [[finally]]
-// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0
-// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]
-
-// CHECK: [[finallycont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___except@@"(i1 zeroext false, i8* %[[fp]])
 // CHECK-NEXT: ret i32 1
 
-// CHECK: [[finallyresume]]
-// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
-
 // CHECK: [[ehresume]]
 // CHECK: resume
 
+// CHECK-LABEL: define internal void @"\01?fin$0 at 0@nested___finally___except@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
+
 int nested___finally___finally() {
   int myres = 0;
   __try {
@@ -320,51 +306,44 @@ int nested___finally___finally() {
 // The order of basic blocks in the below doesn't matter.
 // CHECK-LABEL: define i32 @nested___finally___finally()
 
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-LABEL: invoke void @g()
 // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
 
 // CHECK: [[g1_cont]]
 // CHECK: store i32 16, i32* %[[myres:[^ ]*]],
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
-
-// CHECK: [[finally]]
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3
-// CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
-
-// CHECK: [[g2_cont]]
-// CHECK-NEXT: br label %[[tryleave:[^ ]*]]
-// CHECK-NOT: store i32 23
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: invoke void @"\01?fin$1 at 0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK-NEXT:       to label %[[finally_cont:.*]] unwind label %[[g2_lpad:.*]]
 
-// There's an unreachable block for the skipped `myres = 51`.
+// CHECK: [[finally_cont]]
 // CHECK: store i32 51, i32* %[[myres]]
-// CHECK-NEXT: br label %[[tryleave]]
-
-// CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]
-
-// CHECK: [[outerfinally]]
-// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0
-// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]
-
-// CHECK: [[finallycont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
 // CHECK-NEXT: ret i32 1
 
 // CHECK: [[g1_lpad]]
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: invoke void @"\01?fin$1 at 0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK-NEXT:       to label %[[finally_cont2:.*]] unwind label %[[g2_lpad]]
 
 // CHECK: [[g2_lpad]]
-// CHECK: br label %[[ehcleanup:[^ ]*]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: br label %[[ehcleanup:.*]]
+
+// CHECK: [[finally_cont2]]
+// CHECK: br label %[[ehcleanup]]
 
 // CHECK: [[ehcleanup]]
-// CHECK-NEXT: store i8 1, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[outerfinally]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK: resume
 
-// CHECK: [[finallyresume]]
-// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
+// CHECK-LABEL: define internal void @"\01?fin$0 at 0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
 
-// CHECK: [[ehresume]]
-// CHECK: resume
+// CHECK-LABEL: define internal void @"\01?fin$1 at 0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @g()
+// CHECK: unreachable

Modified: cfe/trunk/test/CodeGen/exceptions-seh.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh.c?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/exceptions-seh.c (original)
+++ cfe/trunk/test/CodeGen/exceptions-seh.c Mon Apr 13 15:03:03 2015
@@ -118,8 +118,6 @@ int nested_try(void) {
 // 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(void) {
   ++g;
@@ -138,24 +136,23 @@ void basic_finally(void) {
 // CHECK:       to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[cont]]
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK: load i32, i32* @g
-// CHECK: add i32 %{{.*}}, -1
-// CHECK: store i32 %{{.*}}, i32* @g
-// CHECK: icmp eq
-// CHECK: br i1 %{{.*}}, label
-//
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@basic_finally@@"(i1 zeroext false, i8* %[[fp]])
 // CHECK: ret void
 //
 // CHECK: [[lpad]]
 // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
 // CHECK-NEXT: cleanup
-// CHECK: br label %[[finally]]
-//
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@basic_finally@@"(i1 zeroext true, i8* %[[fp]])
 // CHECK: resume
 
+// CHECK: define internal void @"\01?fin$0 at 0@basic_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK:   load i32, i32* @g, align 4
+// CHECK:   add i32 %{{.*}}, -1
+// CHECK:   store i32 %{{.*}}, i32* @g, align 4
+// CHECK:   ret void
+
 int returns_int(void);
 int except_return(void) {
   __try {

Modified: cfe/trunk/test/CodeGenCXX/exceptions-seh.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/exceptions-seh.cpp?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/exceptions-seh.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/exceptions-seh.cpp Mon Apr 13 15:03:03 2015
@@ -5,6 +5,7 @@
 // RUN:         -o - -mconstructor-aliases -O1 -disable-llvm-optzns | \
 // RUN:         FileCheck %s --check-prefix=CHECK --check-prefix=NOCXX
 
+extern "C" unsigned long _exception_code();
 extern "C" void might_throw();
 
 struct HasCleanup {
@@ -95,4 +96,47 @@ void use_seh_in_lambda() {
 // CHECK: invoke void @might_throw() #[[NOINLINE]]
 // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
 
+static int my_unique_global;
+
+extern "C" inline void use_seh_in_inline_func() {
+  __try {
+    might_throw();
+  } __except(_exception_code() == 424242) {
+  }
+  __try {
+    might_throw();
+  } __finally {
+    my_unique_global = 1234;
+  }
+}
+
+void use_inline() {
+  use_seh_in_inline_func();
+}
+
+// CHECK-LABEL: define linkonce_odr void @use_seh_in_inline_func() #{{[0-9]+}} comdat {
+// CHECK: invoke void @might_throw()
+//
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK-NEXT: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0 at 0@use_seh_in_inline_func@@" to i8*)
+//
+// CHECK: invoke void @might_throw()
+//
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@use_seh_in_inline_func@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
+//
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@use_seh_in_inline_func@@"(i1 zeroext true, i8* %[[fp]])
+
+// CHECK-LABEL: define internal i32 @"\01?filt$0 at 0@use_seh_in_inline_func@@"(i8* %exception_pointers, i8* %frame_pointer) #{{[0-9]+}} comdat($use_seh_in_inline_func)
+// CHECK: icmp eq i32 %{{.*}}, 424242
+// CHECK: zext i1 %{{.*}} to i32
+// CHECK: ret i32
+
+// CHECK-LABEL: define internal void @"\01?fin$0 at 0@use_seh_in_inline_func@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) #{{[0-9]+}} comdat($use_seh_in_inline_func)
+// CHECK: store i32 1234, i32* @my_unique_global
+
 // CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} }

Modified: cfe/trunk/test/SemaCXX/switch-implicit-fallthrough.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/switch-implicit-fallthrough.cpp?rev=234787&r1=234786&r2=234787&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/switch-implicit-fallthrough.cpp (original)
+++ cfe/trunk/test/SemaCXX/switch-implicit-fallthrough.cpp Mon Apr 13 15:03:03 2015
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wimplicit-fallthrough %s
 
+
 int fallthrough(int n) {
   switch (n / 10) {
       if (n - 1) {
@@ -299,8 +300,3 @@ int fallthrough_targets(int n) {
   }
   return n;
 }
-
-[[clang::fallthrough]] int a; // expected-error {{'fallthrough' attribute only applies to empty statements}}
-[[clang::fallthrough]] int f(); // expected-error {{'fallthrough' attribute only applies to empty statements}}
-void g([[clang::fallthrough]] int p); // expected-error {{'fallthrough' attribute only applies to empty statements}}
-struct [[clang::fallthrough]] S; // expected-error {{'fallthrough' attribute only applies to empty statements}}





More information about the cfe-commits mailing list