Skip to content

Commit

Permalink
Implement catching C++ class pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
ibuclaw committed Jan 16, 2016
1 parent cfa9a44 commit 088ceae
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 60 deletions.
1 change: 1 addition & 0 deletions gcc/d/d-dmd-gcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ FuncDeclaration *search_toString(StructDeclaration *);

// Used in d-lang.cc
void initTraitsStringTable();
const char *cppTypeInfoMangle(Dsymbol *s);

// Used in d-codegen.cc
Expression *getTypeInfo(Type *type, Scope *sc);
Expand Down
24 changes: 19 additions & 5 deletions gcc/d/d-lang.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1562,18 +1562,32 @@ d_eh_personality()
}

static tree
d_build_eh_type_type (tree type)
d_build_eh_type_type(tree type)
{
Type *dtype = lang_dtype (type);
Symbol *sym;
Type *dtype = lang_dtype(type);

if (dtype)
dtype = dtype->toBasetype();

gcc_assert (dtype && dtype->ty == Tclass);
sym = ((TypeClass *) dtype)->sym->toSymbol();

return convert (ptr_type_node, build_address (sym->Stree));
ClassDeclaration *cd = ((TypeClass *) dtype)->sym;
tree decl;

// Let C++ do the RTTI generation, and just reference the symbol.
if (cd->cpp)
{
const char *ident = cppTypeInfoMangle(cd);
decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
get_identifier(ident), unknown_type_node);
DECL_EXTERNAL (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
TREE_READONLY (decl) = 1;
}
else
decl = cd->toSymbol()->Stree;

return convert(ptr_type_node, build_address(decl));
}

void
Expand Down
2 changes: 2 additions & 0 deletions gcc/d/d-target.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ int Target::realsize;
int Target::realpad;
int Target::realalignsize;
bool Target::reverseCppOverloads;
bool Target::cppExceptions;


void
Expand All @@ -54,6 +55,7 @@ Target::init()
realpad = TYPE_PRECISION(long_double_type_node) / BITS_PER_UNIT;
realalignsize = TYPE_ALIGN_UNIT(long_double_type_node);
reverseCppOverloads = false;
cppExceptions = true;

// Define what type to use for size_t, ptrdiff_t.
size_t wordsize = int_size_in_bytes(size_type_node);
Expand Down
14 changes: 14 additions & 0 deletions gcc/d/dfrontend/cppmangle.c
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,13 @@ class CppMangleVisitor : public Visitor
store(NULL);
store(t);
}

const char *mangle_typeinfo(Dsymbol *s)
{
buf.writestring("_ZTIP");
cpp_mangle_name(s, false);
return buf.extractString();
}
};

char *toCppMangle(Dsymbol *s)
Expand All @@ -901,6 +908,13 @@ char *toCppMangle(Dsymbol *s)
return v.mangleOf(s);
}

const char *cppTypeInfoMangle(Dsymbol *s)
{
//printf("cppTypeInfoMangle(%s)\n", s.toChars());
CppMangleVisitor v;
return v.mangle_typeinfo(s);
}

#elif TARGET_WINDOS

// Windows DMC and Microsoft Visual C++ mangling
Expand Down
71 changes: 47 additions & 24 deletions gcc/d/dfrontend/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -4436,8 +4436,9 @@ Statement *TryCatchStatement::semantic(Scope *sc)
for (size_t i = 0; i < catches->dim; i++)
{ Catch *c = (*catches)[i];
c->semantic(sc);
if (c->type->ty == Terror)
{ catchErrors = true;
if (c->errors)
{
catchErrors = true;
continue;
}

Expand Down Expand Up @@ -4500,6 +4501,7 @@ Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler)
this->type = t;
this->ident = id;
this->handler = handler;
this->errors = false;
var = NULL;
internalCatch = false;
}
Expand All @@ -4523,6 +4525,7 @@ void Catch::semantic(Scope *sc)
{
// If enclosing is scope(success) or scope(exit), this will be placed in finally block.
error(loc, "cannot put catch statement inside %s", Token::toChars(sc->os->tok));
errors = true;
}
if (sc->tf)
{
Expand All @@ -4533,6 +4536,7 @@ void Catch::semantic(Scope *sc)
* body into a nested function.
*/
error(loc, "cannot put catch statement inside finally block");
errors = true;
}
#endif

Expand All @@ -4549,33 +4553,52 @@ void Catch::semantic(Scope *sc)
type = tid;
}
type = type->semantic(loc, sc);
ClassDeclaration *cd = type->toBasetype()->isClassHandle();
if (!cd || ((cd != ClassDeclaration::throwable) && !ClassDeclaration::throwable->isBaseOf(cd, NULL)))
if (type == Type::terror)
errors = true;
else
{
if (type != Type::terror)
ClassDeclaration *cd = type->toBasetype()->isClassHandle();
if (!cd)
{
error(loc, "can only catch class objects, not '%s'", type->toChars());
errors = true;
}
else if (cd->isCPPclass())
{
if (!Target::cppExceptions)
{
error(loc, "catching C++ class objects not supported for this target");
errors = true;
}
if (sc->func && !sc->intypeof && !internalCatch && sc->func->setUnsafe())
{
error(loc, "cannot catch C++ class objects in @safe code");
errors = true;
}
}
else if (cd != ClassDeclaration::throwable && !ClassDeclaration::throwable->isBaseOf(cd, NULL))
{
error(loc, "can only catch class objects derived from Throwable, not '%s'", type->toChars());
type = Type::terror;
errors = true;
}
else if (sc->func && !sc->intypeof && !internalCatch &&
cd != ClassDeclaration::exception && !ClassDeclaration::exception->isBaseOf(cd, NULL) &&
sc->func->setUnsafe())
{
error(loc, "can only catch class objects derived from Exception in @safe code, not '%s'", type->toChars());
errors = true;
}
}
else if (sc->func &&
!sc->intypeof &&
!internalCatch &&
cd != ClassDeclaration::exception &&
!ClassDeclaration::exception->isBaseOf(cd, NULL) &&
sc->func->setUnsafe())
{
error(loc, "can only catch class objects derived from Exception in @safe code, not '%s'", type->toChars());
type = Type::terror;
}
else if (ident)
{
var = new VarDeclaration(loc, type, ident, NULL);
var->semantic(sc);
sc->insert(var);
}
handler = handler->semantic(sc);

if (ident)
{
var = new VarDeclaration(loc, type, ident, NULL);
var->semantic(sc);
sc->insert(var);
}
handler = handler->semantic(sc);
if (handler && handler->isErrorStatement())
errors = true;
}
sc->pop();
}

Expand Down
2 changes: 2 additions & 0 deletions gcc/d/dfrontend/statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,8 @@ class Catch : public RootObject
Identifier *ident;
VarDeclaration *var;
Statement *handler;
bool errors; // set if semantic processing errors

// was generated by the compiler,
// wasn't present in source code
bool internalCatch;
Expand Down
1 change: 1 addition & 0 deletions gcc/d/dfrontend/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct Target
static int realpad; // 'padding' added to the CPU real size to bring it up to realsize
static int realalignsize; // alignment for reals
static bool reverseCppOverloads; // with dmc, overloaded functions are grouped and in reverse order
static bool cppExceptions; // set if catching C++ exceptions is supported
static int c_longsize; // size of a C 'long' or 'unsigned long' type
static int c_long_doublesize; // size of a C 'long double'

Expand Down
4 changes: 4 additions & 0 deletions gcc/d/runtime.def
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ DEF_D_RUNTIME(SWITCH_ERROR, "_d_switch_error", P2(STRING, UINT), VOID, ECF_NORET
// override, but instead conflicts with another method found in a base class.
DEF_D_RUNTIME(HIDDEN_FUNC, "_d_hidden_func", P1(VOIDPTR), VOID, ECF_NORETURN)

// C++ Exception Handlers.
DEF_D_RUNTIME(CXA_BEGIN_CATCH, "__cxa_begin_catch", P1(VOIDPTR), VOIDPTR, ECF_NOTHROW)
DEF_D_RUNTIME(CXA_END_CATCH, "__cxa_end_catch", P0(), VOID, ECF_NONE)

// Remove helper macros
#undef CONST
#undef ARRAY
Expand Down
29 changes: 23 additions & 6 deletions gcc/d/toir.cc
Original file line number Diff line number Diff line change
Expand Up @@ -784,13 +784,21 @@ class IRVisitor : public Visitor
set_input_location(vcatch->loc);
this->start_scope(level_catch);

tree ehptr = d_build_call_nary(builtin_decl_explicit(BUILT_IN_EH_POINTER),
1, integer_zero_node);
tree catchtype = build_ctype(vcatch->type);
tree object = NULL_TREE;

// Get D's internal exception Object, different from the generic
// Retrieve the internal exception object, which could be for a
// D or C++ catch handler. This is different from the generic
// exception pointer returned from gcc runtime.
tree ehptr = d_build_call_nary(builtin_decl_explicit(BUILT_IN_EH_POINTER),
1, integer_zero_node);
tree object = build_libcall(LIBCALL_BEGIN_CATCH, 1, &ehptr);
Type *tcatch = vcatch->type->toBasetype();
ClassDeclaration *cd = tcatch->isClassHandle();
if (cd->cpp)
object = build_libcall(LIBCALL_CXA_BEGIN_CATCH, 1, &ehptr);
else
object = build_libcall(LIBCALL_BEGIN_CATCH, 1, &ehptr);

if (vcatch->var)
{
object = build_nop(build_ctype(vcatch->type), object);
Expand All @@ -803,15 +811,24 @@ class IRVisitor : public Visitor
}
else
{
// Still need to emit a call to __gdc_begin_catch() to remove
// the object from the uncaught exceptions list.
// Still need to emit a call to __gdc_begin_catch() to
// remove the object from the uncaught exceptions list.
add_stmt(object);
}

if (vcatch->handler)
vcatch->handler->accept(this);

tree catchbody = this->end_scope();

// Need to wrap C++ handlers in a try/finally block to signal
// the end catch callback.
if (cd->cpp)
{
tree endcatch = build_libcall(LIBCALL_CXA_END_CATCH, 0, NULL);
catchbody = build2(TRY_FINALLY_EXPR, void_type_node,
catchbody, endcatch);
}
add_stmt(build2(CATCH_EXPR, void_type_node, catchtype, catchbody));
}
}
Expand Down

0 comments on commit 088ceae

Please sign in to comment.