121 changes: 97 additions & 24 deletions src/clone.d
Original file line number Diff line number Diff line change
Expand Up @@ -747,20 +747,22 @@ extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
Loc declLoc = sd.postblits.dim ? sd.postblits[0].loc : sd.loc;
Loc loc = Loc(); // internal code should have no loc to prevent coverage

for (size_t i = 0; i < sd.postblits.dim; i++)
{
stc |= sd.postblits[i].storage_class & STCdisable;
}

Statements* a = null;
for (size_t i = 0; i < sd.fields.dim && !(stc & STCdisable); i++)
{
VarDeclaration v = sd.fields[i];
auto v = sd.fields[i];
if (v.storage_class & STCref)
continue;
Type tv = v.type.baseElemOf();
if (tv.ty != Tstruct || !v.type.size())
if (tv.ty != Tstruct)
continue;
StructDeclaration sdv = (cast(TypeStruct)tv).sym;
auto sdv = (cast(TypeStruct)tv).sym;
if (!sdv.postblit)
continue;
sdv.postblit.functionSemantic();
Expand All @@ -774,74 +776,115 @@ extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
}
if (!a)
a = new Statements();
Expression ex = new ThisExp(loc);
ex = new DotVarExp(loc, ex, v);
if (v.type.toBasetype().ty == Tstruct)

Expression ex;
tv = v.type.toBasetype();
if (tv.ty == Tstruct)
{
// this.v.__xpostblit()

ex = new ThisExp(loc);
ex = new DotVarExp(loc, ex, v);

// This is a hack so we can call postblits on const/immutable objects.
ex = new AddrExp(loc, ex);
ex = new CastExp(loc, ex, v.type.mutableOf().pointerTo());
ex = new PtrExp(loc, ex);
if (stc & STCsafe)
stc = (stc & ~STCsafe) | STCtrusted;

ex = new DotVarExp(loc, ex, sdv.postblit, false);
ex = new CallExp(loc, ex);
}
else
{
// _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n])

uinteger_t n = 1;
while (tv.ty == Tsarray)
{
n *= (cast(TypeSArray)tv).dim.toUInteger();
tv = tv.nextOf().toBasetype();
}
if (n == 0)
continue;

ex = new ThisExp(loc);
ex = new DotVarExp(loc, ex, v);

// This is a hack so we can call postblits on const/immutable objects.
ex = new DotIdExp(loc, ex, Id.ptr);
ex = new CastExp(loc, ex, sdv.type.pointerTo());
if (stc & STCsafe)
stc = (stc & ~STCsafe) | STCtrusted;
uinteger_t n = v.type.size() / sdv.type.size();
ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, n, Type.tsize_t));

ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t),
new IntegerExp(loc, n, Type.tsize_t));
// Prevent redundant bounds check
(cast(SliceExp)ex).upperIsInBounds = true;
(cast(SliceExp)ex).lowerIsLessThanUpper = true;
ex = new CallExp(loc, new IdentifierExp(loc, Id._ArrayPostblit), ex);
}
a.push(new ExpStatement(loc, ex)); // combine in forward order

/* Bugzilla 10972: When the following field postblit calls fail,
* this field should be destructed for Exception Safety.
*/
if (!sdv.dtor)
continue;
sdv.dtor.functionSemantic();

ex = new ThisExp(loc);
ex = new DotVarExp(loc, ex, v);
if (v.type.toBasetype().ty == Tstruct)
tv = v.type.toBasetype();
if (tv.ty == Tstruct)
{
// this.v.__xdtor()

ex = new ThisExp(loc);
ex = new DotVarExp(loc, ex, v);

// This is a hack so we can call destructors on const/immutable objects.
ex = new AddrExp(loc, ex);
ex = new CastExp(loc, ex, v.type.mutableOf().pointerTo());
ex = new PtrExp(loc, ex);
if (stc & STCsafe)
stc = (stc & ~STCsafe) | STCtrusted;

ex = new DotVarExp(loc, ex, sdv.dtor, false);
ex = new CallExp(loc, ex);
}
else
{
// _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])

uinteger_t n = 1;
while (tv.ty == Tsarray)
{
n *= (cast(TypeSArray)tv).dim.toUInteger();
tv = tv.nextOf().toBasetype();
}
//if (n == 0)
// continue;

ex = new ThisExp(loc);
ex = new DotVarExp(loc, ex, v);

// This is a hack so we can call destructors on const/immutable objects.
ex = new DotIdExp(loc, ex, Id.ptr);
ex = new CastExp(loc, ex, sdv.type.pointerTo());
if (stc & STCsafe)
stc = (stc & ~STCsafe) | STCtrusted;
uinteger_t n = v.type.size() / sdv.type.size();
ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, n, Type.tsize_t));

ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t),
new IntegerExp(loc, n, Type.tsize_t));
// Prevent redundant bounds check
(cast(SliceExp)ex).upperIsInBounds = true;
(cast(SliceExp)ex).lowerIsLessThanUpper = true;

ex = new CallExp(loc, new IdentifierExp(loc, Id._ArrayDtor), ex);
}
a.push(new OnScopeStatement(loc, TOKon_scope_failure, new ExpStatement(loc, ex)));
}

/* Build our own "postblit" which executes a
*/
if (a || (stc & STCdisable))
Expand All @@ -854,14 +897,17 @@ extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
sd.members.push(dd);
dd.semantic(sc);
}

FuncDeclaration xpostblit = null;
switch (sd.postblits.dim)
{
case 0:
break;

case 1:
xpostblit = sd.postblits[0];
break;

default:
Expression e = null;
stc = STCsafe | STCnothrow | STCpure | STCnogc;
Expand All @@ -887,6 +933,7 @@ extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
xpostblit = dd;
break;
}

// Add an __xpostblit alias to make the inclusive postblit accessible
if (xpostblit)
{
Expand All @@ -911,16 +958,17 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
Loc declLoc = ad.dtors.dim ? ad.dtors[0].loc : ad.loc;
Loc loc = Loc(); // internal code should have no loc to prevent coverage

Expression e = null;
for (size_t i = 0; i < ad.fields.dim; i++)
{
VarDeclaration v = ad.fields[i];
auto v = ad.fields[i];
if (v.storage_class & STCref)
continue;
Type tv = v.type.baseElemOf();
if (tv.ty != Tstruct || !v.type.size())
auto tv = v.type.baseElemOf();
if (tv.ty != Tstruct)
continue;
StructDeclaration sdv = (cast(TypeStruct)tv).sym;
auto sdv = (cast(TypeStruct)tv).sym;
if (!sdv.dtor)
continue;
sdv.dtor.functionSemantic();
Expand All @@ -931,37 +979,59 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
e = null;
break;
}
Expression ex = new ThisExp(loc);
ex = new DotVarExp(loc, ex, v);
if (v.type.toBasetype().ty == Tstruct)

Expression ex;
tv = v.type.toBasetype();
if (tv.ty == Tstruct)
{
// this.v.__xdtor()

ex = new ThisExp(loc);
ex = new DotVarExp(loc, ex, v);

// This is a hack so we can call destructors on const/immutable objects.
ex = new AddrExp(loc, ex);
ex = new CastExp(loc, ex, v.type.mutableOf().pointerTo());
ex = new PtrExp(loc, ex);
if (stc & STCsafe)
stc = (stc & ~STCsafe) | STCtrusted;

ex = new DotVarExp(loc, ex, sdv.dtor, false);
ex = new CallExp(loc, ex);
}
else
{
// _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])

uinteger_t n = 1;
while (tv.ty == Tsarray)
{
n *= (cast(TypeSArray)tv).dim.toUInteger();
tv = tv.nextOf().toBasetype();
}
if (n == 0)
continue;

ex = new ThisExp(loc);
ex = new DotVarExp(loc, ex, v);

// This is a hack so we can call destructors on const/immutable objects.
ex = new DotIdExp(loc, ex, Id.ptr);
ex = new CastExp(loc, ex, sdv.type.pointerTo());
if (stc & STCsafe)
stc = (stc & ~STCsafe) | STCtrusted;
uinteger_t n = v.type.size() / sdv.type.size();
ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, n, Type.tsize_t));

ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t),
new IntegerExp(loc, n, Type.tsize_t));
// Prevent redundant bounds check
(cast(SliceExp)ex).upperIsInBounds = true;
(cast(SliceExp)ex).lowerIsLessThanUpper = true;

ex = new CallExp(loc, new IdentifierExp(loc, Id._ArrayDtor), ex);
}
e = Expression.combine(ex, e); // combine in reverse order
}

/* Build our own "destructor" which executes e
*/
if (e || (stc & STCdisable))
Expand All @@ -974,14 +1044,17 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
ad.members.push(dd);
dd.semantic(sc);
}

FuncDeclaration xdtor = null;
switch (ad.dtors.dim)
{
case 0:
break;

case 1:
xdtor = ad.dtors[0];
break;

default:
e = null;
stc = STCsafe | STCnothrow | STCpure | STCnogc;
Expand All @@ -1007,6 +1080,7 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
xdtor = dd;
break;
}

// Add an __xdtor alias to make the inclusive dtor accessible
if (xdtor)
{
Expand Down Expand Up @@ -1063,8 +1137,7 @@ extern (C++) FuncDeclaration buildInv(AggregateDeclaration ad, Scope* sc)
}
e = Expression.combine(e, new CallExp(loc, new VarExp(loc, ad.invs[i], false)));
}
InvariantDeclaration inv;
inv = new InvariantDeclaration(declLoc, Loc(), stc | stcx, Id.classInvariant);
auto inv = new InvariantDeclaration(declLoc, Loc(), stc | stcx, Id.classInvariant);
inv.fbody = new ExpStatement(loc, e);
ad.members.push(inv);
inv.semantic(sc);
Expand Down
156 changes: 56 additions & 100 deletions src/dclass.d
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,6 @@ public:

if (semanticRun >= PASSsemanticdone)
return;
uint dprogress_save = Module.dprogress;
int errors = global.errors;

//printf("+ClassDeclaration.semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
Expand All @@ -443,7 +442,7 @@ public:
type = type.semantic(loc, sc);
if (type.ty == Tclass && (cast(TypeClass)type).sym != this)
{
TemplateInstance ti = (cast(TypeClass)type).sym.isInstantiated();
auto ti = (cast(TypeClass)type).sym.isInstantiated();
if (ti && isError(ti))
(cast(TypeClass)type).sym = this;
}
Expand Down Expand Up @@ -730,7 +729,7 @@ public:
*/
for (size_t i = 0; i < members.dim; i++)
{
Dsymbol s = (*members)[i];
auto s = (*members)[i];
s.addMember(sc, this);
}

Expand All @@ -755,13 +754,14 @@ public:
*/
for (size_t i = 0; i < members.dim; i++)
{
Dsymbol s = (*members)[i];
auto s = (*members)[i];
//printf("[%d] setScope %s %s, sc2 = %p\n", i, s.kind(), s.toChars(), sc2);
s.setScope(sc2);
}

sc2.pop();
}

for (size_t i = 0; i < baseclasses.dim; i++)
{
BaseClass* b = (*baseclasses)[i];
Expand Down Expand Up @@ -840,13 +840,7 @@ public:
makeNested();
}

// it might be determined already, by AggregateDeclaration.size().
if (sizeok != SIZEOKdone)
sizeok = SIZEOKnone;

Scope* sc2 = sc.push(this);
//sc2.stc &= ~(STCfinal | STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared);
//sc2.stc |= storage_class & STC_TYPECTOR;
sc2.stc &= STCsafe | STCtrusted | STCsystem;
sc2.parent = this;
sc2.inunion = 0;
Expand All @@ -867,8 +861,9 @@ public:
sc2.structalign = STRUCTALIGN_DEFAULT;
sc2.userAttribDecl = null;

foreach (s; *members)
for (size_t i = 0; i < members.dim; ++i)
{
auto s = (*members)[i];
s.importAll(sc2);
}

Expand All @@ -879,48 +874,21 @@ public:
s.semantic(sc2);
}

finalizeSize();

if (sizeok == SIZEOKfwd)
if (!determineFields())
{
// semantic() failed due to forward references
// Unwind what we did, and defer it for later
foreach (v; fields)
{
v.offset = 0;
}
fields.setDim(0);
structsize = 0;
alignsize = 0;

assert(type == Type.terror);
sc2.pop();

_scope = scx ? scx : sc.copy();
_scope.setNoFree();
_scope._module.addDeferredSemantic(this);
Module.dprogress = dprogress_save;
//printf("\tsemantic('%s') failed due to forward references\n", toChars());
return;
}

Module.dprogress++;
semanticRun = PASSsemanticdone;
//printf("-ClassDeclaration.semantic(%s), type = %p\n", toChars(), type);
//members.print();

version (none) // FIXME
{
LafterSizeok:
// The additions of special member functions should have its own
// sub-semantic analysis pass, and have to be deferred sometimes.
// See the case in compilable/test14838.d
for (size_t i = 0; i < fields.dim; i++)
/* Following special member functions creation needs semantic analysis
* completion of sub-structs in each field types.
*/
foreach (v; fields)
{
VarDeclaration v = fields[i];
Type tb = v.type.baseElemOf();
if (tb.ty != Tstruct)
continue;
StructDeclaration sd = (cast(TypeStruct)tb).sym;
auto sd = (cast(TypeStruct)tb).sym;
if (sd.semanticRun >= PASSsemanticdone)
continue;

Expand All @@ -929,11 +897,9 @@ public:
_scope = scx ? scx : sc.copy();
_scope.setNoFree();
_scope._module.addDeferredSemantic(this);

//printf("\tdeferring %s\n", toChars());
return;
}
}

/* Look for special member functions.
* They must be in this class, not in a base class.
Expand All @@ -942,14 +908,14 @@ public:
aggNew = cast(NewDeclaration)search(Loc(), Id.classNew);
aggDelete = cast(DeleteDeclaration)search(Loc(), Id.classDelete);

// this.ctor is already set
// Look for the constructor
ctor = searchCtor();

if (!ctor && noDefaultCtor)
{
// A class object is always created by constructor, so this check is legitimate.
for (size_t i = 0; i < fields.dim; i++)
foreach (v; fields)
{
VarDeclaration v = fields[i];
if (v.storage_class & STCnodefaultctor)
.error(v.loc, "field %s must be initialized in constructor", v.toChars());
}
Expand All @@ -960,21 +926,24 @@ public:
// this() { }
if (!ctor && baseClass && baseClass.ctor)
{
FuncDeclaration fd = resolveFuncCall(loc, sc2, baseClass.ctor, null, null, null, 1);
auto fd = resolveFuncCall(loc, sc2, baseClass.ctor, null, null, null, 1);
if (fd && !fd.errors)
{
//printf("Creating default this(){} for class %s\n", toChars());
TypeFunction btf = cast(TypeFunction)fd.type;
auto btf = cast(TypeFunction)fd.type;
auto tf = new TypeFunction(null, null, 0, LINKd, fd.storage_class);
tf.purity = btf.purity;
tf.purity = btf.purity;
tf.isnothrow = btf.isnothrow;
tf.isnogc = btf.isnogc;
tf.trust = btf.trust;
tf.isnogc = btf.isnogc;
tf.trust = btf.trust;

auto ctor = new CtorDeclaration(loc, Loc(), 0, tf);
ctor.fbody = new CompoundStatement(Loc(), new Statements());

members.push(ctor);
ctor.addMember(sc, this);
ctor.semantic(sc2);

this.ctor = ctor;
defaultCtor = ctor;
}
Expand All @@ -987,14 +956,19 @@ public:

dtor = buildDtor(this, sc2);

if (FuncDeclaration f = hasIdentityOpAssign(this, sc2))
if (auto f = hasIdentityOpAssign(this, sc2))
{
if (!(f.storage_class & STCdisable))
error(f.loc, "identity assignment operator overload is illegal");
}

inv = buildInv(this, sc2);

Module.dprogress++;
semanticRun = PASSsemanticdone;
//printf("-ClassDeclaration.semantic(%s), type = %p\n", toChars(), type);
//members.print();

sc2.pop();

if (global.errors != errors)
Expand All @@ -1008,13 +982,15 @@ public:

// Verify fields of a synchronized class are not public
if (storage_class & STCsynchronized)
foreach (vd; this.fields)
{
if (!vd.isThisDeclaration() &&
!vd.prot().isMoreRestrictiveThan(Prot(PROTpublic)))
foreach (vd; this.fields)
{
vd.error("Field members of a synchronized class cannot be %s",
protectionToChars(vd.prot().kind));
if (!vd.isThisDeclaration() &&
!vd.prot().isMoreRestrictiveThan(Prot(PROTpublic)))
{
vd.error("Field members of a synchronized class cannot be %s",
protectionToChars(vd.prot().kind));
}
}
}

Expand Down Expand Up @@ -1172,8 +1148,7 @@ public:

final override void finalizeSize()
{
if (sizeok != SIZEOKnone)
return;
assert(sizeok != SIZEOKdone);

// Set the offsets of the fields and determine the size of the class
if (baseClass)
Expand Down Expand Up @@ -1201,7 +1176,7 @@ public:
structsize += Target.ptrsize; // allow room for __monitor
}

//printf("finalizeSize() %s\n", toChars());
//printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
size_t bi = 0; // index into vtblInterfaces[]

/****
Expand All @@ -1221,10 +1196,15 @@ public:

foreach (BaseClass* b; cd.interfaces)
{
if (b.sym.sizeok != SIZEOKdone)
b.sym.finalizeSize();
assert(b.sym.sizeok == SIZEOKdone);

if (!b.sym.alignsize)
b.sym.alignsize = Target.ptrsize;
alignmember(b.sym.alignsize, b.sym.alignsize, &offset);
assert(bi < vtblInterfaces.dim);

BaseClass* bv = (*vtblInterfaces)[bi];
if (b.sym.interfaces.length == 0)
{
Expand Down Expand Up @@ -1256,43 +1236,20 @@ public:
return;
}

// FIXME: Currently setFieldOffset functions need to increase fields
// to calculate each variable offsets. It can be improved later.
fields.setDim(0);

uint offset = structsize;
foreach (s; *members)
{
s.setFieldOffset(this, &offset, false);
}

if (sizeok == SIZEOKfwd)
return;

sizeok = SIZEOKdone;

// Calculate fields[i].overlapped
checkOverlappedFields();

// Look for the constructor
ctor = searchCtor();
if (ctor && ctor.toParent() != this)
ctor = null; // search() looks through ancestor classes
if (ctor)
{
// Finish all constructors semantics to determine this.noDefaultCtor.
struct SearchCtor
{
extern (C++) static int fp(Dsymbol s, void* ctxt)
{
CtorDeclaration f = s.isCtorDeclaration();
if (f && f.semanticRun == PASSinit)
f.semantic(null);
return 0;
}
}

foreach (s; *members)
{
s.apply(&SearchCtor.fp, null);
}
}
}

final bool isFuncHidden(FuncDeclaration fd)
Expand Down Expand Up @@ -1543,6 +1500,8 @@ public:
return;
int errors = global.errors;

//printf("+InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type);

Scope* scx = null;
if (_scope)
{
Expand All @@ -1563,7 +1522,7 @@ public:
type = type.semantic(loc, sc);
if (type.ty == Tclass && (cast(TypeClass)type).sym != this)
{
TemplateInstance ti = (cast(TypeClass)type).sym.isInstantiated();
auto ti = (cast(TypeClass)type).sym.isInstantiated();
if (ti && isError(ti))
(cast(TypeClass)type).sym = this;
}
Expand Down Expand Up @@ -1839,21 +1798,19 @@ public:
s.semantic(sc2);
}

finalizeSize();

Module.dprogress++;
semanticRun = PASSsemanticdone;
//printf("-InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type);
//members.print();

sc2.pop();

if (global.errors != errors)
{
// The type is no good.
type = Type.terror;
}

//members.print();
sc2.pop();

//printf("-InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type);

version (none)
{
if (type.ty == Tclass && (cast(TypeClass)type).sym != this)
Expand All @@ -1865,7 +1822,6 @@ public:
assert(type.ty != Tclass || (cast(TypeClass)type).sym == this);
}


/*******************************************
* Determine if 'this' is a base class of cd.
* (Actually, if it is an interface supported by cd)
Expand Down
44 changes: 19 additions & 25 deletions src/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -1709,6 +1709,9 @@ public:
if (!isField())
return;
assert(!(storage_class & (STCstatic | STCextern | STCparameter | STCtls)));

//printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());

/* Fields that are tuples appear both as part of TupleDeclarations and
* as members. That means ignore them if they are already a field.
*/
Expand All @@ -1727,39 +1730,26 @@ public:
return;
}
}

// Check for forward referenced types which will fail the size() call
Type t = type.toBasetype();
if (storage_class & STCref)
{
// References are the size of a pointer
t = Type.tvoidptr;
}
if (t.ty == Tstruct || t.ty == Tsarray)
Type tv = t.baseElemOf();
if (tv.ty == Tstruct)
{
Type tv = t.baseElemOf();
if (tv.ty == Tstruct)
auto ts = cast(TypeStruct)tv;
assert(ts.sym != ad); // already checked in ad.determineFields()
if (!ts.sym.determineSize(loc))
{
TypeStruct ts = cast(TypeStruct)tv;
if (ts.sym == ad)
{
const(char)* s = (t.ty == Tsarray) ? "static array of " : "";
ad.error("cannot have field %s with %ssame struct type", toChars(), s);
return;
}
if (ts.sym.sizeok != SIZEOKdone && ts.sym._scope)
ts.sym.semantic(null);
if (ts.sym.sizeok != SIZEOKdone)
{
ad.sizeok = SIZEOKfwd; // cannot finish; flag as forward referenced
return;
}
type = Type.terror;
errors = true;
return;
}
}
if (t.ty == Tident)
{
ad.sizeok = SIZEOKfwd; // cannot finish; flag as forward referenced
return;
}

// List in ad.fields. Even if the type is error, it's necessary to avoid
// pointless error diagnostic "more initializers than fields" on struct literal.
Expand All @@ -1768,9 +1758,13 @@ public:
if (t.ty == Terror)
return;

uint memsize = cast(uint)t.size(loc); // size of member
uint memalignsize = Target.fieldalign(t); // size of member for alignment purposes
offset = AggregateDeclaration.placeField(poffset, memsize, memalignsize, alignment, &ad.structsize, &ad.alignsize, isunion);
uint memsize = cast(uint)t.size(loc); // size of member
uint memalignsize = Target.fieldalign(t); // size of member for alignment purposes
offset = AggregateDeclaration.placeField(
poffset,
memsize, memalignsize, alignment,
&ad.structsize, &ad.alignsize,
isunion);
//printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
//printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
}
Expand Down
3 changes: 2 additions & 1 deletion src/dimport.d
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,8 @@ public:
if (mod.needmoduleinfo)
{
//printf("module5 %s because of %s\n", sc.module.toChars(), mod.toChars());
sc._module.needmoduleinfo = 1;
if (sc)
sc._module.needmoduleinfo = 1;
}
}
}
Expand Down
30 changes: 28 additions & 2 deletions src/dmodule.d
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ public:
extern (C++) static __gshared DsymbolTable modules; // symbol table of all modules
extern (C++) static __gshared Modules amodules; // array of all modules
extern (C++) static __gshared Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them
extern (C++) static __gshared Dsymbols deferred2; // deferred Dsymbol's needing semantic2() run on them
extern (C++) static __gshared Dsymbols deferred3; // deferred Dsymbol's needing semantic3() run on them
extern (C++) static __gshared uint dprogress; // progress resolving the deferred list

Expand Down Expand Up @@ -1131,6 +1132,18 @@ public:
deferred.push(s);
}

static void addDeferredSemantic2(Dsymbol s)
{
//printf("Module::addDeferredSemantic2('%s')\n", s.toChars());
deferred2.push(s);
}

static void addDeferredSemantic3(Dsymbol s)
{
//printf("Module::addDeferredSemantic3('%s')\n", s.toChars());
deferred3.push(s);
}

/******************************************
* Run semantic() on deferred symbols.
*/
Expand Down Expand Up @@ -1184,13 +1197,26 @@ public:
//printf("-Module::runDeferredSemantic(), len = %d\n", deferred.dim);
}

static void addDeferredSemantic3(Dsymbol s)
static void runDeferredSemantic2()
{
deferred3.push(s);
Module.runDeferredSemantic();

Dsymbols* a = &Module.deferred2;
for (size_t i = 0; i < a.dim; i++)
{
Dsymbol s = (*a)[i];
//printf("[%d] %s semantic2a\n", i, s.toPrettyChars());
s.semantic2(null);

if (global.errors)
break;
}
}

static void runDeferredSemantic3()
{
Module.runDeferredSemantic2();

Dsymbols* a = &Module.deferred3;
for (size_t i = 0; i < a.dim; i++)
{
Expand Down
151 changes: 49 additions & 102 deletions src/dstruct.d
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,6 @@ public:

if (semanticRun >= PASSsemanticdone)
return;
uint dprogress_save = Module.dprogress;
int errors = global.errors;

//printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", this, toPrettyChars(), sizeok);
Expand All @@ -296,7 +295,7 @@ public:
type = type.semantic(loc, sc);
if (type.ty == Tstruct && (cast(TypeStruct)type).sym != this)
{
TemplateInstance ti = (cast(TypeStruct)type).sym.isInstantiated();
auto ti = (cast(TypeStruct)type).sym.isInstantiated();
if (ti && isError(ti))
(cast(TypeStruct)type).sym = this;
}
Expand Down Expand Up @@ -331,13 +330,12 @@ public:
return;
}
if (!symtab)
{
symtab = new DsymbolTable();

if (sizeok == SIZEOKnone) // if not already done the addMember step
{
for (size_t i = 0; i < members.dim; i++)
{
Dsymbol s = (*members)[i];
auto s = (*members)[i];
//printf("adding member '%s' to '%s'\n", s.toChars(), this.toChars());
s.addMember(sc, this);
}
Expand All @@ -353,71 +351,45 @@ public:
sc2.structalign = STRUCTALIGN_DEFAULT;
sc2.userAttribDecl = null;

if (sizeok == SIZEOKdone)
goto LafterSizeok;
sizeok = SIZEOKnone;

/* Set scope so if there are forward references, we still might be able to
* resolve individual members like enums.
*/
for (size_t i = 0; i < members.dim; i++)
{
Dsymbol s = (*members)[i];
auto s = (*members)[i];
//printf("struct: setScope %s %s\n", s.kind(), s.toChars());
s.setScope(sc2);
}

for (size_t i = 0; i < members.dim; i++)
{
Dsymbol s = (*members)[i];
auto s = (*members)[i];
s.importAll(sc2);
}

for (size_t i = 0; i < members.dim; i++)
{
Dsymbol s = (*members)[i];
auto s = (*members)[i];
s.semantic(sc2);
}

finalizeSize();

if (sizeok == SIZEOKfwd)
if (!determineFields())
{
// semantic() failed because of forward references.
// Unwind what we did, and defer it for later
for (size_t i = 0; i < fields.dim; i++)
{
VarDeclaration v = fields[i];
v.offset = 0;
}
fields.setDim(0);
structsize = 0;
alignsize = 0;

assert(type.ty == Terror);
sc2.pop();

_scope = scx ? scx : sc.copy();
_scope.setNoFree();
_scope._module.addDeferredSemantic(this);
Module.dprogress = dprogress_save;
//printf("\tdeferring %s\n", toChars());
return;
}

Module.dprogress++;
//printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());

LafterSizeok:
// The additions of special member functions should have its own
// sub-semantic analysis pass, and have to be deferred sometimes.
// See the case in compilable/test14838.d
for (size_t i = 0; i < fields.dim; i++)
/* Following special member functions creation needs semantic analysis
* completion of sub-structs in each field types. For example, buildDtor
* needs to check existence of elaborate dtor in type of each fields.
* See the case in compilable/test14838.d
*/
foreach (v; fields)
{
VarDeclaration v = fields[i];
Type tb = v.type.baseElemOf();
if (tb.ty != Tstruct)
continue;
StructDeclaration sd = (cast(TypeStruct)tb).sym;
auto sd = (cast(TypeStruct)tb).sym;
if (sd.semanticRun >= PASSsemanticdone)
continue;

Expand All @@ -435,7 +407,8 @@ public:
aggNew = cast(NewDeclaration)search(Loc(), Id.classNew);
aggDelete = cast(DeleteDeclaration)search(Loc(), Id.classDelete);

// this->ctor is already set in finalizeSize()
// Look for the constructor
ctor = searchCtor();

dtor = buildDtor(this, sc2);
postblit = buildPostBlit(this, sc2);
Expand All @@ -449,6 +422,10 @@ public:

inv = buildInv(this, sc2);

Module.dprogress++;
semanticRun = PASSsemanticdone;
//printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());

sc2.pop();

if (ctor)
Expand All @@ -460,7 +437,7 @@ public:
sc = sc.push();
sc.tinst = null;
sc.minst = null;
FuncDeclaration fcall = resolveFuncCall(loc, sc, scall, null, null, null, 1);
auto fcall = resolveFuncCall(loc, sc, scall, null, null, null, 1);
sc = sc.pop();
global.endGagging(xerrors);

Expand All @@ -472,22 +449,6 @@ public:
}
}

Module.dprogress++;
semanticRun = PASSsemanticdone;

TypeTuple tup = toArgTypes(type);
size_t dim = tup.arguments.dim;
if (dim >= 1)
{
assert(dim <= 2);
arg1type = (*tup.arguments)[0].type;
if (dim == 2)
arg2type = (*tup.arguments)[1].type;
}

if (sc.func)
semantic2(sc);

if (global.errors != errors)
{
// The type is no good.
Expand Down Expand Up @@ -588,9 +549,12 @@ public:

override final void finalizeSize()
{
//printf("StructDeclaration::finalizeSize() %s\n", toChars());
if (sizeok != SIZEOKnone)
return;
//printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
assert(sizeok != SIZEOKdone);

//printf("+StructDeclaration::finalizeSize() %s, fields.dim = %d, sizeok = %d\n", toChars(), fields.dim, sizeok);

fields.setDim(0); // workaround

// Set the offsets of the fields and determine the size of the struct
uint offset = 0;
Expand All @@ -600,7 +564,7 @@ public:
Dsymbol s = (*members)[i];
s.setFieldOffset(this, &offset, isunion);
}
if (sizeok == SIZEOKfwd)
if (type.ty == Terror)
return;

// 0 sized struct's are set to 1 byte
Expand All @@ -617,56 +581,39 @@ public:
structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
else
structsize = (structsize + alignment - 1) & ~(alignment - 1);

sizeok = SIZEOKdone;

//printf("-StructDeclaration::finalizeSize() %s, fields.dim = %d, structsize = %d\n", toChars(), fields.dim, structsize);

// Calculate fields[i].overlapped
checkOverlappedFields();

// Determine if struct is all zeros or not
zeroInit = 1;
for (size_t i = 0; i < fields.dim; i++)
foreach (vd; fields)
{
VarDeclaration vd = fields[i];
if (!vd.isDataseg())
if (vd._init)
{
if (vd._init)
{
// Should examine init to see if it is really all 0's
zeroInit = 0;
break;
}
else
{
if (!vd.type.isZeroInit(loc))
{
zeroInit = 0;
break;
}
}
// Should examine init to see if it is really all 0's
zeroInit = 0;
break;
}
}

// Look for the constructor, for the struct literal/constructor call expression
ctor = searchCtor();
if (ctor)
{
// Finish all constructors semantics to determine this->noDefaultCtor.
struct SearchCtor
else if (!vd.type.isZeroInit(loc))
{
extern (C++) static int fp(Dsymbol s, void* ctxt)
{
CtorDeclaration f = s.isCtorDeclaration();
if (f && f.semanticRun == PASSinit)
f.semantic(null);
return 0;
}
zeroInit = 0;
break;
}
}

for (size_t i = 0; i < members.dim; i++)
{
Dsymbol s = (*members)[i];
s.apply(&SearchCtor.fp, null);
}
auto tt = toArgTypes(type);
size_t dim = tt.arguments.dim;
if (dim >= 1)
{
assert(dim <= 2);
arg1type = (*tt.arguments)[0].type;
if (dim == 2)
arg2type = (*tt.arguments)[1].type;
}
}

Expand Down
26 changes: 7 additions & 19 deletions src/dtemplate.d
Original file line number Diff line number Diff line change
Expand Up @@ -8196,7 +8196,7 @@ public:
//printf("test3: enclosing = %d, s->parent = %s\n", enclosing, s->parent->toChars());
s.semantic(sc2);
//printf("test4: enclosing = %d, s->parent = %s\n", enclosing, s->parent->toChars());
sc2._module.runDeferredSemantic();
Module.runDeferredSemantic();
}
}

Expand Down Expand Up @@ -8423,31 +8423,19 @@ public:
{
if (semanticRun == PASSinit) // forward reference had occured
{
/* Cannot handle forward references if mixin is a struct member,
* because addField must happen during struct's semantic, not
* during the mixin semantic.
* runDeferred will re-run mixin's semantic outside of the struct's
* semantic.
*/
AggregateDeclaration ad = toParent().isAggregateDeclaration();
if (ad)
ad.sizeok = SIZEOKfwd;
else
{
// Forward reference
//printf("forward reference - deferring\n");
_scope = scx ? scx : sc.copy();
_scope.setNoFree();
_scope._module.addDeferredSemantic(this);
}
//printf("forward reference - deferring\n");
_scope = scx ? scx : sc.copy();
_scope.setNoFree();
_scope._module.addDeferredSemantic(this);
return;
}

inst = this;
errors = true;
return; // error recovery
}
TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration();

auto tempdecl = this.tempdecl.isTemplateDeclaration();
assert(tempdecl);

if (!ident)
Expand Down
33 changes: 27 additions & 6 deletions src/expression.d
Original file line number Diff line number Diff line change
Expand Up @@ -5791,10 +5791,12 @@ public:

if (tb.ty == Tclass)
{
ClassDeclaration cd = (cast(TypeClass)tb).sym;
auto cd = (cast(TypeClass)tb).sym;
cd.size(loc);
if (cd.sizeok != SIZEOKdone)
return new ErrorExp();
if (!cd.ctor)
cd.ctor = cd.searchCtor();
if (cd.noDefaultCtor && !nargs && !cd.defaultCtor)
{
error("default construction is disabled for type %s", cd.type.toChars());
Expand Down Expand Up @@ -5960,10 +5962,12 @@ public:
}
else if (tb.ty == Tstruct)
{
StructDeclaration sd = (cast(TypeStruct)tb).sym;
auto sd = (cast(TypeStruct)tb).sym;
sd.size(loc);
if (sd.sizeok != SIZEOKdone)
return new ErrorExp();
if (!sd.ctor)
sd.ctor = sd.searchCtor();
if (sd.noDefaultCtor && !nargs)
{
error("default construction is disabled for type %s", sd.type.toChars());
Expand Down Expand Up @@ -6919,7 +6923,10 @@ public:
else if (sc.func)
{
// Bugzilla 11720 - include Dataseg variables
if ((s.isFuncDeclaration() || s.isAggregateDeclaration() || s.isEnumDeclaration() || v && v.isDataseg()) && !sc.func.localsymtab.insert(s))
if ((s.isFuncDeclaration() ||
s.isAggregateDeclaration() ||
s.isEnumDeclaration() ||
v && v.isDataseg()) && !sc.func.localsymtab.insert(s))
{
error("declaration %s is already defined in another scope in %s", s.toPrettyChars(), sc.func.toChars());
return new ErrorExp();
Expand Down Expand Up @@ -9400,6 +9407,8 @@ public:
sd.size(loc); // Resolve forward references to construct object
if (sd.sizeok != SIZEOKdone)
return new ErrorExp();
if (!sd.ctor)
sd.ctor = sd.searchCtor();

// First look for constructor
if (e1.op == TOKtype && sd.ctor)
Expand All @@ -9422,15 +9431,15 @@ public:
sle.useStaticInit = false;

Expression e = sle;
if (CtorDeclaration cf = sd.ctor.isCtorDeclaration())
if (auto cf = sd.ctor.isCtorDeclaration())
{
e = new DotVarExp(loc, e, cf, true);
}
else if (TemplateDeclaration td = sd.ctor.isTemplateDeclaration())
else if (auto td = sd.ctor.isTemplateDeclaration())
{
e = new DotTemplateExp(loc, e, td);
}
else if (OverloadSet os = sd.ctor.isOverloadSet())
else if (auto os = sd.ctor.isOverloadSet())
{
e = new DotExp(loc, e, new OverExp(loc, os));
}
Expand Down Expand Up @@ -12327,6 +12336,12 @@ public:
Type t2 = e2x.type.toBasetype();
if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym)
{
sd.size(loc);
if (sd.sizeok != SIZEOKdone)
return new ErrorExp();
if (!sd.ctor)
sd.ctor = sd.searchCtor();

// Bugzilla 15661: Look for the form from last of comma chain.
auto e2y = e2x;
while (e2y.op == TOKcomma)
Expand Down Expand Up @@ -12438,6 +12453,12 @@ public:
}
else if (!e2x.implicitConvTo(t1))
{
sd.size(loc);
if (sd.sizeok != SIZEOKdone)
return new ErrorExp();
if (!sd.ctor)
sd.ctor = sd.searchCtor();

if (sd.ctor)
{
/* Look for implicit constructor call
Expand Down
36 changes: 13 additions & 23 deletions src/func.d
Original file line number Diff line number Diff line change
Expand Up @@ -562,8 +562,6 @@ public:
_scope = null;
}

uint dprogress_save = Module.dprogress;

foverrides.setDim(0); // reset in case semantic() is being retried for this function

storage_class |= sc.stc & ~STCref;
Expand Down Expand Up @@ -975,11 +973,11 @@ public:
}
}
break;

case -2:
// can't determine because of fwd refs
cd.sizeok = SIZEOKfwd; // can't finish due to forward reference
Module.dprogress = dprogress_save;
// can't determine because of forward references
return;

default:
{
FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration();
Expand Down Expand Up @@ -1062,17 +1060,20 @@ public:
{
case -1:
break;

case -2:
cd.sizeok = SIZEOKfwd; // can't finish due to forward reference
Module.dprogress = dprogress_save;
// can't determine because of forward references
return;

default:
{
FuncDeclaration fdv = cast(FuncDeclaration)b.sym.vtbl[vi];
auto fdv = cast(FuncDeclaration)b.sym.vtbl[vi];
Type ti = null;

/* Remember which functions this overrides
*/
foverrides.push(fdv);

/* Should we really require 'override' when implementing
* an interface function?
*/
Expand All @@ -1085,20 +1086,8 @@ public:
/* Only need to have a tintro if the vptr
* offsets differ
*/
uint errors = global.errors;
global.gag++; // suppress printing of error messages
int offset;
int baseOf = fdv.type.nextOf().isBaseOf(type.nextOf(), &offset);
global.gag--; // suppress printing of error messages
if (errors != global.errors)
{
// any error in isBaseOf() is a forward reference error, so we bail out
global.errors = errors;
cd.sizeok = SIZEOKfwd; // can't finish due to forward reference
Module.dprogress = dprogress_save;
return;
}
if (baseOf)
if (fdv.type.nextOf().isBaseOf(type.nextOf(), &offset))
{
ti = fdv.type;
}
Expand Down Expand Up @@ -1691,9 +1680,10 @@ public:
// Verify that all the ctorinit fields got initialized
if (!(sc2.callSuper & CSXthis_ctor))
{
for (size_t i = 0; i < ad2.fields.dim; i++)
foreach (i, v; ad2.fields)
{
VarDeclaration v = ad2.fields[i];
if (v.isThisDeclaration())
continue;
if (v.ctorinit == 0)
{
/* Current bugs in the flow analysis:
Expand Down
17 changes: 14 additions & 3 deletions src/mars.d
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,7 @@ Language changes listed by -transition=id:
}
if (global.errors)
fatal();

if (global.params.doHdrGeneration)
{
/* Generate 'header' import files.
Expand All @@ -1411,6 +1412,7 @@ Language changes listed by -transition=id:
}
if (global.errors)
fatal();

// load all unconditional imports for better symbol resolving
for (size_t i = 0; i < modules.dim; i++)
{
Expand All @@ -1421,7 +1423,9 @@ Language changes listed by -transition=id:
}
if (global.errors)
fatal();

backend_init();

// Do semantic analysis
for (size_t i = 0; i < modules.dim; i++)
{
Expand All @@ -1430,8 +1434,8 @@ Language changes listed by -transition=id:
fprintf(global.stdmsg, "semantic %s\n", m.toChars());
m.semantic();
}
if (global.errors)
fatal();
//if (global.errors)
// fatal();
Module.dprogress = 1;
Module.runDeferredSemantic();
if (Module.deferred.dim)
Expand All @@ -1441,8 +1445,9 @@ Language changes listed by -transition=id:
Dsymbol sd = Module.deferred[i];
sd.error("unable to resolve forward reference in definition");
}
fatal();
//fatal();
}

// Do pass 2 semantic analysis
for (size_t i = 0; i < modules.dim; i++)
{
Expand All @@ -1451,8 +1456,10 @@ Language changes listed by -transition=id:
fprintf(global.stdmsg, "semantic2 %s\n", m.toChars());
m.semantic2();
}
Module.runDeferredSemantic2();
if (global.errors)
fatal();

// Do pass 3 semantic analysis
for (size_t i = 0; i < modules.dim; i++)
{
Expand All @@ -1464,6 +1471,7 @@ Language changes listed by -transition=id:
Module.runDeferredSemantic3();
if (global.errors)
fatal();

// Scan for functions to inline
if (global.params.useInline)
{
Expand All @@ -1478,6 +1486,7 @@ Language changes listed by -transition=id:
// Do not attempt to generate output files if errors or warnings occurred
if (global.errors || global.warnings)
fatal();

// inlineScan incrementally run semantic3 of each expanded functions.
// So deps file generation should be moved after the inlinig stage.
if (global.params.moduleDeps)
Expand All @@ -1492,7 +1501,9 @@ Language changes listed by -transition=id:
else
printf("%.*s", cast(int)ob.offset, ob.data);
}

printCtfePerformanceStats();

Library library = null;
if (global.params.lib)
{
Expand Down
5 changes: 4 additions & 1 deletion src/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class Module : public Package
static DsymbolTable *modules; // symbol table of all modules
static Modules amodules; // array of all modules
static Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them
static Dsymbols deferred2; // deferred Dsymbol's needing semantic2() run on them
static Dsymbols deferred3; // deferred Dsymbol's needing semantic3() run on them
static unsigned dprogress; // progress resolving the deferred list
static void init();
Expand Down Expand Up @@ -135,8 +136,10 @@ class Module : public Package
Dsymbol *symtabInsert(Dsymbol *s);
void deleteObjFile();
static void addDeferredSemantic(Dsymbol *s);
static void runDeferredSemantic();
static void addDeferredSemantic2(Dsymbol *s);
static void addDeferredSemantic3(Dsymbol *s);
static void runDeferredSemantic();
static void runDeferredSemantic2();
static void runDeferredSemantic3();
static void clearCache();
int imports(Module *m);
Expand Down
6 changes: 5 additions & 1 deletion src/mtype.d
Original file line number Diff line number Diff line change
Expand Up @@ -2500,6 +2500,10 @@ public:
{
if (v.isField())
{
auto ad = v.toParent().isAggregateDeclaration();
ad.size(e.loc);
if (ad.sizeok != SIZEOKdone)
return new ErrorExp();
e = new IntegerExp(e.loc, v.offset, Type.tsize_t);
return e;
}
Expand Down Expand Up @@ -8020,7 +8024,7 @@ public:
override structalign_t alignment()
{
if (sym.alignment == 0)
sym.size(Loc());
sym.size(sym.loc);
return sym.alignment;
}

Expand Down
3 changes: 2 additions & 1 deletion src/statement.d
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import ddmd.declaration;
import ddmd.denum;
import ddmd.dimport;
import ddmd.dinterpret;
import ddmd.dmodule;
import ddmd.dscope;
import ddmd.dsymbol;
import ddmd.dtemplate;
Expand Down Expand Up @@ -5948,7 +5949,7 @@ public:
s.aliasdecls.push(ad);
}
s.semantic(sc);
//s->semantic2(sc); // Bugzilla 14666
Module.addDeferredSemantic2(s); // Bugzilla 14666
sc.insert(s);
foreach (aliasdecl; s.aliasdecls)
{
Expand Down
5 changes: 2 additions & 3 deletions src/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -777,10 +777,9 @@ extern (C++) Expression semanticTraits(TraitsExp e, Scope* sc)
e.error("first argument is not a class");
return new ErrorExp();
}
if (cd.sizeok == SIZEOKnone)
if (cd.sizeok != SIZEOKdone)
{
if (cd._scope)
cd.semantic(cd._scope);
cd.size(e.loc);
}
if (cd.sizeok != SIZEOKdone)
{
Expand Down
223 changes: 223 additions & 0 deletions test/compilable/testfwdref.d
Original file line number Diff line number Diff line change
Expand Up @@ -491,3 +491,226 @@ class Frop14609 : Foo14609!int
{
public int bar() { return 0; }
}

/***************************************************/
// test case 1, comes from Phobos
/*
TEST_OUTPUT:
---
+alias Alias12540
+anySatisfy, T.length == 1
+isStaticArray
+T.stringof in StaticArrayTypeOf
-T.stringof in StaticArrayTypeOf
-isStaticArray
+hasElaborateCpCtor S == struct or else
-hasElaborateCpCtor S == struct or else
-anySatisfy, T.length == 1
-alias Alias12540
---
*/

template anySatisfy15726x(alias F, T...)
{
//static if (T.length == 1)
//{
pragma(msg, "+anySatisfy, T.length == 1");
enum anySatisfy15726x = F!(T[0]);
pragma(msg, "-anySatisfy, T.length == 1");
//}
}

template StaticArrayTypeOf15726x(T)
{
alias X = T;

static if (is(X : E[n], E, size_t n))
{
//alias StaticArrayTypeOf15726x = X;
}
else
{
pragma(msg, "+T.stringof in StaticArrayTypeOf");
// Fixed: T.stringof (T == Class12540) should not invoke
// T.size() in ClassDeclaration.search().
static assert(0, T.stringof~" is not a static array type");
pragma(msg, "-T.stringof in StaticArrayTypeOf");
}
}

//enum bool isStaticArray(T) = is(StaticArrayTypeOf15726x!T);
template isStaticArray15726x(T)
{
pragma(msg, "+isStaticArray");
enum bool isStaticArray15726x = is(StaticArrayTypeOf15726x!T);
pragma(msg, "-isStaticArray");
}

template hasElaborateCpCtor15726x(S)
{
static if (isStaticArray15726x!S && S.length)
{
//pragma(msg, "X+");
enum bool hasElaborateCpCtor15726x =
hasElaborateCpCtor15726x!(typeof(S.init[0]));
//pragma(msg, "X-");
}
else
{
pragma(msg, "+hasElaborateCpCtor S == struct or else");
static if (is(S == struct))
{
enum bool hasElaborateCpCtor15726x = true;
//enum hasElaborateCpCtor15726x = hasMember!(S, "__postblit")
// || anySatisfy15726x!(.hasElaborateCpCtor15726x, FieldTypeTuple!S);
}
else
{
enum bool hasElaborateCpCtor15726x = false;
}
pragma(msg, "-hasElaborateCpCtor S == struct or else");
}
}

struct VariantN15726x(AllowedTypesParam...)
{
alias AllowedTypes = AllowedTypesParam;

static if (!AllowedTypes.length ||
anySatisfy15726x!(hasElaborateCpCtor15726x, AllowedTypes))
{
}
}

template Algebraic15726x(T)
{
alias Algebraic15726x = VariantN15726x!(T);
}

void test15726x()
{
static struct DummyScope
{
pragma(msg, "+alias Alias12540");
alias Alias12540 = Algebraic15726x!Class12540;
pragma(msg, "-alias Alias12540");
static class Class12540
{
Alias12540 entity;
}
}
}

/***************************************************/
// test case 2, comes from Phobos

struct RefCounted15726y(T)
{
struct RefCountedStore
{
struct Impl
{
T _payload;
}
Impl* _store;
}
RefCountedStore _refCounted;

this(this) {}

~this()
{
_refCounted._store._payload.__xdtor();
}
}

struct RangeT15726y(A)
{
A[1] _outer_;
alias RC = RangeT15726y!(const(A));
}

struct Array15726y(T)
{
struct Payload
{
~this();
}

alias Data = RefCounted15726y!(Payload);
Data _data;

alias Range = RangeT15726y!Array15726y;
}

void test15726y()
{
alias Range = RangeT15726y!(Array15726y!int);
Range r;
r = r; // opAssign
}

/***************************************************/
// 15726

struct RC15726(T)
{
struct Impl
{
T _payload;
}

Impl* _store;

~this()
{
destroy15726a(_store._payload);
}
}

// ----

struct Con15726a(T)
{
alias Stmt15726a = .Stmt15726a!T;
}

struct Stmt15726a(T)
{
alias Con15726a = .Con15726a!T;

RC15726!Payload data;

struct Payload
{
Con15726a con;
}
}

Con15726a!int x15726a;

void destroy15726a(T)(ref T obj) @trusted
{
auto buf = (cast(ubyte*)&obj)[0 .. T.sizeof];
}

// ----

struct Util15726b(C, S) {}

struct Con15726b(T)
{
alias Util15726b = .Util15726b!(Con15726b!T, Stmt15726b!T);
}

struct Stmt15726b(T)
{
struct Payload
{
Con15726b!T con;
}

RC15726!Payload data;
}

Con15726b!int x15726b;
2 changes: 1 addition & 1 deletion test/fail_compilation/fail42.d
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail42.d(20): Error: struct fail42.Yuiop no size yet for forward reference
fail_compilation/fail42.d(22): Error: struct fail42.Qwert no size because of forward reference
---
*/

Expand Down