From 5aaa165ebe4c4177f5d461bab50671fc83b0aee5 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 13 Apr 2015 20:01:20 +0000 Subject: [PATCH] Revert r234613 (and follow-ups 234614, 234616, 234618), it caused PR23216. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@234786 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Mangle.h | 3 - include/clang/Basic/Attr.td | 5 +- include/clang/Basic/DiagnosticSemaKinds.td | 2 +- include/clang/Sema/AttributeList.h | 3 +- lib/AST/ItaniumMangle.cpp | 12 - lib/AST/MicrosoftMangle.cpp | 14 - lib/CodeGen/CGException.cpp | 265 ++++++++----------- lib/CodeGen/CGStmt.cpp | 6 - lib/CodeGen/CodeGenFunction.cpp | 2 +- lib/CodeGen/CodeGenFunction.h | 30 ++- lib/Driver/SanitizerArgs.cpp | 3 +- test/CodeGen/exceptions-seh-finally.c | 227 +++++++++------- test/CodeGen/exceptions-seh-leave.c | 149 ++++++----- test/CodeGen/exceptions-seh.c | 23 +- test/CodeGenCXX/exceptions-seh.cpp | 44 --- test/SemaCXX/switch-implicit-fallthrough.cpp | 6 +- 16 files changed, 385 insertions(+), 409 deletions(-) diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h index 1050e65ff0..e4bccedff9 100644 --- a/include/clang/AST/Mangle.h +++ b/include/clang/AST/Mangle.h @@ -135,9 +135,6 @@ 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 diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 05a399afda..bc2051d868 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -106,6 +106,8 @@ def SharedVar : SubsetSubjecthasGlobalStorage()}]>; +def NotAllowedOnDecls : SubsetSubject; + // 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, @@ -690,7 +692,8 @@ def ExtVectorType : Attr { def FallThrough : Attr { let Spellings = [CXX11<"clang", "fallthrough">]; -// let Subjects = [NullStmt]; + let Subjects = SubjectList<[NotAllowedOnDecls], ErrorDiag, + "ExpectedEmptyStatement">; let Documentation = [FallthroughDocs]; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 6e37856c34..2ebc430e52 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2266,7 +2266,7 @@ def warn_attribute_wrong_decl_type : Warning< "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}1">, + "interface or protocol declarations|kernel functions|empty statements}1">, InGroup; def err_attribute_wrong_decl_type : Error; def warn_type_attribute_wrong_type : Warning< diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 58b1b9ee24..300f15055e 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -846,7 +846,8 @@ enum AttributeDeclKind { ExpectedStructOrUnionOrTypedef, ExpectedStructOrTypedef, ExpectedObjectiveCInterfaceOrProtocol, - ExpectedKernelFunction + ExpectedKernelFunction, + ExpectedEmptyStatement }; } // end namespace clang diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 6e55655d85..f890719c20 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -166,8 +166,6 @@ 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; @@ -3969,16 +3967,6 @@ void ItaniumMangleContextImpl::mangleSEHFilterExpression( 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(); -} - void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &Out) { // ::= TH diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 269fb1c255..bf9d7a0118 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -94,7 +94,6 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext { llvm::DenseMap Uniquifier; llvm::DenseMap LambdaIds; llvm::DenseMap SEHFilterIds; - llvm::DenseMap SEHFinallyIds; public: MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags) @@ -152,8 +151,6 @@ 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; @@ -2472,17 +2469,6 @@ void MicrosoftMangleContextImpl::mangleSEHFilterExpression( 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. - // - // ::= ?fin$ @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. diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index ff12a9ab82..cc16053ac7 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -23,7 +23,6 @@ #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; @@ -409,6 +408,13 @@ llvm::Value *CodeGenFunction::getSelectorFromSlot() { 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()) { @@ -1281,7 +1287,8 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) { return; } - EnterSEHTryStmt(S); + SEHFinallyInfo FI; + EnterSEHTryStmt(S, FI); { JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave"); @@ -1294,36 +1301,42 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) { else delete TryExit.getBlock(); } - ExitSEHTryStmt(S); + ExitSEHTryStmt(S, FI); } namespace { -struct PerformSEHFinally : EHScopeStack::Cleanup { - llvm::Function *OutlinedFinally; - PerformSEHFinally(llvm::Function *OutlinedFinally) - : OutlinedFinally(OutlinedFinally) {} +struct PerformSEHFinally : EHScopeStack::Cleanup { + CodeGenFunction::SEHFinallyInfo *FI; + PerformSEHFinally(CodeGenFunction::SEHFinallyInfo *FI) : FI(FI) {} void Emit(CodeGenFunction &CGF, Flags F) override { - ASTContext &Context = CGF.getContext(); - QualType ArgTys[2] = {Context.BoolTy, Context.VoidPtrTy}; - FunctionProtoType::ExtProtoInfo EPI; - const auto *FTP = cast( - 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); + // 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); + } } }; } @@ -1341,8 +1354,7 @@ struct CaptureFinder : ConstStmtVisitor { // See if this is a capture, then recurse. ConstStmtVisitor::Visit(S); for (const Stmt *Child : S->children()) - if (Child) - Visit(Child); + Visit(Child); } void VisitDeclRefExpr(const DeclRefExpr *E) { @@ -1391,16 +1403,12 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, CGM.ErrorUnsupported(VD, "VLA captured by SEH"); continue; } + assert((isa(VD) || VD->isLocalVarDeclOrParm()) && "captured non-local variable"); - // 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::Value *ParentVar = ParentCGF.LocalDeclMap[VD]; + assert(ParentVar && "capture was not a local decl"); llvm::CallInst *RecoverCall = nullptr; CGBuilderTy Builder(AllocaInsertPt); if (auto *ParentAlloca = dyn_cast(ParentVar)) { @@ -1437,81 +1445,63 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, } } -/// 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; - 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, 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()) { - llvm::Comdat *C = CGM.getModule().getOrInsertComdat(ParentFn->getName()); - ParentFn->setComdat(C); - Fn->setComdat(C); - } else { - Fn->setLinkage(llvm::GlobalValue::InternalLinkage); - } - - IsOutlinedSEHHelper = true; - - StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args, - OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart()); - - CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn); - - auto AI = Fn->arg_begin(); - ++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(); + const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl; + llvm::Function *ParentFn = ParentCGF.CurFn; - 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)); + Expr *FilterExpr = Except.getFilterExpr(); // 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(ParentCodeDecl); assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH"); CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS); } - startOutlinedSEHHelper(ParentCGF, Name, getContext().IntTy, Args, FilterExpr); + // 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); + } - // 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); + StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args, + FilterExpr->getLocStart(), FilterExpr->getLocStart()); EmitSEHExceptionCodeSave(); + auto AI = Fn->arg_begin(); + ++AI; + EmitCapturedLocals(ParentCGF, FilterExpr, &*AI); + // Emit the original filter expression, convert to i32, and return. llvm::Value *R = EmitScalarExpr(FilterExpr); R = Builder.CreateIntCast(R, CGM.IntTy, @@ -1520,42 +1510,7 @@ CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, FinishFunction(FilterExpr->getLocEnd()); - 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(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; + return Fn; } void CodeGenFunction::EmitSEHExceptionCodeSave() { @@ -1599,24 +1554,21 @@ llvm::Value *CodeGenFunction::EmitSEHExceptionCode() { } llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() { - // Abnormal termination is just the first parameter to the outlined finally - // helper. - auto AI = CurFn->arg_begin(); - return Builder.CreateZExt(&*AI, Int32Ty); + // 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); } -void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { - CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true); - if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) { +void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) { + if (S.getFinallyHandler()) { // Push a cleanup for __finally blocks. - llvm::Function *FinallyFunc = - HelperCGF.GenerateSEHFinallyFunction(*this, *Finally); - EHStack.pushCleanup(NormalAndEHCleanup, FinallyFunc); + EHStack.pushCleanup(NormalAndEHCleanup, &FI); return; } // Otherwise, we must have an __except block. - const SEHExceptStmt *Except = S.getExceptHandler(); + SEHExceptStmt *Except = S.getExceptHandler(); assert(Except); EHCatchScope *CatchScope = EHStack.pushCatch(1); @@ -1631,17 +1583,40 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { // 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 = - HelperCGF.GenerateSEHFilterFunction(*this, *Except); + FilterCGF.GenerateSEHFilterFunction(*this, *Except); llvm::Constant *OpaqueFunc = llvm::ConstantExpr::getBitCast(FilterFunc, Int8PtrTy); CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except")); } -void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { +void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) { // Just pop the cleanup if it's a __finally block. - if (S.getFinallyHandler()) { + if (const SEHFinallyStmt *Finally = 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; } @@ -1691,13 +1666,7 @@ void CodeGenFunction::EmitSEHLeaveStmt(const SEHLeaveStmt &S) { if (HaveInsertPoint()) EmitStopPoint(&S); - // 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; - } - + assert(!SEHTryEpilogueStack.empty() && + "sema should have rejected this __leave"); EmitBranchThroughCleanup(*SEHTryEpilogueStack.back()); } diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 481fdbe227..e4339849ca 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -1021,12 +1021,6 @@ void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) { /// 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(); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 42c3a423fa..8401d722f4 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -40,7 +40,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) CurFn(nullptr), CapturedStmtInfo(nullptr), SanOpts(CGM.getLangOpts().Sanitize), IsSanitizerScope(false), CurFuncIsThunk(false), AutoreleaseResult(false), SawAsmBlock(false), - IsOutlinedSEHHelper(false), BlockInfo(nullptr), BlockPointer(nullptr), + BlockInfo(nullptr), BlockPointer(nullptr), LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr), NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr), ExceptionSlot(nullptr), EHSelectorSlot(nullptr), diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 343edc2ebf..087acc7317 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -263,10 +263,6 @@ 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; @@ -355,6 +351,17 @@ 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(); } @@ -1045,6 +1052,10 @@ 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(); @@ -1989,19 +2000,12 @@ 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); - - void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, StringRef Name, - QualType RetTy, FunctionArgList &Args, - const Stmt *OutlinedStmt); + void EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI); + void ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI); llvm::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, const SEHExceptStmt &Except); - llvm::Function *GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF, - const SEHFinallyStmt &Finally); - void EmitSEHExceptionCodeSave(); llvm::Value *EmitSEHExceptionCode(); llvm::Value *EmitSEHExceptionInfo(); diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index cd3785cd90..d4e45f1b34 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/lib/Driver/SanitizerArgs.cpp @@ -387,7 +387,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, 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; } } } diff --git a/test/CodeGen/exceptions-seh-finally.c b/test/CodeGen/exceptions-seh-finally.c index a594aaac05..eeadf0d5ec 100644 --- a/test/CodeGen/exceptions-seh-finally.c +++ b/test/CodeGen/exceptions-seh-finally.c @@ -17,20 +17,30 @@ void basic_finally(void) { // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[invoke_cont]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext false, i8* %[[fp]]) +// 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-NEXT: ret void // // CHECK: [[lpad]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext true, i8* %[[fp]]) +// CHECK: store i8 1, i8* %[[abnormal]] +// CHECK: br label %[[finally]] +// +// CHECK: [[resumecont]] +// CHECK: br label %[[ehresume:[^ ]*]] +// +// CHECK: [[ehresume]] // CHECK: resume { i8*, i32 } -// CHECK: define internal void @"\01?fin$0@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 { @@ -57,11 +67,10 @@ l: // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[invoke_cont]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@label_in_finally@@"(i1 zeroext false, i8* %[[fp]]) -// CHECK: ret void - -// CHECK: define internal void @"\01?fin$0@0@label_in_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]] +// CHECK: br label %[[finally:[^ ]*]] +// +// CHECK: [[finally]] // CHECK: br label %[[l:[^ ]*]] // // CHECK: [[l]] @@ -84,22 +93,32 @@ void use_abnormal_termination(void) { // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[invoke_cont]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext false, i8* %[[fp]]) -// CHECK: ret void +// 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: [[lpad]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext true, i8* %[[fp]]) +// CHECK: store i8 1, i8* %[[abnormal]] +// CHECK: br label %[[finally]] +// +// CHECK: [[resumecont]] +// CHECK: br label %[[ehresume:[^ ]*]] +// +// CHECK: [[ehresume]] // CHECK: resume { i8*, i32 } -// CHECK: define internal void @"\01?fin$0@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(); @@ -109,13 +128,12 @@ void noreturn_noop_finally() { } // CHECK-LABEL: define void @noreturn_noop_finally() -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@noreturn_noop_finally@@"(i1 zeroext false, i8* %[[fp]]) -// CHECK: ret void - -// CHECK: define internal void @"\01?fin$0@0@noreturn_noop_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: store i8 0, i8* % +// CHECK: br label %[[finally:[^ ]*]] +// CHECK: [[finally]] // CHECK: call void @abort() -// CHECK: unreachable +// CHECK-NEXT: unreachable +// CHECK-NOT: load void noreturn_finally() { __try { @@ -130,20 +148,18 @@ void noreturn_finally() { // CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[cont]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext false, i8* %[[fp]]) -// CHECK: ret void +// CHECK: store i8 0, i8* % +// CHECK: br label %[[finally:[^ ]*]] +// +// CHECK: [[finally]] +// CHECK: call void @abort() +// CHECK-NEXT: unreachable // // CHECK: [[lpad]] // CHECK: landingpad // CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext true, i8* %[[fp]]) -// CHECK: resume { i8*, i32 } - -// CHECK: define internal void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) -// CHECK: call void @abort() -// CHECK: unreachable +// CHECK: store i8 1, i8* % +// CHECK: br label %[[finally]] int finally_with_return() { __try { @@ -152,15 +168,15 @@ int finally_with_return() { } } // CHECK-LABEL: define i32 @finally_with_return() -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@finally_with_return@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK: store i8 0, i8* % +// CHECK-NEXT: br label %[[finally:[^ ]*]] +// +// CHECK: [[finally]] +// CHECK-NEXT: br label %[[finallycont:[^ ]*]] +// +// CHECK: [[finallycont]] // CHECK-NEXT: ret i32 42 -// CHECK: define internal void @"\01?fin$0@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 { @@ -172,28 +188,38 @@ int nested___finally___finally() { } return 0; } - // CHECK-LABEL: define i32 @nested___finally___finally -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]]) -// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]] +// CHECK: store i8 0, i8* % +// CHECK-NEXT: br label %[[finally:[^ ]*]] // -// CHECK: [[outercont]] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@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:[^ ]*]] // -// CHECK: [[lpad]] -// CHECK-NEXT: landingpad -// CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]]) - -// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) -// CHECK: ret void - -// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) -// CHECK: unreachable +// 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]] int nested___finally___finally_with_eh_edge() { __try { @@ -208,35 +234,58 @@ int nested___finally___finally_with_eh_edge() { return 912; } // CHECK-LABEL: define i32 @nested___finally___finally_with_eh_edge -// CHECK: invoke void @might_crash() -// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]] +// CHECK: invoke void @might_crash() #3 +// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // -// [[invokecont]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]]) -// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]] +// 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:[^ ]*]] // -// CHECK: [[outercont]] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]]) -// CHECK-NEXT: ret i32 912 +// The inner finally's unreachable continuation block: +// CHECK: store i32 0, i32* % +// CHECK-NEXT: br label %[[cleanup]] // -// CHECK: [[lpad1]] -// CHECK-NEXT: landingpad -// CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]]) -// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2]] +// 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: [[lpad2]] +// CHECK: [[cleanupcont]] +// CHECK-NEXT: store i32 912, i32* % +// CHECK-NEXT: br label %[[return:[^ ]*]] +// +// +// CHECK: [[lpad]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]]) +// 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]] +// +// The ehresume block, not reachable either. +// CHECK: [[ehresume]] // CHECK: resume - -// CHECK-LABEL: define internal void @"\01?fin$0@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@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) -// CHECK: unreachable diff --git a/test/CodeGen/exceptions-seh-leave.c b/test/CodeGen/exceptions-seh-leave.c index 793501a9fe..0d38439c9b 100644 --- a/test/CodeGen/exceptions-seh-leave.c +++ b/test/CodeGen/exceptions-seh-leave.c @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s -void g(void); +void g(); ////////////////////////////////////////////////////////////////////////////// // __leave with __except @@ -38,7 +38,7 @@ int __leave_with___except() { return 1; } // CHECK-LABEL: define i32 @__leave_with___except() -// CHECK: invoke void @g() +// CHECK: invoke void bitcast (void (...)* @g to void ()*)() // 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: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_simple@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK-NEXT: store i8 0, i8* % +// CHECK-NEXT: br label % // __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: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_noreturn@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK-NEXT: store i8 0, i8* % +// CHECK-NEXT: br label % // 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 @g() +// CHECK: invoke void bitcast (void (...)* @g to void ()*)() // 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: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK-NEXT: store i8 0, i8* % +// CHECK-NEXT: br label % ////////////////////////////////////////////////////////////////////////////// @@ -142,37 +142,45 @@ 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 @g() -// CHECK-NEXT: to label %[[g1_cont1:.*]] unwind label %[[g1_lpad:.*]] +// 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: [[g1_cont1]] -// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i1 zeroext false, i8* %[[fp]]) -// CHECK-NEXT: to label %[[fin_cont:.*]] unwind label %[[g2_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: [[fin_cont]] +// Unused __finally continuation block // CHECK: store i32 51, i32* % +// CHECK-NEXT: br label %[[tryleave]] + +// CHECK: [[tryleave]] // CHECK-NEXT: br label %[[trycont:[^ ]*]] // CHECK: [[g1_lpad]] -// CHECK-NEXT: landingpad -// CHECK-NEXT: catch i8* null -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i1 zeroext true, i8* %[[fp]]) -// CHECK-NEXT: to label %[[g1_resume:.*]] unwind label %[[g2_lpad]] +// CHECK: store i8 1, i8* % +// CHECK-NEXT: br label %[[finally]] // CHECK: [[g2_lpad]] -// CHECK: br label %[[trycont]] +// CHECK-NOT: %[[abnormal]] +// CHECK: br label %[[except:[^ ]*]] + +// CHECK: [[except]] +// CHECK-NEXT: br label %[[trycont]] // CHECK: [[trycont]] // CHECK-NEXT: ret i32 1 -// CHECK-LABEL: define internal void @"\01?fin$0@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 { @@ -194,7 +202,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 @g() +// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)() // CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] // CHECK: [[g1_cont]] @@ -205,7 +213,7 @@ int nested___except___except() { // CHECK: br label %[[except:[^ ]*]] // CHECK: [[except]] -// CHECK-NEXT: invoke void @g() +// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3 // CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] // CHECK: [[g2_cont]] @@ -248,7 +256,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 @g() +// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)() // CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] // CHECK: [[g1_cont]] @@ -258,7 +266,7 @@ int nested___finally___except() { // CHECK: br label %[[except:[^ ]*]] // CHECK: [[except]] -// CHECK-NEXT: invoke void @g() +// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() // CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] // CHECK: [[g2_cont]] @@ -266,25 +274,31 @@ int nested___finally___except() { // CHECK-NOT: 23 // CHECK: [[g2_lpad]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i1 zeroext true, i8* %[[fp]]) -// CHECK-NEXT: br label %[[ehresume:[^ ]*]] +// CHECK: store i8 1, i8* %[[abnormal:[^ ]*]] +// CHECK-NEXT: br label %[[finally:[^ ]*]] // CHECK: [[trycont]] // CHECK: store i32 51, i32* % // CHECK-NEXT: br label %[[tryleave]] // CHECK: [[tryleave]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i1 zeroext false, i8* %[[fp]]) +// 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-NEXT: ret i32 1 +// CHECK: [[finallyresume]] +// CHECK-NEXT: br label %[[ehresume:[^ ]*]] + // CHECK: [[ehresume]] // CHECK: resume -// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___except@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) -// CHECK: ret void - int nested___finally___finally() { int myres = 0; __try { @@ -306,44 +320,51 @@ 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 @g() +// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)() // CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] // CHECK: [[g1_cont]] // CHECK: store i32 16, i32* %[[myres:[^ ]*]], -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]]) -// CHECK-NEXT: to label %[[finally_cont:.*]] unwind label %[[g2_lpad:.*]] +// 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: [[finally_cont]] +// There's an unreachable block for the skipped `myres = 51`. // CHECK: store i32 51, i32* %[[myres]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]]) +// 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-NEXT: ret i32 1 // CHECK: [[g1_lpad]] -// CHECK-NEXT: landingpad -// CHECK-NEXT: cleanup -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]]) -// CHECK-NEXT: to label %[[finally_cont2:.*]] unwind label %[[g2_lpad]] +// CHECK: store i8 1, i8* %[[abnormal]] +// CHECK-NEXT: br label %[[finally:[^ ]*]] // CHECK: [[g2_lpad]] -// CHECK-NEXT: landingpad -// CHECK-NEXT: cleanup -// CHECK: br label %[[ehcleanup:.*]] - -// CHECK: [[finally_cont2]] -// CHECK: br label %[[ehcleanup]] +// CHECK: br label %[[ehcleanup:[^ ]*]] // CHECK: [[ehcleanup]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]]) -// CHECK: resume +// CHECK-NEXT: store i8 1, i8* %[[abnormal]] +// CHECK-NEXT: br label %[[outerfinally]] -// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) -// CHECK: ret void +// CHECK: [[finallyresume]] +// CHECK-NEXT: br label %[[ehresume:[^ ]*]] -// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) -// CHECK: call void @g() -// CHECK: unreachable +// CHECK: [[ehresume]] +// CHECK: resume diff --git a/test/CodeGen/exceptions-seh.c b/test/CodeGen/exceptions-seh.c index 9a273ced56..2d9d4b1f01 100644 --- a/test/CodeGen/exceptions-seh.c +++ b/test/CodeGen/exceptions-seh.c @@ -118,6 +118,8 @@ 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; @@ -136,23 +138,24 @@ void basic_finally(void) { // CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[cont]] -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) -// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext false, i8* %[[fp]]) +// 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: ret void // // CHECK: [[lpad]] // 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@0@basic_finally@@"(i1 zeroext true, i8* %[[fp]]) +// CHECK: br label %[[finally]] +// // CHECK: resume -// CHECK: define internal void @"\01?fin$0@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 { diff --git a/test/CodeGenCXX/exceptions-seh.cpp b/test/CodeGenCXX/exceptions-seh.cpp index cb5f6dfad9..5f93cb1be3 100644 --- a/test/CodeGenCXX/exceptions-seh.cpp +++ b/test/CodeGenCXX/exceptions-seh.cpp @@ -5,7 +5,6 @@ // 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 { @@ -96,47 +95,4 @@ 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@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@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@0@use_seh_in_inline_func@@"(i1 zeroext true, i8* %[[fp]]) - -// CHECK-LABEL: define internal i32 @"\01?filt$0@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@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.*}} } diff --git a/test/SemaCXX/switch-implicit-fallthrough.cpp b/test/SemaCXX/switch-implicit-fallthrough.cpp index 0bc43cdbd4..a547dc6d9f 100644 --- a/test/SemaCXX/switch-implicit-fallthrough.cpp +++ b/test/SemaCXX/switch-implicit-fallthrough.cpp @@ -1,6 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wimplicit-fallthrough %s - int fallthrough(int n) { switch (n / 10) { if (n - 1) { @@ -300,3 +299,8 @@ 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}} -- 2.40.0