Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for the non-global template issue 5710 #9282

Merged
merged 20 commits into from
Apr 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 59 additions & 2 deletions src/dmd/aggregate.d
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
Dsymbol enclosing;

VarDeclaration vthis; // 'this' parameter if this aggregate is nested
VarDeclaration vthis2; // 'this' parameter if this aggregate is a template and is nested

// Special member functions
FuncDeclarations invs; // Array of invariants
Expand Down Expand Up @@ -238,6 +239,15 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
return true;
}

/***************************************
* Returns:
* The total number of fields minus the number of hidden fields.
*/
final size_t nonHiddenFields()
{
return fields.dim - isNested() - (vthis2 !is null);
}

/***************************************
* Collect all instance fields, then determine instance size.
* Returns:
Expand Down Expand Up @@ -322,6 +332,8 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
auto cd = isClassDeclaration();
if (!cd || !cd.baseClass || !cd.baseClass.isNested())
nfields--;
if (vthis2 && !(cd && cd.baseClass && cd.baseClass.vthis2))
nfields--;
}
bool errors = false;

Expand Down Expand Up @@ -392,7 +404,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
//printf("AggregateDeclaration::fill() %s\n", toChars());
assert(sizeok == Sizeok.done);
assert(elements);
size_t nfields = fields.dim - isNested();
const nfields = nonHiddenFields();
bool errors = false;

size_t dim = elements.dim;
Expand Down Expand Up @@ -639,7 +651,9 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
return;

// If nested struct, add in hidden 'this' pointer to outer scope
auto s = toParent2();
auto s = toParentLocal();
if (!s)
s = toParent2();
if (!s)
return;
Type t = null;
Expand Down Expand Up @@ -691,9 +705,52 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol

if (sizeok == Sizeok.fwd)
fields.push(vthis);

makeNested2();
}
}

/* Append vthis2 field (this.tupleof[$-1]) to add a second context pointer.
*/
final void makeNested2()
{
if (vthis2)
return;
if (!vthis)
makeNested(); // can't add second before first
if (!vthis)
return;
if (sizeok == Sizeok.done)
return;
if (isUnionDeclaration() || isInterfaceDeclaration())
return;
if (storage_class & STC.static_)
return;

auto s0 = toParentLocal();
auto s = toParent2();
if (!s || !s0 || s == s0)
return;
auto cd = s.isClassDeclaration();
Type t = cd ? cd.type : Type.tvoidptr;

vthis2 = new ThisDeclaration(loc, t);
//vthis2.storage_class |= STC.ref_;

// Emulate vthis2.addMember()
members.push(vthis2);

// Emulate vthis2.dsymbolSemantic()
vthis2.storage_class |= STC.field;
vthis2.parent = this;
vthis2.protection = Prot(Prot.Kind.public_);
vthis2.alignment = t.alignment();
vthis2.semanticRun = PASS.semanticdone;

if (sizeok == Sizeok.fwd)
fields.push(vthis2);
}

override final bool isExport() const
{
return protection.kind == Prot.Kind.export_;
Expand Down
17 changes: 14 additions & 3 deletions src/dmd/ctfeexpr.d
Original file line number Diff line number Diff line change
Expand Up @@ -1658,8 +1658,12 @@ void assignInPlace(Expression dest, Expression src)
assert(dest.op == src.op);
oldelems = (cast(StructLiteralExp)dest).elements;
newelems = (cast(StructLiteralExp)src).elements;
if ((cast(StructLiteralExp)dest).sd.isNested() && oldelems.dim == newelems.dim - 1)
oldelems.push(null);
auto sd = (cast(StructLiteralExp)dest).sd;
const nfields = sd.nonHiddenFields();
const nvthis = sd.fields.dim - nfields;
if (nvthis && oldelems.dim >= nfields && oldelems.dim < newelems.dim)
foreach (_; 0 .. newelems.dim - oldelems.dim)
oldelems.push(null);
}
else if (dest.op == TOK.arrayLiteral && src.op == TOK.arrayLiteral)
{
Expand Down Expand Up @@ -1857,7 +1861,14 @@ bool isCtfeValueValid(Expression newval)
{
// e1 should be a CTFE reference
Expression e1 = (cast(AddrExp)newval).e1;
return tb.ty == Tpointer && (e1.op == TOK.structLiteral && isCtfeValueValid(e1) || e1.op == TOK.variable || e1.op == TOK.dotVariable && isCtfeReferenceValid(e1) || e1.op == TOK.index && isCtfeReferenceValid(e1) || e1.op == TOK.slice && e1.type.toBasetype().ty == Tsarray);
return tb.ty == Tpointer &&
(
(e1.op == TOK.structLiteral || e1.op == TOK.arrayLiteral) && isCtfeValueValid(e1) ||
e1.op == TOK.variable ||
e1.op == TOK.dotVariable && isCtfeReferenceValid(e1) ||
e1.op == TOK.index && isCtfeReferenceValid(e1) ||
e1.op == TOK.slice && e1.type.toBasetype().ty == Tsarray
);
}
if (newval.op == TOK.slice)
{
Expand Down
12 changes: 6 additions & 6 deletions src/dmd/dcast.d
Original file line number Diff line number Diff line change
Expand Up @@ -2360,17 +2360,17 @@ Expression castTo(Expression e, Scope* sc, Type t)
result = new DelegateExp(e.loc, new ThisExp(e.loc), f, false);
result = result.expressionSemantic(sc);
}
else if (f.isNested())
{
result = new DelegateExp(e.loc, IntegerExp.literal!0, f, false);
result = result.expressionSemantic(sc);
}
else if (f.needThis())
{
e.error("no `this` to create delegate for `%s`", f.toChars());
result = new ErrorExp();
return;
}
else if (f.isNested())
{
result = new DelegateExp(e.loc, IntegerExp.literal!0, f, false);
result = result.expressionSemantic(sc);
}
else
{
e.error("cannot cast from function pointer to delegate");
Expand Down Expand Up @@ -2435,7 +2435,7 @@ Expression castTo(Expression e, Scope* sc, Type t)
e.error("%s", msg);
if (f != e.func) // if address not already marked as taken
f.tookAddressOf++;
result = new DelegateExp(e.loc, e.e1, f, false);
result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2);
result.type = t;
return;
}
Expand Down
8 changes: 5 additions & 3 deletions src/dmd/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ import dmd.visitor;
*/
bool checkFrameAccess(Loc loc, Scope* sc, AggregateDeclaration ad, size_t iStart = 0)
{
Dsymbol sparent = ad.toParent2();
Dsymbol sparent = ad.toParentLocal();
Dsymbol sparent2 = ad.toParent2();
Dsymbol s = sc.func;
if (ad.isNested() && s)
{
//printf("ad = %p %s [%s], parent:%p\n", ad, ad.toChars(), ad.loc.toChars(), ad.parent);
//printf("sparent = %p %s [%s], parent: %s\n", sparent, sparent.toChars(), sparent.loc.toChars(), sparent.parent,toChars());
if (!ensureStaticLinkTo(s, sparent))
//printf("sparent2 = %p %s [%s], parent: %s\n", sparent2, sparent2.toChars(), sparent2.loc.toChars(), sparent2.parent,toChars());
if (!ensureStaticLinkTo(s, sparent) || sparent != sparent2 && !ensureStaticLinkTo(s, sparent2))
{
error(loc, "cannot access frame pointer of `%s`", ad.toPrettyChars());
return true;
Expand Down Expand Up @@ -186,7 +188,7 @@ bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1)
{
if (s)
{
s = s.toParent2();
s = toParentP(s, var.toParent2());
continue;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/dmd/delegatize.d
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ bool ensureStaticLinkTo(Dsymbol s, Dsymbol p)
if (ad.storage_class & STC.static_)
break;
}
s = s.toParent2();
s = toParentP(s, p);
}
return false;
}
77 changes: 69 additions & 8 deletions src/dmd/dinterpret.d
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
// except for delegates. (Note that the 'this' pointer may be null).
// Func literals report isNested() even if they are in global scope,
// so we need to check that the parent is a function.
if (fd.isNested() && fd.toParent2().isFuncDeclaration() && !thisarg && istate)
if (fd.isNested() && fd.toParentLocal().isFuncDeclaration() && !thisarg && istate)
thisarg = ctfeStack.getThis();

if (fd.needThis() && !thisarg)
Expand Down Expand Up @@ -876,6 +876,26 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
InterState istatex;
istatex.caller = istate;
istatex.fd = fd;

if (fd.isThis2)
{
Expression arg0 = thisarg;
if (arg0 && arg0.type.ty == Tstruct)
{
Type t = arg0.type.pointerTo();
arg0 = new AddrExp(arg0.loc, arg0);
arg0.type = t;
}
auto elements = new Expressions(2);
(*elements)[0] = arg0;
(*elements)[1] = ctfeStack.getThis();
Type t2 = Type.tvoidptr.sarrayOf(2);
const loc = thisarg ? thisarg.loc : fd.loc;
thisarg = new ArrayLiteralExp(loc, t2, elements);
thisarg = new AddrExp(loc, thisarg);
thisarg.type = t2.pointerTo();
}

ctfeStack.startFrame(thisarg);
if (fd.vthis && thisarg)
{
Expand Down Expand Up @@ -1000,6 +1020,24 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
e = CTFEExp.voidexp;
if (tf.isref && e.op == TOK.variable && (cast(VarExp)e).var == fd.vthis)
e = thisarg;
if (tf.isref && fd.isThis2 && e.op == TOK.index)
{
auto ie = cast(IndexExp)e;
auto pe = ie.e1.isPtrExp();
auto ve = !pe ? null : pe.e1.isVarExp();
if (ve && ve.var == fd.vthis)
{
auto ne = ie.e2.isIntegerExp();
assert(ne);
assert(thisarg.op == TOK.address);
e = (cast(AddrExp)thisarg).e1;
e = (*(cast(ArrayLiteralExp)e).elements)[cast(size_t)ne.getInteger()];
if (e.op == TOK.address)
{
e = (cast(AddrExp)e).e1;
}
}
}
assert(e !is null);

// Leave the function
Expand Down Expand Up @@ -2010,6 +2048,12 @@ public:
if (istate && istate.fd.vthis)
{
result = new VarExp(e.loc, istate.fd.vthis);
if (istate.fd.isThis2)
{
result = new PtrExp(e.loc, result);
result.type = Type.tvoidptr.sarrayOf(2);
result = new IndexExp(e.loc, result, IntegerExp.literal!0);
}
result.type = e.type;
}
else
Expand All @@ -2020,6 +2064,18 @@ public:
result = ctfeStack.getThis();
if (result)
{
if (istate && istate.fd.isThis2)
{
assert(result.op == TOK.address);
result = (cast(AddrExp)result).e1;
assert(result.op == TOK.arrayLiteral);
result = (*(cast(ArrayLiteralExp)result).elements)[0];
if (e.type.ty == Tstruct)
{
result = (cast(AddrExp)result).e1;
}
return;
}
assert(result.op == TOK.structLiteral || result.op == TOK.classReference);
return;
}
Expand Down Expand Up @@ -2867,17 +2923,22 @@ public:
if (dim != e.sd.fields.dim)
{
// guaranteed by AggregateDeclaration.fill and TypeStruct.defaultInitLiteral
assert(e.sd.isNested() && dim == e.sd.fields.dim - 1);
const nvthis = e.sd.fields.dim - e.sd.nonHiddenFields();
assert(e.sd.fields.dim - dim == nvthis);

/* If a nested struct has no initialized hidden pointer,
* set it to null to match the runtime behaviour.
*/
auto ne = new NullExp(e.loc);
ne.type = e.sd.vthis.type;
foreach (const i; 0 .. nvthis)
{
auto ne = new NullExp(e.loc);
auto vthis = i == 0 ? e.sd.vthis : e.sd.vthis2;
ne.type = vthis.type;

expsx = copyArrayOnWrite(expsx, e.elements);
expsx.push(ne);
++dim;
expsx = copyArrayOnWrite(expsx, e.elements);
expsx.push(ne);
++dim;
}
}
assert(dim == e.sd.fields.dim);

Expand Down Expand Up @@ -4980,7 +5041,7 @@ public:
// Member function call

// Currently this is satisfied because closure is not yet supported.
assert(!fd.isNested());
assert(!fd.isNested() || fd.needThis());

if (pthis.op == TOK.typeid_)
{
Expand Down
4 changes: 2 additions & 2 deletions src/dmd/dstruct.d
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
if (!elements)
return true;

size_t nfields = fields.dim - isNested();
thewilsonator marked this conversation as resolved.
Show resolved Hide resolved
const nfields = nonHiddenFields();
size_t offset = 0;
for (size_t i = 0; i < elements.dim; i++)
{
Expand All @@ -456,7 +456,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
e = resolveProperties(sc, e);
if (i >= nfields)
{
if (i == fields.dim - 1 && isNested() && e.op == TOK.null_)
if (i <= fields.dim && e.op == TOK.null_)
{
// CTFE sometimes creates null as hidden pointer; we'll allow this.
continue;
Expand Down
25 changes: 25 additions & 0 deletions src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -5065,6 +5065,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
memcpy(cldec.vtbl.tdata(), cldec.baseClass.vtbl.tdata(), (void*).sizeof * cldec.vtbl.dim);

cldec.vthis = cldec.baseClass.vthis;
cldec.vthis2 = cldec.baseClass.vthis2;
}
else
{
Expand Down Expand Up @@ -5102,6 +5103,30 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
cldec.enclosing = null;
}
if (cldec.vthis2)
{
if (cldec.toParent2() != cldec.baseClass.toParent2() &&
(!cldec.toParent2() ||
!cldec.baseClass.toParent2().getType() ||
!cldec.baseClass.toParent2().getType().isBaseOf(cldec.toParent2().getType(), null)))
{
if (cldec.toParent2() && cldec.toParent2() != cldec.toParentLocal())
{
cldec.error("needs the frame pointer of `%s`, but super class `%s` needs the frame pointer of `%s`",
cldec.toParent2().toChars(),
cldec.baseClass.toChars(),
cldec.baseClass.toParent2().toChars());
}
else
{
cldec.error("doesn't need a frame pointer, but super class `%s` needs the frame pointer of `%s`",
cldec.baseClass.toChars(),
cldec.baseClass.toParent2().toChars());
}
}
}
else
cldec.makeNested2();
}
else
cldec.makeNested();
Expand Down
Loading