summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorReid Kleckner <reid@kleckner.net>2015-01-22 01:36:17 +0000
committerReid Kleckner <reid@kleckner.net>2015-01-22 01:36:17 +0000
commit1d59f99f5c1c28035bd5fa35626d5813dc2b0500 (patch)
tree89bed5a8ee159a87b91585c17662264709410f25 /clang/lib
parente855c2ae0a205cc47aff5f21c0cf97d556e80e64 (diff)
downloadbcm5719-llvm-1d59f99f5c1c28035bd5fa35626d5813dc2b0500.tar.gz
bcm5719-llvm-1d59f99f5c1c28035bd5fa35626d5813dc2b0500.zip
Initial support for Win64 SEH IR emission
The lowering looks a lot like normal EH lowering, with the exception that the exceptions are caught by executing filter expression code instead of matching typeinfo globals. The filter expressions are outlined into functions which are used in landingpad clauses where typeinfo would normally go. Major aspects that still need work: - Non-call exceptions in __try bodies won't work yet. The plan is to outline the __try block in the frontend to keep things simple. - Filter expressions cannot use local variables until capturing is implemented. - __finally blocks will not run after exceptions. Fixing this requires work in the LLVM SEH preparation pass. The IR lowering looks like this: // C code: bool safe_div(int n, int d, int *r) { __try { *r = normal_div(n, d); } __except(_exception_code() == EXCEPTION_INT_DIVIDE_BY_ZERO) { return false; } return true; } ; LLVM IR: define i32 @filter(i8* %e, i8* %fp) { %ehptrs = bitcast i8* %e to i32** %ehrec = load i32** %ehptrs %code = load i32* %ehrec %matches = icmp eq i32 %code, i32 u0xC0000094 %matches.i32 = zext i1 %matches to i32 ret i32 %matches.i32 } define i1 zeroext @safe_div(i32 %n, i32 %d, i32* %r) { %rr = invoke i32 @normal_div(i32 %n, i32 %d) to label %normal unwind to label %lpad normal: store i32 %rr, i32* %r ret i1 1 lpad: %ehvals = landingpad {i8*, i32} personality i32 (...)* @__C_specific_handler catch i8* bitcast (i32 (i8*, i8*)* @filter to i8*) %ehptr = extractvalue {i8*, i32} %ehvals, i32 0 %sel = extractvalue {i8*, i32} %ehvals, i32 1 %filter_sel = call i32 @llvm.eh.seh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @filter to i8*)) %matches = icmp eq i32 %sel, %filter_sel br i1 %matches, label %eh.except, label %eh.resume eh.except: ret i1 false eh.resume: resume } Reviewers: rjmccall, rsmith, majnemer Differential Revision: http://reviews.llvm.org/D5607 llvm-svn: 226760
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp12
-rw-r--r--clang/lib/AST/MicrosoftMangle.cpp14
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp7
-rw-r--r--clang/lib/CodeGen/CGException.cpp255
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp2
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h14
-rw-r--r--clang/lib/Parse/ParseStmt.cpp11
-rw-r--r--clang/lib/Sema/JumpDiagnostics.cpp4
-rw-r--r--clang/lib/Sema/Scope.cpp3
-rw-r--r--clang/lib/Sema/SemaChecking.cpp38
10 files changed, 353 insertions, 7 deletions
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 156ad646fa6..467bbe1f225 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -156,6 +156,8 @@ public:
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &Out) override;
+ void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
+ raw_ostream &Out) override;
void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override;
void mangleItaniumThreadLocalWrapper(const VarDecl *D,
raw_ostream &) override;
@@ -3845,6 +3847,16 @@ void ItaniumMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D,
Mangler.getStream() << D->getName();
}
+void ItaniumMangleContextImpl::mangleSEHFilterExpression(
+ const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "__filt_";
+ if (shouldMangleDeclName(EnclosingDecl))
+ Mangler.mangle(EnclosingDecl);
+ else
+ Mangler.getStream() << EnclosingDecl->getName();
+}
+
void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D,
raw_ostream &Out) {
// <special-name> ::= TH <object name>
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 72f90f67cbd..4b238863869 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -89,6 +89,7 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
+ llvm::DenseMap<const NamedDecl *, unsigned> SEHFilterIds;
public:
MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
@@ -134,6 +135,8 @@ public:
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &Out) override;
+ void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
+ raw_ostream &Out) override;
void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
// Lambda closure types are already numbered.
@@ -2318,6 +2321,17 @@ void MicrosoftMangleContextImpl::mangleCXXRTTICompleteObjectLocator(
Mangler.getStream() << '@';
}
+void MicrosoftMangleContextImpl::mangleSEHFilterExpression(
+ const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ // The function body is in the same comdat as the function with the handler,
+ // so the numbering here doesn't have to be the same across TUs.
+ //
+ // <mangled-name> ::= ?filt$ <filter-number> @0
+ Mangler.getStream() << "\01?filt$" << SEHFilterIds[EnclosingDecl]++ << "@0@";
+ Mangler.mangleName(EnclosingDecl);
+}
+
void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
// This is just a made up unique string for the purposes of tbaa. undname
// does *not* know how to demangle it.
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 635e34207de..8f320d1d776 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -1650,6 +1650,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Builder.CreateAlignedLoad(IntToPtr, /*Align=*/4, /*isVolatile=*/true);
return RValue::get(Load);
}
+
+ case Builtin::BI__exception_code:
+ case Builtin::BI_exception_code:
+ return RValue::get(EmitSEHExceptionCode());
+ case Builtin::BI__exception_info:
+ case Builtin::BI_exception_info:
+ return RValue::get(EmitSEHExceptionInfo());
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index cb8eb8fa490..94cfca962d1 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -16,6 +16,7 @@
#include "CGCleanup.h"
#include "CGObjCRuntime.h"
#include "TargetInfo.h"
+#include "clang/AST/Mangle.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "llvm/IR/CallSite.h"
@@ -98,9 +99,10 @@ static llvm::Constant *getTerminateFn(CodeGenModule &CGM) {
StringRef name;
// In C++, use std::terminate().
- if (CGM.getLangOpts().CPlusPlus)
- name = "_ZSt9terminatev"; // FIXME: mangling!
- else if (CGM.getLangOpts().ObjC1 &&
+ if (CGM.getLangOpts().CPlusPlus &&
+ CGM.getTarget().getCXXABI().isItaniumFamily()) {
+ name = "_ZSt9terminatev";
+ } else if (CGM.getLangOpts().ObjC1 &&
CGM.getLangOpts().ObjCRuntime.hasTerminate())
name = "objc_terminate";
else
@@ -137,6 +139,8 @@ namespace {
static const EHPersonality GNU_CPlusPlus;
static const EHPersonality GNU_CPlusPlus_SJLJ;
static const EHPersonality GNU_CPlusPlus_SEH;
+ static const EHPersonality MSVC_except_handler;
+ static const EHPersonality MSVC_C_specific_handler;
};
}
@@ -159,6 +163,10 @@ const EHPersonality
EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", nullptr };
const EHPersonality
EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", nullptr };
+const EHPersonality
+EHPersonality::MSVC_except_handler = { "_except_handler3", nullptr };
+const EHPersonality
+EHPersonality::MSVC_C_specific_handler = { "__C_specific_handler", nullptr };
/// On Win64, use libgcc's SEH personality function. We fall back to dwarf on
/// other platforms, unless the user asked for SjLj exceptions.
@@ -231,9 +239,37 @@ static const EHPersonality &getObjCXXPersonality(const llvm::Triple &T,
llvm_unreachable("bad runtime kind");
}
+static const EHPersonality &getCPersonalityMSVC(const llvm::Triple &T,
+ const LangOptions &L) {
+ if (L.SjLjExceptions)
+ return EHPersonality::GNU_C_SJLJ;
+
+ if (T.getArch() == llvm::Triple::x86)
+ return EHPersonality::MSVC_except_handler;
+ return EHPersonality::MSVC_C_specific_handler;
+}
+
+static const EHPersonality &getCXXPersonalityMSVC(const llvm::Triple &T,
+ const LangOptions &L) {
+ if (L.SjLjExceptions)
+ return EHPersonality::GNU_CPlusPlus_SJLJ;
+ // FIXME: Implement C++ exceptions.
+ return getCPersonalityMSVC(T, L);
+}
+
const EHPersonality &EHPersonality::get(CodeGenModule &CGM) {
const llvm::Triple &T = CGM.getTarget().getTriple();
const LangOptions &L = CGM.getLangOpts();
+ // Try to pick a personality function that is compatible with MSVC if we're
+ // not compiling Obj-C. Obj-C users better have an Obj-C runtime that supports
+ // the GCC-style personality function.
+ if (T.isWindowsMSVCEnvironment() && !L.ObjC1) {
+ if (L.CPlusPlus)
+ return getCXXPersonalityMSVC(T, L);
+ else
+ return getCPersonalityMSVC(T, L);
+ }
+
if (L.CPlusPlus && L.ObjC1)
return getObjCXXPersonality(T, L);
else if (L.CPlusPlus)
@@ -1642,7 +1678,218 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
}
void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
- CGM.ErrorUnsupported(&S, "SEH __try");
+ // FIXME: Implement SEH on other architectures.
+ const llvm::Triple &T = CGM.getTarget().getTriple();
+ if (T.getArch() != llvm::Triple::x86_64 ||
+ !T.isKnownWindowsMSVCEnvironment()) {
+ ErrorUnsupported(&S, "__try statement");
+ return;
+ }
+
+ EnterSEHTryStmt(S);
+ EmitStmt(S.getTryBlock());
+ ExitSEHTryStmt(S);
+}
+
+namespace {
+struct PerformSEHFinally : EHScopeStack::Cleanup {
+ Stmt *Block;
+ PerformSEHFinally(Stmt *Block) : Block(Block) {}
+ void Emit(CodeGenFunction &CGF, Flags F) override {
+ // FIXME: Don't double-emit LabelDecls.
+ CGF.EmitStmt(Block);
+ }
+};
+}
+
+/// Create a stub filter function that will ultimately hold the code of the
+/// filter expression. The EH preparation passes in LLVM will outline the code
+/// from the main function body into this stub.
+llvm::Function *
+CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
+ const SEHExceptStmt &Except) {
+ const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
+ llvm::Function *ParentFn = ParentCGF.CurFn;
+
+ Expr *FilterExpr = Except.getFilterExpr();
+
+ // Get the mangled function name.
+ SmallString<128> Name;
+ {
+ llvm::raw_svector_ostream OS(Name);
+ const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
+ assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
+ CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS);
+ }
+
+ // Arrange a function with the declaration:
+ // int filt(EXCEPTION_POINTERS *exception_pointers, void *frame_pointer)
+ QualType RetTy = getContext().IntTy;
+ FunctionArgList Args;
+ SEHPointersDecl = ImplicitParamDecl::Create(
+ getContext(), nullptr, FilterExpr->getLocStart(),
+ &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
+ Args.push_back(SEHPointersDecl);
+ Args.push_back(ImplicitParamDecl::Create(
+ getContext(), nullptr, FilterExpr->getLocStart(),
+ &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
+ const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ RetTy, Args, FunctionType::ExtInfo(), /*isVariadic=*/false);
+ llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
+ llvm::Function *Fn = llvm::Function::Create(FnTy, ParentFn->getLinkage(),
+ Name.str(), &CGM.getModule());
+ // The filter is either in the same comdat as the function, or it's internal.
+ if (llvm::Comdat *C = ParentFn->getComdat()) {
+ Fn->setComdat(C);
+ } else if (ParentFn->hasWeakLinkage() || ParentFn->hasLinkOnceLinkage()) {
+ // FIXME: Unreachable with Rafael's changes?
+ llvm::Comdat *C = CGM.getModule().getOrInsertComdat(ParentFn->getName());
+ ParentFn->setComdat(C);
+ Fn->setComdat(C);
+ } else {
+ Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
+ }
+
+ StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,
+ FilterExpr->getLocStart(), FilterExpr->getLocStart());
+
+ EmitSEHExceptionCodeSave();
+
+ // Insert dummy allocas for every local variable in scope. We'll initialize
+ // them and prune the unused ones after we find out which ones were
+ // referenced.
+ for (const auto &DeclPtrs : ParentCGF.LocalDeclMap) {
+ const Decl *VD = DeclPtrs.first;
+ llvm::Value *Ptr = DeclPtrs.second;
+ auto *ValTy = cast<llvm::PointerType>(Ptr->getType())->getElementType();
+ LocalDeclMap[VD] = CreateTempAlloca(ValTy, Ptr->getName() + ".filt");
+ }
+
+ // Emit the original filter expression, convert to i32, and return.
+ llvm::Value *R = EmitScalarExpr(FilterExpr);
+ R = Builder.CreateIntCast(R, CGM.IntTy,
+ FilterExpr->getType()->isSignedIntegerType());
+ Builder.CreateStore(R, ReturnValue);
+
+ FinishFunction(FilterExpr->getLocEnd());
+
+ for (const auto &DeclPtrs : ParentCGF.LocalDeclMap) {
+ const Decl *VD = DeclPtrs.first;
+ auto *Alloca = cast<llvm::AllocaInst>(LocalDeclMap[VD]);
+ if (Alloca->hasNUses(0)) {
+ Alloca->eraseFromParent();
+ continue;
+ }
+ ErrorUnsupported(FilterExpr,
+ "SEH filter expression local variable capture");
+ }
+
+ return Fn;
+}
+
+void CodeGenFunction::EmitSEHExceptionCodeSave() {
+ // Save the exception code in the exception slot to unify exception access in
+ // the filter function and the landing pad.
+ // struct EXCEPTION_POINTERS {
+ // EXCEPTION_RECORD *ExceptionRecord;
+ // CONTEXT *ContextRecord;
+ // };
+ // void *exn.slot =
+ // (void *)(uintptr_t)exception_pointers->ExceptionRecord->ExceptionCode;
+ llvm::Value *Ptrs = Builder.CreateLoad(GetAddrOfLocalVar(SEHPointersDecl));
+ llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo();
+ llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy, nullptr);
+ Ptrs = Builder.CreateBitCast(Ptrs, PtrsTy->getPointerTo());
+ llvm::Value *Rec = Builder.CreateStructGEP(Ptrs, 0);
+ Rec = Builder.CreateLoad(Rec);
+ llvm::Value *Code = Builder.CreateLoad(Rec);
+ Code = Builder.CreateZExt(Code, CGM.IntPtrTy);
+ // FIXME: Change landing pads to produce {i32, i32} and make the exception
+ // slot an i32.
+ Code = Builder.CreateIntToPtr(Code, CGM.VoidPtrTy);
+ Builder.CreateStore(Code, getExceptionSlot());
+}
+
+llvm::Value *CodeGenFunction::EmitSEHExceptionInfo() {
+ // Sema should diagnose calling this builtin outside of a filter context, but
+ // don't crash if we screw up.
+ if (!SEHPointersDecl)
+ return llvm::UndefValue::get(Int8PtrTy);
+ return Builder.CreateLoad(GetAddrOfLocalVar(SEHPointersDecl));
+}
+
+llvm::Value *CodeGenFunction::EmitSEHExceptionCode() {
+ // If we're in a landing pad or filter function, the exception slot contains
+ // the code.
+ assert(ExceptionSlot);
+ llvm::Value *Code =
+ Builder.CreatePtrToInt(getExceptionFromSlot(), CGM.IntPtrTy);
+ return Builder.CreateTrunc(Code, CGM.Int32Ty);
+}
+
+void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
+ if (SEHFinallyStmt *Finally = S.getFinallyHandler()) {
+ // Push a cleanup for __finally blocks.
+ EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup,
+ Finally->getBlock());
+ return;
+ }
+
+ // Otherwise, we must have an __except block.
+ SEHExceptStmt *Except = S.getExceptHandler();
+ assert(Except);
+ EHCatchScope *CatchScope = EHStack.pushCatch(1);
+ CodeGenFunction FilterCGF(CGM, /*suppressNewContext=*/true);
+ llvm::Function *FilterFunc =
+ FilterCGF.GenerateSEHFilterFunction(*this, *Except);
+ llvm::Constant *OpaqueFunc =
+ llvm::ConstantExpr::getBitCast(FilterFunc, Int8PtrTy);
+ CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except"));
+}
+
+void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
+ // Just pop the cleanup if it's a __finally block.
+ if (S.getFinallyHandler()) {
+ PopCleanupBlock();
+ return;
+ }
+
+ // Otherwise, we must have an __except block.
+ SEHExceptStmt *Except = S.getExceptHandler();
+ assert(Except && "__try must have __finally xor __except");
+ EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin());
+
+ // Don't emit the __except block if the __try block lacked invokes.
+ // TODO: Model unwind edges from instructions, either with iload / istore or
+ // a try body function.
+ if (!CatchScope.hasEHBranches()) {
+ CatchScope.clearHandlerBlocks();
+ EHStack.popCatch();
+ return;
+ }
+
+ // The fall-through block.
+ llvm::BasicBlock *ContBB = createBasicBlock("__try.cont");
+
+ // We just emitted the body of the __try; jump to the continue block.
+ if (HaveInsertPoint())
+ Builder.CreateBr(ContBB);
+
+ // Check if our filter function returned true.
+ emitCatchDispatchBlock(*this, CatchScope);
+
+ // Grab the block before we pop the handler.
+ llvm::BasicBlock *ExceptBB = CatchScope.getHandler(0).Block;
+ EHStack.popCatch();
+
+ EmitBlockAfterUses(ExceptBB);
+
+ // Emit the __except body.
+ EmitStmt(Except->getBlock());
+
+ Builder.CreateBr(ContBB);
+
+ EmitBlock(ContBB);
}
void CodeGenFunction::EmitSEHLeaveStmt(const SEHLeaveStmt &S) {
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 826171a46e2..d08e011ea3c 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -43,7 +43,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
BlockInfo(nullptr), BlockPointer(nullptr),
LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr),
NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr),
- ExceptionSlot(nullptr), EHSelectorSlot(nullptr),
+ ExceptionSlot(nullptr), EHSelectorSlot(nullptr), SEHPointersDecl(nullptr),
DebugInfo(CGM.getModuleDebugInfo()), DisableDebugInfo(false),
DidCallStackSave(false), IndirectBranch(nullptr), PGO(cgm),
SwitchInsn(nullptr), SwitchWeights(nullptr), CaseRangeBlock(nullptr),
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 8009e78d2ad..44e01c80df7 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -305,6 +305,10 @@ public:
/// write the current selector value into this alloca.
llvm::AllocaInst *EHSelectorSlot;
+ /// The implicit parameter to SEH filter functions of type
+ /// 'EXCEPTION_POINTERS*'.
+ ImplicitParamDecl *SEHPointersDecl;
+
/// Emits a landing pad for the current EH stack.
llvm::BasicBlock *EmitLandingPad();
@@ -1990,6 +1994,16 @@ public:
void EmitCXXTryStmt(const CXXTryStmt &S);
void EmitSEHTryStmt(const SEHTryStmt &S);
void EmitSEHLeaveStmt(const SEHLeaveStmt &S);
+ void EnterSEHTryStmt(const SEHTryStmt &S);
+ void ExitSEHTryStmt(const SEHTryStmt &S);
+
+ llvm::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
+ const SEHExceptStmt &Except);
+
+ void EmitSEHExceptionCodeSave();
+ llvm::Value *EmitSEHExceptionCode();
+ llvm::Value *EmitSEHExceptionInfo();
+
void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
ArrayRef<const Attr *> Attrs = None);
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 2a5f8406a50..c55dbea7d9e 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -466,14 +466,21 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
if (ExpectAndConsume(tok::l_paren))
return StmtError();
- ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope);
+ ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope |
+ Scope::SEHExceptScope);
if (getLangOpts().Borland) {
Ident__exception_info->setIsPoisoned(false);
Ident___exception_info->setIsPoisoned(false);
Ident_GetExceptionInfo->setIsPoisoned(false);
}
- ExprResult FilterExpr(ParseExpression());
+
+ ExprResult FilterExpr;
+ {
+ ParseScopeFlags FilterScope(this, getCurScope()->getFlags() |
+ Scope::SEHFilterScope);
+ FilterExpr = ParseExpression();
+ }
if (getLangOpts().Borland) {
Ident__exception_info->setIsPoisoned(true);
diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp
index fd75c02bb1e..9a9215174ba 100644
--- a/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/clang/lib/Sema/JumpDiagnostics.cpp
@@ -338,6 +338,10 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
return;
}
+ case Stmt::SEHTryStmtClass:
+ // FIXME: Implement jump diagnostics for bad SEH jumps.
+ break;
+
default:
break;
}
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index 6c797788238..eeb2e01781e 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -185,6 +185,9 @@ void Scope::dumpImpl(raw_ostream &OS) const {
} else if (Flags & SEHTryScope) {
OS << "SEHTryScope";
Flags &= ~SEHTryScope;
+ } else if (Flags & SEHExceptScope) {
+ OS << "SEHExceptScope";
+ Flags &= ~SEHExceptScope;
} else if (Flags & OpenMPDirectiveScope) {
OS << "OpenMPDirectiveScope";
Flags &= ~OpenMPDirectiveScope;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index a070944ddb9..c28325a790e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -202,6 +202,28 @@ static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) {
return false;
}
+static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall,
+ Scope::ScopeFlags NeededScopeFlags,
+ unsigned DiagID) {
+ // Scopes aren't available during instantiation. Fortunately, builtin
+ // functions cannot be template args so they cannot be formed through template
+ // instantiation. Therefore checking once during the parse is sufficient.
+ if (!SemaRef.ActiveTemplateInstantiations.empty())
+ return false;
+
+ Scope *S = SemaRef.getCurScope();
+ while (S && !S->isSEHExceptScope())
+ S = S->getParent();
+ if (!S || !(S->getFlags() & NeededScopeFlags)) {
+ auto *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+ SemaRef.Diag(TheCall->getExprLoc(), DiagID)
+ << DRE->getDecl()->getIdentifier();
+ return true;
+ }
+
+ return false;
+}
+
ExprResult
Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
CallExpr *TheCall) {
@@ -461,6 +483,22 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (SemaBuiltinCallWithStaticChain(*this, TheCall))
return ExprError();
break;
+
+ case Builtin::BI__exception_code:
+ case Builtin::BI_exception_code: {
+ if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHExceptScope,
+ diag::err_seh___except_block))
+ return ExprError();
+ break;
+ }
+ case Builtin::BI__exception_info:
+ case Builtin::BI_exception_info: {
+ if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHFilterScope,
+ diag::err_seh___except_filter))
+ return ExprError();
+ break;
+ }
+
}
// Since the target specific builtins for each arch overlap, only check those
OpenPOWER on IntegriCloud