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
54 changes: 54 additions & 0 deletions src/tocsym.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ Classsym *fake_classsym(Identifier *id);
type *Type_toCtype(Type *t);
dt_t **ClassReferenceExp_toInstanceDt(ClassReferenceExp *ce, dt_t **pdt);
dt_t **Expression_toDt(Expression *e, dt_t **pdt);
dt_t **cpp_type_info_ptr_toDt(ClassDeclaration *cd, dt_t **pdt);
Symbol *toInitializer(AggregateDeclaration *ad);
const char *cppTypeInfoMangle(Dsymbol *cd);

/*************************************
* Helper
Expand Down Expand Up @@ -726,3 +728,55 @@ Symbol* toSymbol(ClassReferenceExp *cre)
outdata(s);
return cre->value->sym;
}

/**************************************
* For C++ class cd, generate an instance of __cpp_type_info_ptr
* and populate it with a pointer to the C++ type info.
* Params:
* cd = C++ class
* Returns:
* symbol of instance of __cpp_type_info_ptr
*/
Symbol* toSymbolCpp(ClassDeclaration *cd)
{
assert(cd->isCPPclass());

/* For the symbol std::exception, the type info is _ZTISt9exception
*/
if (!cd->cpp_type_info_ptr_sym)
{
static Symbol *scpp;
if (!scpp)
scpp = fake_classsym(Id::cpp_type_info_ptr);
Symbol *s = toSymbolX(cd, "_cpp_type_info_ptr", SCcomdat, scpp->Stype, "");
s->Sfl = FLdata;
s->Sflags |= SFLnodebug;
cpp_type_info_ptr_toDt(cd, &s->Sdt);
slist_add(s);
outdata(s);
cd->cpp_type_info_ptr_sym = s;
}
return cd->cpp_type_info_ptr_sym;
}

/**********************************
* Generate Symbol of C++ type info for C++ class cd.
* Params:
* cd = C++ class
* Returns:
* Symbol of cd's rtti type info
*/
Symbol *toSymbolCppTypeInfo(ClassDeclaration *cd)
{
const char *id = cppTypeInfoMangle(cd);
Symbol* s = symbol_calloc(id);
s->Sclass = SCextern;
s->Sfl = FLextern; // C++ code will provide the definition
s->Sflags |= SFLnodebug;
TYPE *t = type_fake(TYnptr);
t->Tcount++;
s->Stype = t;
slist_add(s);
return s;
}

26 changes: 26 additions & 0 deletions src/todt.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ void genTypeInfo(Type *t, Scope *sc);
Symbol *toInitializer(AggregateDeclaration *ad);
Symbol *toInitializer(EnumDeclaration *ed);
FuncDeclaration *search_toString(StructDeclaration *sd);
Symbol *toSymbolCppTypeInfo(ClassDeclaration *cd);

/* ================================================================ */

Expand Down Expand Up @@ -610,6 +611,31 @@ dt_t **StructDeclaration_toDt(StructDeclaration *sd, dt_t **pdt)
return pdt;
}

/******************************
* Generate data for instance of __cpp_type_info_ptr that refers
* to the C++ RTTI symbol for cd.
* Params:
* cd = C++ class
*/
dt_t **cpp_type_info_ptr_toDt(ClassDeclaration *cd, dt_t **pdt)
{
//printf("cpp_type_info_ptr_toDt(this = '%s')\n", cd->toChars());
assert(cd->isCPPclass());

// Put in first two members, the vtbl[] and the monitor
pdt = dtxoff(pdt, toVtblSymbol(ClassDeclaration::cpp_type_info_ptr), 0);
pdt = dtsize_t(pdt, 0); // monitor

// Create symbol for C++ type info
Symbol *s = toSymbolCppTypeInfo(cd);

// Put in address of cd's C++ type info
pdt = dtxoff(pdt, s, 0);

//printf("-cpp_type_info_ptr_toDt(this = '%s')\n", cd.toChars());
return pdt;
}

/****************************************************
* Put out initializers of ad->fields[].
* Although this is consistent with the elements[] version, we
Expand Down
28 changes: 28 additions & 0 deletions test/fail_compilation/cppeh1.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// REQUIRED_ARGS: -dwarfeh
/*
TEST_OUTPUT:
---
fail_compilation/cppeh1.d(24): Error: cannot catch C++ class objects in @safe code
---
*/

extern (C++, std)
{
class exception { }
}

@safe:
void bar();
void abc();

void foo()
{
try
{
bar();
}
catch (std.exception e)
{
abc();
}
}
31 changes: 31 additions & 0 deletions test/fail_compilation/cppeh2.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// REQUIRED_ARGS: -dwarfeh
/*
TEST_OUTPUT:
---
fail_compilation/cppeh2.d(19): Error: cannot mix catching D and C++ exceptions in the same try-catch
---
*/

extern (C++, std)
{
class exception { }
}

void bar();
void abc();

void foo()
{
try
{
bar();
}
catch (std.exception e)
{
abc();
}
catch (Exception e)
{
abc();
}
}
2 changes: 1 addition & 1 deletion test/fail_compilation/ice10382.d
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/ice10382.d(14): Error: can only catch class objects derived from Throwable, not 'int'
fail_compilation/ice10382.d(14): Error: can only catch class objects, not 'int'
---
*/

Expand Down
220 changes: 159 additions & 61 deletions test/runnable/cppa.d
Original file line number Diff line number Diff line change
Expand Up @@ -435,69 +435,71 @@ version (linux)
{
extern(C++, __gnu_cxx)
{
struct new_allocator(T)
{
alias size_type = size_t;
static if (is(T : char))
void deallocate(T*, size_type) { }
else
void deallocate(T*, size_type);
}
struct new_allocator(T)
{
alias size_type = size_t;
static if (is(T : char))
void deallocate(T*, size_type) { }
else
void deallocate(T*, size_type);
}
}
}

extern (C++, std)
{
struct allocator(T)
{
version (linux)
{
alias size_type = size_t;
void deallocate(T* p, size_type sz)
{ (cast(__gnu_cxx.new_allocator!T*)&this).deallocate(p, sz); }
}
version (linux)
{
alias size_type = size_t;
void deallocate(T* p, size_type sz)
{ (cast(__gnu_cxx.new_allocator!T*)&this).deallocate(p, sz); }
}
}

version (linux)
{
class vector(T, A = allocator!T)
{
final void push_back(ref const T);
}

struct char_traits(T)
{
}

// https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
version (none)
{
extern (C++, __cxx11)
{
struct basic_string(T, C = char_traits!T, A = allocator!T)
{
}
}
}
else
{
struct basic_string(T, C = char_traits!T, A = allocator!T)
{
}
}

struct basic_istream(T, C = char_traits!T)
{
}

struct basic_ostream(T, C = char_traits!T)
{
}

struct basic_iostream(T, C = char_traits!T)
{
}
class vector(T, A = allocator!T)
{
final void push_back(ref const T);
}

struct char_traits(T)
{
}

// https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
version (none)
{
extern (C++, __cxx11)
{
struct basic_string(T, C = char_traits!T, A = allocator!T)
{
}
}
}
else
{
struct basic_string(T, C = char_traits!T, A = allocator!T)
{
}
}

struct basic_istream(T, C = char_traits!T)
{
}

struct basic_ostream(T, C = char_traits!T)
{
}

struct basic_iostream(T, C = char_traits!T)
{
}
}

class exception { }
}

extern (C++)
Expand All @@ -511,7 +513,7 @@ extern (C++)
void foo14d(std.basic_ostream!(char) *p);
void foo14e(std.basic_iostream!(char) *p);

void foo14f(std.char_traits!char* x, std.basic_string!char* p, std.basic_string!char* q);
void foo14f(std.char_traits!char* x, std.basic_string!char* p, std.basic_string!char* q);
}
}

Expand All @@ -522,12 +524,12 @@ void test14()
std.vector!int p;
foo14(p);

foo14a(null);
foo14b(null);
foo14c(null);
foo14d(null);
foo14e(null);
foo14f(null, null, null);
foo14a(null);
foo14b(null);
foo14c(null);
foo14d(null);
foo14e(null);
foo14f(null, null, null);
}
}

Expand Down Expand Up @@ -599,9 +601,9 @@ version (CRuntime_Microsoft)
{
struct __c_long_double
{
this(double d) { ld = d; }
double ld;
alias ld this;
this(double d) { ld = d; }
double ld;
alias ld this;
}

alias __c_long_double myld;
Expand Down Expand Up @@ -889,6 +891,99 @@ void fuzz()

/****************************************/

extern (C++)
{
void throwit();
}

void testeh()
{
printf("testeh()\n");
version (linux)
{
version (X86_64)
{
bool caught;
try
{
throwit();
}
catch (std.exception e)
{
caught = true;
}
assert(caught);
}
}
}

/****************************************/

version (linux)
{
version (X86_64)
{
bool raii_works = false;
struct RAIITest
{
~this()
{
raii_works = true;
}
}

void dFunction()
{
RAIITest rt;
throwit();
}

void testeh2()
{
printf("testeh2()\n");
try
{
dFunction();
}
catch(std.exception e)
{
assert(raii_works);
}
}
}
else
void testeh2() { }
}
else
void testeh2() { }

/****************************************/

extern (C++) { void throwle(); void throwpe(); }

void testeh3()
{
printf("testeh3()\n");
version (linux)
{
version (X86_64)
{
bool caught = false;
try
{
throwle();
}
catch (std.exception e) //polymorphism test.
{
caught = true;
}
assert(caught);
}
}
}

/****************************************/

void main()
{
test1();
Expand Down Expand Up @@ -920,6 +1015,9 @@ void main()
test14200();
testVtable();
fuzz();
testeh();
testeh2();
testeh3();

printf("Success\n");
}
28 changes: 28 additions & 0 deletions test/runnable/extra-files/cppb.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

#include <stdio.h>
#include <assert.h>
#include <exception>

/**************************************/

Expand Down Expand Up @@ -551,3 +552,30 @@ void fuzz3_cppvararg(wchar arg10, wchar arg11, bool arg12)
{
fuzz3_checkValues(arg10, arg11, arg12);
}

/******************************************/

void throwit()
{
#if _WIN32
#else
std::exception se;
throw se;
#endif
}

/******************************************/

#if linux
#include <stdexcept>

void throwle()
{
std::logic_error le("test");
throw le;
}

#endif

/******************************************/