Skip to content

Commit

Permalink
fix issue 15589 - cleanup after PR #8277
Browse files Browse the repository at this point in the history
fix mangling, add shim functions for vtbl and type info, fix dtor inside Attribdeclaration, use Id-pool
  • Loading branch information
rainers committed Jun 13, 2018
1 parent 3a79629 commit ab0a7bf
Show file tree
Hide file tree
Showing 17 changed files with 370 additions and 61 deletions.
6 changes: 4 additions & 2 deletions src/dmd/aggregate.d
Expand Up @@ -110,8 +110,10 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
Dsymbol aliasthis; // forward unresolved lookups to aliasthis
bool noDefaultCtor; // no default construction

FuncDeclarations dtors; // Array of destructors
FuncDeclaration dtor; // aggregate destructor
DtorDeclarations dtors; // Array of destructors
DtorDeclaration dtor; // aggregate destructor
DtorDeclaration primaryDtor; // non-deleting C++ destructor, same as dtor for D
DtorDeclaration tidtor; // aggregate destructor used in TypeInfo (must have extern(D) ABI)

Expression getRTInfo; // pointer to GC info generated by object.RTInfo(this)

Expand Down
8 changes: 5 additions & 3 deletions src/dmd/aggregate.h
Expand Up @@ -72,7 +72,7 @@ FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc);
FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc);
FuncDeclaration *buildXtoHash(StructDeclaration *ad, Scope *sc);
FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc);
FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc);
DtorDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc);
FuncDeclaration *buildInv(AggregateDeclaration *ad, Scope *sc);

enum ClassKind
Expand Down Expand Up @@ -124,8 +124,10 @@ class AggregateDeclaration : public ScopeDsymbol
Dsymbol *aliasthis; // forward unresolved lookups to aliasthis
bool noDefaultCtor; // no default construction

FuncDeclarations dtors; // Array of destructors
FuncDeclaration *dtor; // aggregate destructor
DtorDeclarations dtors; // Array of destructors
DtorDeclaration *dtor; // aggregate destructor
DtorDeclaration *primaryDtor; // non-deleting C++ destructor, same as dtor for D
DtorDeclaration *tidtor; // aggregate destructor used in TypeInfo (must have extern(D) ABI)

Expression *getRTInfo; // pointer to GC info generated by object.RTInfo(this)

Expand Down
1 change: 1 addition & 0 deletions src/dmd/arraytypes.d
Expand Up @@ -35,6 +35,7 @@ alias BaseClasses = Array!(BaseClass*);
alias ClassDeclarations = Array!(ClassDeclaration);
alias Dsymbols = Array!(Dsymbol);
alias Objects = Array!(RootObject);
alias DtorDeclarations = Array!(DtorDeclaration);
alias FuncDeclarations = Array!(FuncDeclaration);
alias Parameters = Array!(Parameter);
alias Initializers = Array!(Initializer);
Expand Down
2 changes: 2 additions & 0 deletions src/dmd/arraytypes.h
Expand Up @@ -32,6 +32,8 @@ typedef Array<class Dsymbol *> Dsymbols;

typedef Array<class RootObject *> Objects;

typedef Array<class DtorDeclaration *> DtorDeclarations;

typedef Array<class FuncDeclaration *> FuncDeclarations;

typedef Array<class Parameter *> Parameters;
Expand Down
118 changes: 113 additions & 5 deletions src/dmd/clone.d
Expand Up @@ -33,6 +33,7 @@ import dmd.mtype;
import dmd.opover;
import dmd.semantic2;
import dmd.statement;
import dmd.target;
import dmd.typesem;
import dmd.tokens;

Expand Down Expand Up @@ -801,7 +802,7 @@ extern (C++) FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
* Close similarity with StructDeclaration::buildPostBlit(),
* and the ordering changes (runs backward instead of forwards).
*/
extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
extern (C++) DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
{
//printf("AggregateDeclaration::buildDtor() %s\n", ad.toChars());
if (ad.isUnionDeclaration())
Expand Down Expand Up @@ -887,12 +888,12 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
/* extern(C++) destructors call into super to destruct the full hierarchy
*/
ClassDeclaration cldec = ad.isClassDeclaration();
if (cldec && cldec.classKind == ClassKind.cpp && cldec.baseClass && cldec.baseClass.dtor)
if (cldec && cldec.classKind == ClassKind.cpp && cldec.baseClass && cldec.baseClass.primaryDtor)
{
// WAIT BUT: do I need to run `cldec.baseClass.dtor` semantic? would it have been run before?
cldec.baseClass.dtor.functionSemantic();

stc = mergeFuncAttrs(stc, cldec.baseClass.dtor);
stc = mergeFuncAttrs(stc, cldec.baseClass.primaryDtor);
if (!(stc & STC.disable))
{
// super.__xdtor()
Expand All @@ -905,7 +906,7 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
if (stc & STC.safe)
stc = (stc & ~STC.safe) | STC.trusted;

ex = new DotVarExp(loc, ex, cldec.baseClass.dtor, false);
ex = new DotVarExp(loc, ex, cldec.baseClass.primaryDtor, false);
ex = new CallExp(loc, ex);

e = Expression.combine(e, ex); // super dtor last
Expand All @@ -927,7 +928,7 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
}
}

FuncDeclaration xdtor = null;
DtorDeclaration xdtor = null;
switch (ad.dtors.dim)
{
case 0:
Expand Down Expand Up @@ -966,6 +967,11 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
break;
}

ad.primaryDtor = xdtor;

if (xdtor && xdtor.linkage == LINK.cpp && !Target.twoDtorInVtable)
xdtor = buildWindowsCppDtor(ad, xdtor, sc);

// Add an __xdtor alias to make the inclusive dtor accessible
if (xdtor)
{
Expand All @@ -978,6 +984,108 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
return xdtor;
}

/**
* build a shim function around the compound dtor that accepts an argument
* that is used to implement the deleting C++ destructor
*
* Params:
* ad = the aggregate that contains the destructor to wrap
* dtor = the destructor to wrap
* sc = the scope in which to analyze the new function
*
* Returns:
* the shim destructor, semantically analyzed and added to the class as a member
*/
private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclaration dtor, Scope* sc)
{
auto cldec = ad.isClassDeclaration();
if (!cldec || cldec.cppDtorVtblIndex == -1) // scalar deleting dtor not built for non-virtual dtors
return dtor;

// generate deleting C++ destructor corresponding to:
// void* C::~C(int del)
// {
// this->~C();
// // TODO: if (del) delete (char*)this;
// return (void*) this;
// }
Parameter delparam = new Parameter(STC.undefined_, Type.tuns32, Identifier.idPool("del"), new IntegerExp(dtor.loc, 0, Type.tuns32));
Parameters* params = new Parameters;
params.push(delparam);
auto ftype = new TypeFunction(params, Type.tvoidptr, false, LINK.cpp, dtor.storage_class);
auto func = new DtorDeclaration(dtor.loc, dtor.loc, dtor.storage_class, Id.cppdtor);
func.type = ftype;
if (dtor.fbody)
{
const loc = dtor.loc;
auto stmts = new Statements;
auto call = new CallExp(loc, dtor, null);
call.directcall = true;
stmts.push(new ExpStatement(loc, call));
stmts.push(new ReturnStatement(loc, new CastExp(loc, new ThisExp(loc), Type.tvoidptr)));
func.fbody = new CompoundStatement(loc, stmts);
func.generated = true;
}

auto sc2 = sc.push();
sc2.stc &= ~STC.static_; // not a static destructor
sc2.linkage = LINK.cpp;

ad.members.push(func);
func.addMember(sc2, ad);
func.dsymbolSemantic(sc2);

sc2.pop();
return func;
}

/**
* build a shim function around the compound dtor that translates
* a C++ destructor to a destructor with extern(D) calling convention
*
* Params:
* ad = the aggregate that contains the destructor to wrap
* sc = the scope in which to analyze the new function
*
* Returns:
* the shim destructor, semantically analyzed and added to the class as a member
*/
DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc)
{
auto dtor = ad.primaryDtor;
if (!dtor)
return null;

// the only ABI known to be incompatible is Windows/x86
if (ad.classKind != ClassKind.cpp || !global.params.isWindows || global.params.is64bit)
return dtor;

// generate member function that adjusts calling convention (EAX used instead of ECX for 'this'):
// extern(D) void __ticppdtor()
// {
// Class.__dtor();
// }
auto ftype = new TypeFunction(null, Type.tvoid, false, LINK.d, dtor.storage_class);
auto func = new DtorDeclaration(dtor.loc, dtor.loc, dtor.storage_class, Id.ticppdtor);
func.type = ftype;

auto call = new CallExp(dtor.loc, dtor, null);
call.directcall = true; // non-virtual call Class.__dtor();
func.fbody = new ExpStatement(dtor.loc, call);
func.generated = true;

auto sc2 = sc.push();
sc2.stc &= ~STC.static_; // not a static destructor
sc2.linkage = LINK.d;

ad.members.push(func);
func.addMember(sc2, ad);
func.dsymbolSemantic(sc2);

sc2.pop();
return func;
}

/******************************************
* Create inclusive invariant for struct/class by aggregating
* all the invariants in invs[].
Expand Down
2 changes: 1 addition & 1 deletion src/dmd/cppmangle.d
Expand Up @@ -95,7 +95,7 @@ bool isPrimaryDtor(const Dsymbol sym)
return false;
const ad = dtor.isMember();
assert(ad);
return dtor == ad.dtor;
return dtor == ad.primaryDtor;
}

private final class CppMangleVisitor : Visitor
Expand Down
11 changes: 8 additions & 3 deletions src/dmd/cppmanglewin.d
Expand Up @@ -603,7 +603,7 @@ private:
// <flags> ::= Y <calling convention flag>
buf.writeByte('Y');
}
const(char)* args = mangleFunctionType(cast(TypeFunction)d.type, d.needThis(), d.isCtorDeclaration() || d.isDtorDeclaration(), d.isDtorDeclaration() !is null);
const(char)* args = mangleFunctionType(cast(TypeFunction)d.type, d.needThis(), d.isCtorDeclaration() || isPrimaryDtor(d));
buf.writestring(args);
}

Expand Down Expand Up @@ -706,6 +706,11 @@ private:
buf.writestring("?R");
return;
}
else if (sym.ident == Id.cppdtor)
{
buf.writestring("?_G");
return;
}
}
if (TemplateInstance ti = sym.isTemplateInstance())
{
Expand Down Expand Up @@ -1133,7 +1138,7 @@ private:
cur.accept(this);
}

const(char)* mangleFunctionType(TypeFunction type, bool needthis = false, bool noreturn = false, bool noargs = false)
const(char)* mangleFunctionType(TypeFunction type, bool needthis = false, bool noreturn = false)
{
scope VisualCPPMangler tmp = new VisualCPPMangler(this);
// Calling convention
Expand Down Expand Up @@ -1193,7 +1198,7 @@ private:
rettype.accept(tmp);
tmp.flags &= ~MANGLE_RETURN_TYPE;
}
if (!type.parameters || !type.parameters.dim || noargs)
if (!type.parameters || !type.parameters.dim)
{
if (type.varargs == 1)
tmp.buf.writeByte('Z');
Expand Down
53 changes: 23 additions & 30 deletions src/dmd/dsymbolsem.d
Expand Up @@ -3736,15 +3736,27 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
ad.dtors.push(dd);
if (!dd.type)
{
Parameters* params = null;
if (ad.classKind == ClassKind.cpp && !Target.cppDeletingDestructor)
dd.type = new TypeFunction(null, Type.tvoid, false, LINK.d, dd.storage_class);
if (ad.classKind == ClassKind.cpp && dd.ident == Id.dtor)
{
// Windows doesn't use a deleting destructor, it takes an argument instead!
Parameter param = new Parameter(STC.undefined_, Type.tuns32, new Identifier("del"), new IntegerExp(Loc.initial, 0, Type.tuns32));
params = new Parameters;
(*params).push(param);
if (auto cldec = ad.isClassDeclaration())
{
assert (cldec.cppDtorVtblIndex == -1); // double-call check already by dd.type
if (cldec.baseClass && cldec.baseClass.cppDtorVtblIndex != -1)
{
// override the base virtual
cldec.cppDtorVtblIndex = cldec.baseClass.cppDtorVtblIndex;
}
else if (!dd.isFinal())
{
// reserve the dtor slot for the destructor (which we'll create later)
cldec.cppDtorVtblIndex = cast(int)cldec.vtbl.dim;
cldec.vtbl.push(dd);
if (Target.twoDtorInVtable)
cldec.vtbl.push(dd); // deleting destructor uses a second slot
}
}
}
dd.type = new TypeFunction(params, Type.tvoid, false, LINK.d, dd.storage_class);
}

sc = sc.push();
Expand Down Expand Up @@ -4237,6 +4249,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sd.ctor = sd.searchCtor();

sd.dtor = buildDtor(sd, sc2);
sd.tidtor = buildExternDDtor(sd, sc2);
sd.postblit = buildPostBlit(sd, sc2);

buildOpAssign(sd, sc2);
Expand Down Expand Up @@ -4777,27 +4790,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
auto s = (*cldec.members)[i];
s.dsymbolSemantic(sc2);

if (cldec.classKind == ClassKind.cpp)
{
const DtorDeclaration dtor = s.isDtorDeclaration();
if (dtor && cldec.cppDtorVtblIndex == -1)
{
if (cldec.baseClass && cldec.baseClass.cppDtorVtblIndex != -1)
{
// override the base virtual
cldec.cppDtorVtblIndex = cldec.baseClass.cppDtorVtblIndex;
}
else if (!dtor.isFinal())
{
// reserve the dtor slot for the destructor (which we'll create later)
cldec.cppDtorVtblIndex = cast(int)cldec.vtbl.dim;
cldec.vtbl.push(s);
if (Target.cppDeletingDestructor)
cldec.vtbl.push(s); // deleting destructor uses a second slot
}
}
}
}

if (!cldec.determineFields())
Expand Down Expand Up @@ -4884,17 +4876,18 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}

cldec.dtor = buildDtor(cldec, sc2);
cldec.tidtor = buildExternDDtor(cldec, sc2);

if (cldec.classKind == ClassKind.cpp && cldec.cppDtorVtblIndex != -1)
{
// now we've built the aggregate destructor, we'll make it virtual and assign it to the reserved vtable slot
cldec.dtor.vtblIndex = cldec.cppDtorVtblIndex;
cldec.vtbl[cldec.cppDtorVtblIndex] = cldec.dtor;

if (Target.cppDeletingDestructor)
if (Target.twoDtorInVtable)
{
// TODO: create a C++ compatible deleting destructor (call out to `operator delete`)
// for the mooment, we'll call the non-deleting destructor and leak
// for the moment, we'll call the non-deleting destructor and leak
cldec.vtbl[cldec.cppDtorVtblIndex + 1] = cldec.dtor;
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/dmd/id.d
Expand Up @@ -66,6 +66,8 @@ immutable Msgtable[] msgtable =
{ "__xdtor", "__xdtor" },
{ "__fieldDtor", "__fieldDtor" },
{ "__aggrDtor", "__aggrDtor" },
{ "cppdtor", "__cppdtor" },
{ "ticppdtor", "__ticppdtor" },
{ "postblit", "__postblit" },
{ "__xpostblit", "__xpostblit" },
{ "__fieldPostblit", "__fieldPostblit" },
Expand Down

0 comments on commit ab0a7bf

Please sign in to comment.