Skip to content

Commit

Permalink
C++ EH: initial front end work
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Jan 12, 2016
1 parent a540e39 commit 5f0852b
Show file tree
Hide file tree
Showing 15 changed files with 290 additions and 22 deletions.
2 changes: 2 additions & 0 deletions src/aggregate.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ class ClassDeclaration : public AggregateDeclaration
static ClassDeclaration *throwable;
static ClassDeclaration *exception;
static ClassDeclaration *errorException;
static ClassDeclaration *cpp_type_info_ptr;

ClassDeclaration *baseClass; // NULL only if this is Object
FuncDeclaration *staticCtor;
Expand All @@ -276,6 +277,7 @@ class ClassDeclaration : public AggregateDeclaration
int inuse; // to prevent recursive attempts
Baseok baseok; // set the progress of base classes resolving
Objc_ClassDeclaration objc;
Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr

ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses, bool inObject = false);
Dsymbol *syntaxCopy(Dsymbol *s);
Expand Down
2 changes: 2 additions & 0 deletions src/backend/rtlsym.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ SYMBOL_SCPP(LOCAL_UNWIND2, FLfunc,FREGSAVED,"_local_unwind2", 0, tsclib) \
SYMBOL_Z(UNWIND_RESUME, FLfunc,FREGSAVED,"_Unwind_Resume", SFLexit, tsclib) \
SYMBOL_Z(PERSONALITY, FLfunc,FREGSAVED,"__dmd_personality_v0", 0, tsclib) \
SYMBOL_Z(BEGIN_CATCH, FLfunc,FREGSAVED,"__dmd_begin_catch", 0, tsclib) \
SYMBOL_Z(CXA_BEGIN_CATCH, FLfunc,FREGSAVED,"__cxa_begin_catch", 0, tsclib) \
SYMBOL_Z(CXA_END_CATCH, FLfunc,FREGSAVED,"__cxa_end_catch", 0, tsclib) \
\
SYMBOL_Z(TLS_INDEX, FLextern,0,"_tls_index",0,tsint) \
SYMBOL_Z(TLS_ARRAY, FLextern,0,"_tls_array",0,tspvoid) \
Expand Down
22 changes: 21 additions & 1 deletion src/cppmangle.d
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Compiler implementation of the $(LINK2 http://www.dlang.org, D programming language)
*
* Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
* Copyright: Copyright (c) 1999-2015 by Digital Mars, All Rights Reserved
* Authors: Walter Bright, http://www.digitalmars.com
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Source: $(DMDSRC cppmangle.d)
Expand Down Expand Up @@ -893,6 +893,13 @@ static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TAR
store(null);
store(t);
}

final const(char)* mangle_typeinfo(Dsymbol s)
{
buf.writestring("_ZTI");
source_name(s);
return buf.extractString();
}
}

extern (C++) char* toCppMangle(Dsymbol s)
Expand All @@ -901,6 +908,13 @@ static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TAR
scope CppMangleVisitor v = new CppMangleVisitor();
return v.mangleOf(s);
}

extern (C++) const(char)* cppTypeInfoMangle(Dsymbol s)
{
//printf("cppTypeInfoMangle(%s)\n", s.toChars());
scope CppMangleVisitor v = new CppMangleVisitor();
return v.mangle_typeinfo(s);
}
}
else static if (TARGET_WINDOS)
{
Expand Down Expand Up @@ -1910,6 +1924,12 @@ else static if (TARGET_WINDOS)
scope VisualCPPMangler v = new VisualCPPMangler(!global.params.mscoff);
return v.mangleOf(s);
}

extern (C++) const(char)* cppTypeInfoMangle(Dsymbol s)
{
//printf("cppTypeInfoMangle(%s)\n", s.toChars());
assert(0);
}
}
else
{
Expand Down
9 changes: 9 additions & 0 deletions src/dclass.d
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ public:
extern (C++) static __gshared ClassDeclaration throwable;
extern (C++) static __gshared ClassDeclaration exception;
extern (C++) static __gshared ClassDeclaration errorException;
extern (C++) static __gshared ClassDeclaration cpp_type_info_ptr; // Object.__cpp_type_info_ptr

ClassDeclaration baseClass; // NULL only if this is Object
FuncDeclaration staticCtor;
Expand Down Expand Up @@ -210,6 +211,8 @@ public:

Objc_ClassDeclaration objc;

Symbol* cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr

final extern (D) this(Loc loc, Identifier id, BaseClasses* baseclasses, bool inObject = false)
{
super(loc, id);
Expand Down Expand Up @@ -367,6 +370,12 @@ public:
error("%s", msg);
errorException = this;
}
if (id == Id.cpp_type_info_ptr)
{
if (!inObject)
error("%s", msg);
cpp_type_info_ptr = this;
}
}
baseok = BASEOKnone;
}
Expand Down
1 change: 1 addition & 0 deletions src/func.d
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ enum FUNCFLAGnogcInprocess = 8; // working on determining @nogc
enum FUNCFLAGreturnInprocess = 0x10; // working on inferring 'return' for parameters
enum FUNCFLAGinlineScanned = 0x20; // function has been scanned for inline possibilities


/***********************************************************
*/
extern (C++) class FuncDeclaration : Declaration
Expand Down
1 change: 1 addition & 0 deletions src/idgen.d
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ Msgtable[] msgtable =
{ "__c_long" },
{ "__c_ulong" },
{ "__c_long_double" },
{ "cpp_type_info_ptr", "__cpp_type_info_ptr" },

{ "TypeInfo" },
{ "TypeInfo_Class" },
Expand Down
44 changes: 41 additions & 3 deletions src/s2ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ elem *addressElem(elem *e, Type *t, bool alwaysCopy = false);
type *Type_toCtype(Type *t);
elem *toElemDtor(Expression *e, IRState *irs);
Symbol *toSymbol(Type *t);
Symbol *toSymbolCpp(ClassDeclaration *cd);
unsigned totym(Type *tx);
Symbol *toSymbol(Dsymbol *s);
RET retStyle(TypeFunction *tf);
Expand Down Expand Up @@ -1069,7 +1070,8 @@ class S2irVisitor : public Visitor
elem *e3 = el_bin(OPeq, TYvoid, el_var(tryblock->jcatchvar), el_una(OPind, TYnptr, e));
#else
// jcatchvar = __dmd_catch_begin(__exception_object);
elem *e = el_bin(OPcall, TYnptr, el_var(getRtlsym(RTLSYM_BEGIN_CATCH)), el_var(seo));
elem *ebegin = el_var(getRtlsym(RTLSYM_BEGIN_CATCH));
elem *e = el_bin(OPcall, TYnptr, ebegin, el_var(seo));
elem *e3 = el_bin(OPeq, TYvoid, el_var(tryblock->jcatchvar), e);
#endif

Expand Down Expand Up @@ -1100,7 +1102,26 @@ class S2irVisitor : public Visitor

assert(cs->type);

Symbol *catchtype = toSymbol(cs->type->toBasetype());
/* The catch type can be a C++ class or a D class.
* If a D class, insert a pointer to TypeInfo into the typesTable[].
* If a C++ class, insert a pointer to __cpp_type_info_ptr into the typesTable[].
*/
Type *tcatch = cs->type->toBasetype();
ClassDeclaration *cd = tcatch->isClassHandle();
bool isCPPclass = cd->isCPPclass();
Symbol *catchtype;
if (isCPPclass)
{
catchtype = toSymbolCpp(cd);
if (i == 0)
{
// rewrite ebegin to use __cxa_begin_catch
Symbol *s = getRtlsym(RTLSYM_CXA_BEGIN_CATCH);
ebegin->EV.sp.Vsym = s;
}
}
else
catchtype = toSymbol(tcatch);

/* Look for catchtype in typesTable[] using linear search,
* insert if not already there,
Expand Down Expand Up @@ -1148,7 +1169,24 @@ class S2irVisitor : public Visitor
ex = el_bin(OPeq, tym, ex, el_var(toSymbol(cs->var)));
block_appendexp(catchState.blx->curblock, ex);
}
Statement_toIR(cs->handler, &catchState);
if (isCPPclass)
{
/* C++ catches need to end with call to __cxa_end_catch().
* Create:
* try { handler } finally { __cxa_end_catch(); }
* Note that this is worst case code because it always sets up an exception handler.
* At some point should try to do better.
*/
FuncDeclaration *fdend = FuncDeclaration::genCfunc(NULL, Type::tvoid, "__cxa_end_catch");
Expression *ec = VarExp::create(Loc(), fdend);
Expression *e = CallExp::create(Loc(), ec);
e->type = Type::tvoid;
Statement *sf = ExpStatement::create(Loc(), e);
Statement *stf = TryFinallyStatement::create(Loc(), cs->handler, sf);
Statement_toIR(stf, &catchState);
}
else
Statement_toIR(cs->handler, &catchState);
}
blx->curblock->appendSucc(breakblock2);
if (i + 1 == numcases)
Expand Down
81 changes: 64 additions & 17 deletions src/statement.d
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module ddmd.statement;

import core.stdc.stdarg;
import core.stdc.stdio;

import ddmd.aggregate;
import ddmd.aliasthis;
import ddmd.arrayop;
Expand Down Expand Up @@ -5123,6 +5124,10 @@ public:

override Statement semantic(Scope* sc)
{
uint flags;
enum FLAGcpp = 1;
enum FLAGd = 2;

_body = _body.semanticScope(sc, null, null);
assert(_body);
/* Even if body is empty, still do semantic analysis on catches
Expand All @@ -5131,11 +5136,14 @@ public:
foreach (i, c; *catches)
{
c.semantic(sc);
if (c.type.ty == Terror)
if (c.errors)
{
catchErrors = true;
continue;
}
auto cd = c.type.toBasetype().isClassHandle();
flags |= cd.isCPPclass() ? FLAGcpp : FLAGd;

// Determine if current catch 'hides' any previous catches
foreach (j; 0 .. i)
{
Expand All @@ -5149,6 +5157,16 @@ public:
}
}
}

if (sc.func)
{
if (flags == (FLAGcpp | FLAGd))
{
error("cannot mix catching D and C++ exceptions in the same try-catch");
catchErrors = true;
}
}

if (catchErrors)
return new ErrorStatement();
if (_body.isErrorStatement())
Expand Down Expand Up @@ -5197,6 +5215,8 @@ public:
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 Expand Up @@ -5225,6 +5245,7 @@ public:
{
// 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 @@ -5235,6 +5256,7 @@ public:
* body into a nested function.
*/
error(loc, "cannot put catch statement inside finally block");
errors = true;
}
}
auto sym = new ScopeDsymbol();
Expand All @@ -5249,27 +5271,52 @@ public:
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)
auto 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;
}

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;
}
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);
sc.pop();
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/target.d
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct Target
extern (C++) static __gshared int realpad; // 'padding' added to the CPU real size to bring it up to realsize
extern (C++) static __gshared int realalignsize; // alignment for reals
extern (C++) static __gshared bool reverseCppOverloads; // with dmc and cl, overloaded functions are grouped and in reverse order
extern (C++) static __gshared bool cppExceptions; // set if catching C++ exceptions is supported
extern (C++) static __gshared int c_longsize; // size of a C 'long' or 'unsigned long' type
extern (C++) static __gshared int c_long_doublesize; // size of a C 'long double'
extern (C++) static __gshared int classinfosize; // size of 'ClassInfo'
Expand Down Expand Up @@ -82,6 +83,8 @@ struct Target
c_long_doublesize = realsize;
if (global.params.is64bit && global.params.isWindows)
c_long_doublesize = 8;

cppExceptions = global.params.dwarfeh || (global.params.is64bit && global.params.isLinux);
}

/******************************
Expand Down
1 change: 1 addition & 0 deletions src/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,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 and cl, 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'
static int classinfosize; // size of 'ClassInfo'
Expand Down

0 comments on commit 5f0852b

Please sign in to comment.