32 changes: 26 additions & 6 deletions gen/statements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
//
//===----------------------------------------------------------------------===//

#include "import.h"
#include "init.h"
#include "mars.h"
#include "module.h"
#include "mtype.h"
#include "port.h"
#include "gen/abi.h"
#include "gen/arrays.h"
#include "gen/cgforeign.h"
#include "gen/classes.h"
#include "gen/coverage.h"
#include "gen/dvalue.h"
Expand Down Expand Up @@ -718,7 +720,7 @@ class ToIRVisitor : public Visitor {

assert(stmt->catches);

typedef llvm::SmallVector<std::pair<ClassDeclaration*, llvm::BasicBlock*>, 6>
typedef llvm::SmallVector<std::pair<Type*, llvm::BasicBlock*>, 6> // CALYPSO
CatchBlocks;
CatchBlocks catchBlocks;
catchBlocks.reserve(stmt->catches->dim);
Expand All @@ -734,6 +736,11 @@ class ToIRVisitor : public Visitor {
irs->scope() = IRScope(catchBB);
irs->DBuilder.EmitBlockStart((*it)->loc);

if (auto lp = (*it)->langPlugin()) // CALYPSO
lp->codegen()->toBeginCatch(irs, *it);
else
{

llvm::Function* enterCatchFn =
LLVM_D_GetRuntimeFunction(Loc(), irs->module, "_d_eh_enter_catch");
irs->ir->CreateCall(enterCatchFn);
Expand Down Expand Up @@ -771,6 +778,7 @@ class ToIRVisitor : public Visitor {
DtoStore(exc, irLocal->value);
}
}
}

// emit handler, if there is one
// handler is zero for instance for 'catch { debug foo(); }'
Expand All @@ -779,25 +787,37 @@ class ToIRVisitor : public Visitor {
}

if (!irs->scopereturned()) {
// CALYPSO BUG FIXME: _cxa_end_catch won't be called if it already returned
if (auto lp = (*it)->langPlugin())
lp->codegen()->toEndCatch(irs, *it);
irs->ir->CreateBr(endbb);
}

irs->DBuilder.EmitBlockEnd();

catchBlocks.push_back(std::make_pair(
(*it)->type->toBasetype()->isClassHandle(), catchBB));
(*it)->type->toBasetype(), catchBB));
}

// Only after emitting all the catch bodies, register the catch scopes.
// This is so that (re)throwing inside a catch does not match later
// catches.
Catches::reverse_iterator c_it = stmt->catches->rbegin();
for (CatchBlocks::iterator it = catchBlocks.begin(),
end = catchBlocks.end();
it != end; ++it
it != end; ++it, ++c_it
) {
DtoResolveClass(it->first);
irs->func()->scopes->pushCatch(
getIrAggr(it->first)->getClassInfoSymbol(), it->second);
llvm::Constant *catchType;
if (auto lp = (*c_it)->langPlugin()) // CALYPSO
catchType = lp->codegen()->toCatchScopeType(irs, it->first);
else
{
ClassDeclaration *cd = it->first->isClassHandle();
DtoResolveClass(cd);
catchType = getIrAggr(cd)->getClassInfoSymbol();
}

irs->func()->scopes->pushCatch(catchType, it->second);
}

// Emit the try block.
Expand Down
8 changes: 4 additions & 4 deletions ir/irfunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,10 @@ void ScopeStack::popCleanups(CleanupCursor targetScope) {
}
}

void ScopeStack::pushCatch(llvm::Constant* classInfoPtr,
void ScopeStack::pushCatch(llvm::Constant* clausePtr,
llvm::BasicBlock* bodyBlock
) {
catchScopes.push_back({classInfoPtr, bodyBlock, currentCleanupScope()});
catchScopes.push_back({clausePtr, bodyBlock, currentCleanupScope()});
currentLandingPads().push_back(0);
}

Expand Down Expand Up @@ -368,7 +368,7 @@ llvm::BasicBlock* ScopeStack::emitLandingPad() {

// Add the ClassInfo reference to the landingpad instruction so it is
// emitted to the EH tables.
landingPad->addClause(it->classInfoPtr);
landingPad->addClause(it->clausePtr);

llvm::BasicBlock* mismatchBB = llvm::BasicBlock::Create(
irs->context(),
Expand All @@ -378,7 +378,7 @@ llvm::BasicBlock* ScopeStack::emitLandingPad() {

// "Call" llvm.eh.typeid.for, which gives us the eh selector value to compare with
llvm::Value* ehTypeId = irs->ir->CreateCall(GET_INTRINSIC_DECL(eh_typeid_for),
DtoBitCast(it->classInfoPtr, getVoidPtrType()));
DtoBitCast(it->clausePtr, getVoidPtrType()));

// Compare the selector value from the unwinder against the expected
// one and branch accordingly.
Expand Down
4 changes: 2 additions & 2 deletions ir/irfunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ class CleanupScope {
struct CatchScope {
/// The ClassInfo reference corresponding to the type to match the
/// exception object against.
llvm::Constant* classInfoPtr;
llvm::Constant* clausePtr;

/// The block to branch to if the exception type matches.
llvm::BasicBlock* bodyBlock;
Expand Down Expand Up @@ -221,7 +221,7 @@ class ScopeStack {
/// given ClassInfo constant and to branch to the given body block if it
/// matches. The registered catch blocks are maintained on a stack, with the
/// top-most (i.e. last pushed, innermost) taking precedence.
void pushCatch(llvm::Constant* classInfoPtr, llvm::BasicBlock* bodyBlock);
void pushCatch(llvm::Constant* clausePtr, llvm::BasicBlock* bodyBlock);

/// Unregisters the last registered catch block.
void popCatch();
Expand Down
2 changes: 1 addition & 1 deletion runtime/druntime
40 changes: 40 additions & 0 deletions tests/calypso/eh/std_exception.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* C++ catch basic example.
*
* Build with :
* $ clang++ std_exception_cpp.cpp
* $ ldc2 std_exception_cpp.o -L-lstdc++ std_exception.d
*/

modmap (C++) "<exception>";
modmap (C++) "std_exception_cpp.h";

import (C++) std.exception;
import (C++) ooops;
import std.stdio, std.conv, std.string;

extern(C++) void throwException();

void main()
{
try
{
writeln("Calling throwException");
throwException();
}
catch (Throwable t)
{
writeln("Nope, catched a Throwable");
}
catch (C++) (uint n)
{
writeln("Wrong catch, this is for C++ uint exceptions");
writeln("n == ", n);
}
catch (C++) (ooops *e)
{
writeln("Catching the C++ std::exception!");
writeln("e == ", e);
writeln("what() == ", e.what());
}
}
6 changes: 6 additions & 0 deletions tests/calypso/eh/std_exception_cpp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "std_exception_cpp.h"

void throwException()
{
throw new ooops;
}
5 changes: 5 additions & 0 deletions tests/calypso/eh/std_exception_cpp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include <exception>

struct ooops : std::exception {
const char* what() const _GLIBCXX_USE_NOEXCEPT { return "Ooops!"; }
};