- Rewrite without frontend outlining
http://reviews.llvm.org/D5607
Files:
include/clang/AST/Mangle.h
include/clang/Basic/Builtins.def
include/clang/Basic/DiagnosticCommonKinds.td
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Sema/Scope.h
lib/AST/ItaniumMangle.cpp
lib/AST/MicrosoftMangle.cpp
lib/CodeGen/CGBuiltin.cpp
lib/CodeGen/CGException.cpp
lib/CodeGen/CodeGenFunction.h
lib/Parse/ParseStmt.cpp
lib/Sema/JumpDiagnostics.cpp
lib/Sema/Scope.cpp
lib/Sema/SemaChecking.cpp
test/CodeGen/exceptions-seh-leave.c
test/CodeGen/exceptions-seh.c
test/OpenMP/parallel_codegen.cpp
test/Sema/__try.c
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/AST/Mangle.h
===================================================================
--- include/clang/AST/Mangle.h
+++ include/clang/AST/Mangle.h
@@ -132,6 +132,9 @@
virtual void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &) = 0;
+ virtual void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
+ raw_ostream &Out) = 0;
+
/// Generates a unique string for an externally visible type for use with TBAA
/// or type uniquing.
/// TODO: Extend this to internal types by generating names that are unique
Index: include/clang/Basic/Builtins.def
===================================================================
--- include/clang/Basic/Builtins.def
+++ include/clang/Basic/Builtins.def
@@ -692,11 +692,15 @@
BUILTIN(__builtin_rindex, "c*cC*i", "Fn")
// Microsoft builtins. These are only active with -fms-extensions.
-LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
+LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_exception_code, "ULi", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__exception_code, "ULi", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_exception_info, "v*", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__exception_info, "v*", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedCompareExchange, "LiLiD*LiLi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
Index: include/clang/Basic/DiagnosticCommonKinds.td
===================================================================
--- include/clang/Basic/DiagnosticCommonKinds.td
+++ include/clang/Basic/DiagnosticCommonKinds.td
@@ -112,6 +112,16 @@
"interpreting as unsigned">,
InGroup<DiagGroup<"implicitly-unsigned-literal">>;
+// SEH
+def err_seh_expected_handler : Error<
+ "expected '__except' or '__finally' block">;
+def err_seh___except_block : Error<
+ "%0 only allowed in __except block or filter expression">;
+def err_seh___except_filter : Error<
+ "%0 only allowed in __except filter expression">;
+def err_seh___finally_block : Error<
+ "%0 only allowed in __finally block">;
+
// Sema && AST
def note_invalid_subexpr_in_const_expr : Note<
"subexpression not valid in a constant expression">;
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -947,18 +947,6 @@
def warn_pragma_unknown_extension : Warning<
"unknown OpenCL extension %0 - ignoring">, InGroup<IgnoredPragmas>;
-def err_seh_expected_handler : Error<
- "expected '__except' or '__finally' block">;
-
-def err_seh___except_block : Error<
- "%0 only allowed in __except block">;
-
-def err_seh___except_filter : Error<
- "%0 only allowed in __except filter expression">;
-
-def err_seh___finally_block : Error<
- "%0 only allowed in __finally block">;
-
// OpenMP support.
def warn_pragma_omp_ignored : Warning<
"unexpected '#pragma omp ...' in program">, InGroup<SourceUsesOpenMP>, DefaultIgnore;
Index: include/clang/Sema/Scope.h
===================================================================
--- include/clang/Sema/Scope.h
+++ include/clang/Sema/Scope.h
@@ -115,8 +115,14 @@
/// This scope corresponds to an enum.
EnumScope = 0x40000,
- /// This scope corresponds to a SEH try.
+ /// This scope corresponds to an SEH try.
SEHTryScope = 0x80000,
+
+ /// This scope corresponds to an SEH except.
+ SEHExceptScope = 0x100000,
+
+ /// We are currently in the filter expression of an SEH except block.
+ SEHFilterScope = 0x200000,
};
private:
/// The parent scope for this scope. This is null for the translation-unit
@@ -407,6 +413,9 @@
/// \brief Determine whether this scope is a SEH '__try' block.
bool isSEHTryScope() const { return getFlags() & Scope::SEHTryScope; }
+ /// \brief Determine whether this scope is a SEH '__except' block.
+ bool isSEHExceptScope() const { return getFlags() & Scope::SEHExceptScope; }
+
/// containedInPrototypeScope - Return true if this or a parent scope
/// is a FunctionPrototypeScope.
bool containedInPrototypeScope() const;
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -156,6 +156,8 @@
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &Out) override;
+ void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
+ raw_ostream &Out) override;
void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override;
void mangleItaniumThreadLocalWrapper(const VarDecl *D,
raw_ostream &) override;
@@ -3845,6 +3847,16 @@
Mangler.getStream() << D->getName();
}
+void ItaniumMangleContextImpl::mangleSEHFilterExpression(
+ const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "__filt_";
+ if (shouldMangleDeclName(EnclosingDecl))
+ Mangler.mangle(EnclosingDecl);
+ else
+ Mangler.getStream() << EnclosingDecl->getName();
+}
+
void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D,
raw_ostream &Out) {
// <special-name> ::= TH <object name>
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -89,6 +89,7 @@
llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
+ llvm::DenseMap<const NamedDecl *, unsigned> SEHFilterIds;
public:
MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
@@ -134,6 +135,8 @@
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &Out) override;
+ void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
+ raw_ostream &Out) override;
void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
// Lambda closure types are already numbered.
@@ -2318,6 +2321,17 @@
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.
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -1650,6 +1650,13 @@
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
Index: lib/CodeGen/CGException.cpp
===================================================================
--- lib/CodeGen/CGException.cpp
+++ 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 @@
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 @@
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 @@
EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", nullptr };
const EHPersonality
EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", nullptr };
+const EHPersonality
+EHPersonality::MSVC_except_handler = { "_except_handler4", nullptr };
+const EHPersonality
+EHPersonality::MSVC_C_specific_handler = { "__C_specific_handler", nullptr };
/// 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 @@
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)
@@ -395,6 +431,13 @@
CGF.DeactivateCleanupBlock(cleanup, cast<llvm::Instruction>(typedAddr));
}
+/// Returns true if this landing pad is using filter functions to select catches
+/// instead of RTTI.
+static bool EHUsesFilterFunctions(CodeGenModule &CGM) {
+ const EHPersonality &P = EHPersonality::get(CGM);
+ return StringRef("__C_specific_handler") == P.PersonalityFn;
+}
+
llvm::Value *CodeGenFunction::getExceptionSlot() {
if (!ExceptionSlot)
ExceptionSlot = CreateTempAlloca(Int8PtrTy, "exn.slot");
@@ -1642,7 +1685,152 @@
}
void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
- CGM.ErrorUnsupported(&S, "SEH __try");
+ EnterSEHTryStmt(S);
+ EmitStmt(S.getTryBlock());
+ ExitSEHTryStmt(S);
+}
+
+namespace {
+struct PerformSEHFinally : EHScopeStack::Cleanup {
+ Stmt *Block;
+ PerformSEHFinally(Stmt *Block) : Block(Block) {}
+ void Emit(CodeGenFunction &CGF, Flags F) override { CGF.EmitStmt(Block); }
+};
+}
+
+llvm::Constant *
+CodeGenFunction::GenerateSEHFilterFunction() {
+ // Get the mangled function name.
+ SmallString<128> Name;
+ {
+ llvm::raw_svector_ostream OS(Name);
+ const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(CurCodeDecl);
+ 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 ArgTys[2] = { getContext().VoidPtrTy, getContext().VoidPtrTy };
+ FunctionProtoType::ExtProtoInfo EPI;
+ QualType FTP =
+ getContext().getFunctionType(getContext().IntTy, ArgTys, EPI);
+ CanQual<FunctionProtoType> CanFTP =
+ FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>();
+ const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionType(CanFTP);
+ llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
+ llvm::Function *Fn = llvm::Function::Create(FnTy, CurFn->getLinkage(),
+ Name.str(), &CGM.getModule());
+
+ // The filter is either in the same comdat as the function, or it's internal.
+ if (llvm::Comdat *C = CurFn->getComdat()) {
+ Fn->setComdat(C);
+ } else if (CurFn->hasWeakLinkage() || CurFn->hasLinkOnceLinkage()) {
+ llvm::Comdat *C = CGM.getModule().getOrInsertComdat(CurFn->getName());
+ CurFn->setComdat(C);
+ Fn->setComdat(C);
+ } else {
+ Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
+ }
+
+ // Insert an unreachable entry block.
+ llvm::BasicBlock *Entry = llvm::BasicBlock::Create(getLLVMContext(), "", Fn);
+ CGBuilderTy(Entry).CreateUnreachable();
+
+ return llvm::ConstantExpr::getBitCast(Fn, Int8PtrTy);
+}
+
+llvm::Value *CodeGenFunction::EmitSEHExceptionInfo() {
+ return getExceptionFromSlot();
+}
+
+llvm::Value *CodeGenFunction::EmitSEHExceptionCode() {
+ // FIXME: Implement outside of filter expressions.
+ //
+ // struct EXCEPTION_POINTERS {
+ // EXCEPTION_RECORD *ExceptionRecord;
+ // CONTEXT *ContextRecord;
+ // };
+ // ((EXCEPTION_POINTERS*)ehptr)->ExceptionRecord->ExceptionCode;
+ llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo();
+ llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy, nullptr);
+ llvm::Value *EHPtr =
+ Builder.CreateBitCast(getExceptionFromSlot(), PtrsTy->getPointerTo());
+ llvm::Value *Rec = Builder.CreateStructGEP(EHPtr, 0);
+ Rec = Builder.CreateLoad(Rec);
+ return Builder.CreateLoad(Rec);
+}
+
+void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
+ if (SEHExceptStmt *Except = S.getExceptHandler()) {
+ EHCatchScope *CatchScope = EHStack.pushCatch(1);
+ llvm::Constant *FilterFuncStub = GenerateSEHFilterFunction();
+ llvm::BasicBlock *ExceptBB = createBasicBlock("__except");
+ CatchScope->setHandler(0, FilterFuncStub, ExceptBB);
+ }
+
+ if (SEHFinallyStmt *Finally = S.getFinallyHandler()) {
+ // SEH cleanups should be simple.
+ EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup,
+ Finally->getBlock());
+ }
+}
+
+void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
+ if (SEHExceptStmt *Except = S.getExceptHandler()) {
+ EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin());
+
+ // Don't emit the __except block if the __try block lacked invokes.
+ // TODO: Model unwind edges from instructions, either with iload / istore or
+ // a try body function.
+ if (!CatchScope.hasEHBranches()) {
+ CatchScope.clearHandlerBlocks();
+ EHStack.popCatch();
+ return;
+ }
+
+ // The fall-through block.
+ llvm::BasicBlock *ContBB = createBasicBlock("__try.cont");
+
+ // We just emitted the body of the __try; jump to the continue block.
+ if (HaveInsertPoint())
+ Builder.CreateBr(ContBB);
+
+ // Check if our filter function returned true.
+ emitCatchDispatchBlock(*this, CatchScope);
+
+ // Grab the block before we pop the handler.
+ llvm::BasicBlock *ExceptBB = CatchScope.getHandler(0).Block;
+ EHStack.popCatch();
+
+ EmitBlockAfterUses(ExceptBB);
+
+ // Emit the filter expression, and pass the result to @llvm.eh.seh.filter().
+ llvm::Value *R = EmitScalarExpr(Except->getFilterExpr());
+ assert(R->getType() == Int32Ty && "filter expr isn't i32");
+ // FIXME: Use getIntrinsic when this is a real intrinsic.
+ llvm::Function *FilterIntrin = cast_or_null<llvm::Function>(
+ CGM.getModule().getNamedValue("llvm.eh.seh.filter"));
+ if (!FilterIntrin) {
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(VoidTy, Int32Ty, /*isVarArg=*/false);
+ FilterIntrin =
+ llvm::Function::Create(FnTy, llvm::GlobalValue::ExternalLinkage,
+ "llvm.eh.seh.filter", &CGM.getModule());
+ }
+ Builder.CreateCall(FilterIntrin, R);
+
+ // Emit the __except body.
+ EmitStmt(Except->getBlock());
+
+ Builder.CreateBr(ContBB);
+
+ EmitBlock(ContBB);
+ }
+
+ if (SEHFinallyStmt *Finally = S.getFinallyHandler()) {
+ PopCleanupBlock();
+ }
}
void CodeGenFunction::EmitSEHLeaveStmt(const SEHLeaveStmt &S) {
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -1988,6 +1988,14 @@
void EmitCXXTryStmt(const CXXTryStmt &S);
void EmitSEHTryStmt(const SEHTryStmt &S);
void EmitSEHLeaveStmt(const SEHLeaveStmt &S);
+ void EnterSEHTryStmt(const SEHTryStmt &S);
+ void ExitSEHTryStmt(const SEHTryStmt &S);
+
+ llvm::Constant *GenerateSEHFilterFunction();
+
+ llvm::Value *EmitSEHExceptionCode();
+ llvm::Value *EmitSEHExceptionInfo();
+
void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
ArrayRef<const Attr *> Attrs = None);
Index: lib/Parse/ParseStmt.cpp
===================================================================
--- lib/Parse/ParseStmt.cpp
+++ lib/Parse/ParseStmt.cpp
@@ -466,14 +466,21 @@
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);
Index: lib/Sema/JumpDiagnostics.cpp
===================================================================
--- lib/Sema/JumpDiagnostics.cpp
+++ lib/Sema/JumpDiagnostics.cpp
@@ -338,6 +338,10 @@
return;
}
+ case Stmt::SEHTryStmtClass:
+ // FIXME: Implement jump diagnostics for bad SEH jumps.
+ break;
+
default:
break;
}
Index: lib/Sema/Scope.cpp
===================================================================
--- lib/Sema/Scope.cpp
+++ lib/Sema/Scope.cpp
@@ -185,6 +185,9 @@
} else if (Flags & SEHTryScope) {
OS << "SEHTryScope";
Flags &= ~SEHTryScope;
+ } else if (Flags & SEHExceptScope) {
+ OS << "SEHExceptScope";
+ Flags &= ~SEHExceptScope;
} else if (Flags & OpenMPDirectiveScope) {
OS << "OpenMPDirectiveScope";
Flags &= ~OpenMPDirectiveScope;
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -461,6 +461,36 @@
if (SemaBuiltinCallWithStaticChain(*this, TheCall))
return ExprError();
break;
+
+ case Builtin::BI__exception_code:
+ case Builtin::BI_exception_code: {
+ Scope *S = getCurScope();
+ while (S && !S->isSEHExceptScope())
+ S = S->getParent();
+ if (!S || !S->isSEHExceptScope()) {
+ auto *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+ Diag(TheCall->getExprLoc(), diag::err_seh___except_block)
+ << DRE->getDecl()->getIdentifier();
+ return ExprError();
+ }
+ break;
+ }
+
+ case Builtin::BI__exception_info:
+ case Builtin::BI_exception_info: {
+ // FIXME: Diagnose if this is used in the __except block.
+ Scope *S = getCurScope();
+ while (S && !S->isSEHExceptScope())
+ S = S->getParent();
+ if (!S || !(S->getFlags() & Scope::SEHFilterScope)) {
+ auto *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+ Diag(TheCall->getExprLoc(), diag::err_seh___except_filter)
+ << DRE->getDecl()->getIdentifier();
+ return ExprError();
+ }
+ break;
+ }
+
}
// Since the target specific builtins for each arch overlap, only check those
Index: test/CodeGen/exceptions-seh-leave.c
===================================================================
--- test/CodeGen/exceptions-seh-leave.c
+++ test/CodeGen/exceptions-seh-leave.c
@@ -15,5 +15,5 @@
return 1;
}
// CHECK-NOT: error:
-// CHECK: error: cannot compile this SEH __try yet
+// CHECK: error: cannot compile this SEH __leave yet
// CHECK-NOT: error:
Index: test/CodeGen/exceptions-seh.c
===================================================================
--- test/CodeGen/exceptions-seh.c
+++ test/CodeGen/exceptions-seh.c
@@ -1,19 +1,131 @@
-// RUN: not %clang_cc1 -triple i686-pc-win32 -fexceptions -fms-extensions -emit-llvm -o - %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fexceptions -fms-extensions -emit-llvm -o - | FileCheck %s
-// This is a codegen test because we only emit the diagnostic when we start
-// generating code.
+// FIXME: Perform this outlining automatically CodeGen.
+void try_body(int numerator, int denominator, int *myres) {
+ *myres = numerator / denominator;
+}
+// CHECK-LABEL: define void @try_body(i32 %numerator, i32 %denominator, i32* %myres)
+// CHECK: sdiv i32
+// CHECK: store i32 %{{.*}}, i32*
+// CHECK: ret void
-int SaveDiv(int numerator, int denominator, int *res) {
+int safe_div(int numerator, int denominator, int *res) {
int myres = 0;
+ int success = 1;
__try {
- myres = numerator / denominator;
- __leave;
+ try_body(numerator, denominator, &myres);
} __except (1) {
- return 0;
+ success = -42;
}
*res = myres;
- return 1;
+ return success;
+}
+// CHECK-LABEL: define i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res)
+// CHECK: invoke void @try_body(i32 %{{.*}}, i32 %{{.*}}, i32* %{{.*}})
+// CHECK: to label %{{.*}} unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[lpad]]
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK: %[[sel:[^ ]*]] = load i32*
+// CHECK: %[[filt_id:[^ ]*]] = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@safe_div@@" to i8*))
+// CHECK: %[[matches:[^ ]*]] = icmp eq i32 %[[sel]], %[[filt_id]]
+// CHECK: br i1 %[[matches]], label %[[except_bb:[^ ]*]], label %{{.*}}
+//
+// CHECK: [[except_bb]]
+// CHECK: call void @llvm.eh.seh.filter(i32 1)
+// CHECK: store i32 -42, i32* %[[success:[^ ]*]]
+//
+// CHECK: %[[res:[^ ]*]] = load i32* %[[success]]
+// CHECK: ret i32 %[[res]]
+
+void j(void);
+
+int nested_try() {
+ int r = 42;
+ __try {
+ __try {
+ j();
+ r = 0;
+ } __except(_exception_code() == 123) {
+ r = 123;
+ }
+ } __except(_exception_code() == 456) {
+ r = 456;
+ }
+ return r;
+}
+// CHECK-LABEL: define i32 @nested_try()
+// CHECK: store i32 42, i32* %[[r:[^ ,]*]]
+// CHECK: invoke void @j()
+// CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[cont]]
+// CHECK: store i32 0, i32* %[[r]]
+// CHECK: br label %[[inner_try_cont:[^ ]*]]
+//
+// CHECK: [[lpad]]
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$1@0@nested_try@@" to i8*)
+// CHECK: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@nested_try@@" to i8*)
+// CHECK: store i8* %{{.*}}, i8** %[[ehptr_slot:[^ ]*]]
+// CHECK: store i32 %{{.*}}, i32* %[[sel_slot:[^ ]*]]
+//
+// CHECK: load i32* %[[sel_slot]]
+// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @"\01?filt$1@0@nested_try@@" to i8*))
+// CHECK: icmp eq i32
+// CHECK: br i1
+//
+// CHECK: load i32* %[[sel_slot]]
+// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@nested_try@@" to i8*))
+// CHECK: icmp eq i32
+// CHECK: br i1
+//
+// CHECK: load i8** %[[ehptr_slot]]
+// CHECK: call void @llvm.eh.seh.filter(i32 %{{.*}})
+// CHECK: store i32 456, i32* %[[r]]
+// CHECK: br label %[[outer_try_cont:[^ ]*]]
+//
+// CHECK: [[outer_try_cont]]
+// CHECK: %[[r_load:[^ ]*]] = load i32* %[[r]]
+// CHECK: ret i32 %[[r_load]]
+//
+// CHECK: load i8** %[[ehptr_slot]]
+// CHECK: call void @llvm.eh.seh.filter(i32 %{{.*}})
+// CHECK: store i32 123, i32* %[[r]]
+// CHECK: br label %[[inner_try_cont]]
+//
+// CHECK: [[inner_try_cont]]
+// CHECK: br label %[[outer_try_cont]]
+
+// FIXME: This lowering of __finally can't actually work, it will have to
+// change.
+static unsigned g = 0;
+void basic_finally() {
+ ++g;
+ __try {
+ j();
+ } __finally {
+ --g;
+ }
}
-// CHECK-NOT: error:
-// CHECK: error: cannot compile this SEH __try yet
-// CHECK-NOT: error:
+// CHECK-LABEL: define void @basic_finally()
+// CHECK: load i32* @g
+// CHECK: add i32 %{{.*}}, 1
+// CHECK: store i32 %{{.*}}, i32* @g
+//
+// CHECK: invoke void @j()
+// CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[cont]]
+// CHECK: load i32* @g
+// CHECK: add i32 %{{.*}}, -1
+// CHECK: store i32 %{{.*}}, i32* @g
+// CHECK: ret void
+//
+// CHECK: [[lpad]]
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK-NEXT: cleanup
+// CHECK: load i32* @g
+// CHECK: add i32 %{{.*}}, -1
+// CHECK: store i32 %{{.*}}, i32* @g
+// CHECK: resume
Index: test/OpenMP/parallel_codegen.cpp
===================================================================
--- test/OpenMP/parallel_codegen.cpp
+++ test/OpenMP/parallel_codegen.cpp
@@ -70,7 +70,7 @@
// CHECK-NEXT: [[ARGC:%.+]] = load i32* [[ARGC_REF]]
// CHECK-NEXT: invoke void [[FOO:@.+foo.+]](i32{{[ ]?[a-z]*}} [[ARGC]])
// CHECK: ret void
-// CHECK: call void @{{.+terminate.*}}(
+// CHECK: call void @{{.+terminate.*|abort}}(
// CHECK-NEXT: unreachable
// CHECK-NEXT: }
// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
@@ -82,7 +82,7 @@
// CHECK-DEBUG-NEXT: [[ARGC:%.+]] = load i32* [[ARGC_REF]]
// CHECK-DEBUG-NEXT: invoke void [[FOO:@.+foo.+]](i32 [[ARGC]])
// CHECK-DEBUG: ret void
-// CHECK-DEBUG: call void @{{.+terminate.*}}(
+// CHECK-DEBUG: call void @{{.+terminate.*|abort}}(
// CHECK-DEBUG-NEXT: unreachable
// CHECK-DEBUG-NEXT: }
@@ -123,7 +123,7 @@
// CHECK-NEXT: [[ARGC:%.+]] = load i8*** [[ARGC_REF]]
// CHECK-NEXT: invoke void [[FOO1:@.+foo.+]](i8** [[ARGC]])
// CHECK: ret void
-// CHECK: call void @{{.+terminate.*}}(
+// CHECK: call void @{{.+terminate.*|abort}}(
// CHECK-NEXT: unreachable
// CHECK-NEXT: }
// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
@@ -135,7 +135,7 @@
// CHECK-DEBUG-NEXT: [[ARGC:%.+]] = load i8*** [[ARGC_REF]]
// CHECK-DEBUG-NEXT: invoke void [[FOO1:@.+foo.+]](i8** [[ARGC]])
// CHECK-DEBUG: ret void
-// CHECK-DEBUG: call void @{{.+terminate.*}}(
+// CHECK-DEBUG: call void @{{.+terminate.*|abort}}(
// CHECK-DEBUG-NEXT: unreachable
// CHECK-DEBUG-NEXT: }
Index: test/Sema/__try.c
===================================================================
--- test/Sema/__try.c
+++ test/Sema/__try.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fborland-extensions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fborland-extensions -DBORLAND -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s
#define JOIN2(x,y) x ## y
#define JOIN(x,y) JOIN2(x,y)
@@ -10,8 +11,10 @@
struct EXCEPTION_INFO{};
-int __exception_code();
+unsigned long __exception_code();
+#ifdef BORLAND
struct EXCEPTION_INFO* __exception_info();
+#endif
void __abnormal_termination();
#define GetExceptionCode __exception_code
@@ -143,7 +146,11 @@
__except( function_scope ? 1 : -1 ) {}
}
+#ifdef BORLAND
void TEST() {
+ (void)__abnormal_termination(); // expected-error{{only allowed in __finally block}}
+ (void)AbnormalTermination(); // expected-error{{only allowed in __finally block}}
+
__try {
(void)AbnormalTermination; // expected-error{{only allowed in __finally block}}
(void)__abnormal_termination; // expected-error{{only allowed in __finally block}}
@@ -160,15 +167,27 @@
__abnormal_termination();
}
}
+#endif
void TEST() {
- (void)__exception_code; // expected-error{{only allowed in __except block}}
- (void)__exception_info; // expected-error{{only allowed in __except filter expression}}
- (void)__abnormal_termination; // expected-error{{only allowed in __finally block}}
-
- (void)GetExceptionCode(); // expected-error{{only allowed in __except block}}
+ (void)__exception_info(); // expected-error{{only allowed in __except filter expression}}
(void)GetExceptionInformation(); // expected-error{{only allowed in __except filter expression}}
- (void)AbnormalTermination(); // expected-error{{only allowed in __finally block}}
+}
+
+void TEST() {
+#ifndef BORLAND
+ (void)__exception_code; // expected-error{{builtin functions must be directly called}}
+#endif
+ (void)__exception_code(); // expected-error{{only allowed in __except block or filter expression}}
+ (void)GetExceptionCode(); // expected-error{{only allowed in __except block or filter expression}}
+}
+
+void TEST() {
+ __try {
+ } __except(1) {
+ GetExceptionCode(); // valid
+ GetExceptionInformation(); // expected-error{{only allowed in __except filter expression}}
+ }
}
void test_seh_leave_stmt() {
@@ -188,4 +207,3 @@
}
__leave; // expected-error{{'__leave' statement not in __try block}}
}
-
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits