252 changes: 204 additions & 48 deletions src/dclass.d
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,21 @@ struct BaseClass
extern (C++) bool fillVtbl(ClassDeclaration cd, FuncDeclarations* vtbl, int newinstance)
{
bool result = false;

//printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", sym->toChars(), cd->toChars());
if (vtbl)
vtbl.setDim(sym.vtbl.dim);

// first entry is ClassInfo reference
for (size_t j = sym.vtblOffset(); j < sym.vtbl.dim; j++)
{
FuncDeclaration ifd = sym.vtbl[j].isFuncDeclaration();
FuncDeclaration fd;
TypeFunction tf;

//printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null");
assert(ifd);

// Find corresponding function in this class
tf = (ifd.type.ty == Tfunction) ? cast(TypeFunction)ifd.type : null;
assert(tf); // should always be non-null
Expand All @@ -93,9 +97,11 @@ struct BaseClass
// Check that calling conventions match
if (fd.linkage != ifd.linkage)
fd.error("linkage doesn't match interface function");

// Check that it is current
if (newinstance && fd.toParent() != cd && ifd.toParent() == sym)
cd.error("interface function '%s' is not implemented", ifd.toFullSignature());

if (fd.toParent() == cd)
result = true;
}
Expand All @@ -105,6 +111,7 @@ struct BaseClass
// BUG: should mark this class as abstract?
if (!cd.isAbstract())
cd.error("interface function '%s' is not implemented", ifd.toFullSignature());

fd = null;
}
if (vtbl)
Expand All @@ -125,8 +132,10 @@ struct BaseClass
{
BaseClass* b = &baseInterfaces[i];
BaseClass* b2 = sym.interfaces[i];

assert(b2.vtbl.dim == 0); // should not be filled yet
memcpy(b, b2, BaseClass.sizeof);

if (i) // single inheritance is i==0
vtblInterfaces.push(b); // only need for M.I.
b.copyBaseInterfaces(vtblInterfaces);
Expand Down Expand Up @@ -204,22 +213,28 @@ public:
final extern (D) this(Loc loc, Identifier id, BaseClasses* baseclasses, bool inObject = false)
{
super(loc, id);

static __gshared const(char)* msg = "only object.d can define this reserved class name";

if (baseclasses)
{
// Actually, this is a transfer
this.baseclasses = baseclasses;
}
else
this.baseclasses = new BaseClasses();

//printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses->dim);

// For forward references
type = new TypeClass(this);

if (id)
{
// Look for special class names
if (id == Id.__sizeof || id == Id.__xalignof || id == Id._mangleof)
error("illegal class name");

// BUG: What if this is the wrong TypeInfo, i.e. it is nested?
if (id.toChars()[0] == 'T')
{
Expand Down Expand Up @@ -326,12 +341,14 @@ public:
Type.typeinfovector = this;
}
}

if (id == Id.Object)
{
if (!inObject)
error("%s", msg);
object = this;
}

if (id == Id.Throwable)
{
if (!inObject)
Expand All @@ -357,15 +374,20 @@ public:
override Dsymbol syntaxCopy(Dsymbol s)
{
//printf("ClassDeclaration::syntaxCopy('%s')\n", toChars());
ClassDeclaration cd = s ? cast(ClassDeclaration)s : new ClassDeclaration(loc, ident, null);
ClassDeclaration cd =
s ? cast(ClassDeclaration)s
: new ClassDeclaration(loc, ident, null);

cd.storage_class |= storage_class;

cd.baseclasses.setDim(this.baseclasses.dim);
for (size_t i = 0; i < cd.baseclasses.dim; i++)
{
BaseClass* b = (*this.baseclasses)[i];
auto b2 = new BaseClass(b.type.syntaxCopy(), b.protection);
(*cd.baseclasses)[i] = b2;
}

return ScopeDsymbol.syntaxCopy(cd);
}

Expand All @@ -374,42 +396,52 @@ public:
//printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
//printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : "");
//printf("sc->stc = %x\n", sc->stc);

//{ static int n; if (++n == 20) *(char*)0=0; }

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);

Scope* scx = null;
if (_scope)
{
sc = _scope;
scx = _scope; // save so we don't make redundant copies
_scope = null;
}

if (!parent)
{
assert(sc.parent && (sc.func || !ident));
parent = sc.parent;

if (!ident) // if anonymous class
{
const(char)* id = "__anonclass";
ident = Identifier.generateId(id);
}
}
assert(parent && !isAnonymous());

type = type.semantic(loc, sc);
if (type.ty == Tclass && (cast(TypeClass)type).sym != this)
{
TemplateInstance ti = (cast(TypeClass)type).sym.isInstantiated();
if (ti && isError(ti))
(cast(TypeClass)type).sym = this;
}

// Ungag errors when not speculative
Ungag ungag = ungagSpeculative();

if (semanticRun == PASSinit)
{
protection = sc.protection;

storage_class |= sc.stc;
if (storage_class & STCdeprecated)
isdeprecated = true;
Expand All @@ -419,7 +451,9 @@ public:
isscope = true;
if (storage_class & STCabstract)
isabstract = true;

userAttribDecl = sc.userAttribDecl;

if (sc.linkage == LINKcpp)
cpp = true;
if (sc.linkage == LINKobjc)
Expand All @@ -431,19 +465,24 @@ public:
return;
}
semanticRun = PASSsemantic;

if (baseok < BASEOKdone)
{
baseok = BASEOKin;

// Expand any tuples in baseclasses[]
for (size_t i = 0; i < baseclasses.dim;)
{
_scope = scx ? scx : sc.copy();
_scope.setNoFree();

BaseClass* b = (*baseclasses)[i];
//printf("+ %s [%d] b->type = %s\n", toChars(), i, b->type->toChars());
b.type = b.type.semantic(loc, sc);
//printf("- %s [%d] b->type = %s\n", toChars(), i, b->type->toChars());

_scope = null;

Type tb = b.type.toBasetype();
if (tb.ty == Ttuple)
{
Expand All @@ -461,13 +500,15 @@ public:
else
i++;
}

if (baseok >= BASEOKdone)
{
//printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun);
if (semanticRun >= PASSsemanticdone)
return;
goto Lancestorsdone;
}

// See if there's a base class as first in baseclasses[]
if (baseclasses.dim)
{
Expand All @@ -492,6 +533,7 @@ public:
}
if (tc.sym.isInterfaceDeclaration())
goto L7;

for (ClassDeclaration cdb = tc.sym; cdb; cdb = cdb.baseClass)
{
if (cdb == this)
Expand All @@ -501,13 +543,15 @@ public:
goto L7;
}
}

/* Bugzilla 11034: Essentially, class inheritance hierarchy
* and instance size of each classes are orthogonal information.
* Therefore, even if tc->sym->sizeof == SIZEOKnone,
* we need to set baseClass field for class covariance check.
*/
baseClass = tc.sym;
b.sym = baseClass;

if (tc.sym._scope && tc.sym.baseok < BASEOKdone)
tc.sym.semantic(null); // Try to resolve forward reference
if (tc.sym.baseok < BASEOKdone)
Expand All @@ -519,6 +563,7 @@ public:
}
L7:
}

// Treat the remaining entries in baseclasses as interfaces
// Check for errors, handle forward references
for (size_t i = (baseClass ? 1 : 0); i < baseclasses.dim;)
Expand All @@ -533,6 +578,7 @@ public:
baseclasses.remove(i);
continue;
}

// Check for duplicate interfaces
for (size_t j = (baseClass ? 1 : 0); j < i; j++)
{
Expand All @@ -553,7 +599,9 @@ public:
tc.checkDeprecated(loc, sc);
}
}

b.sym = tc.sym;

if (tc.sym._scope && tc.sym.baseok < BASEOKdone)
tc.sym.semantic(null); // Try to resolve forward reference
if (tc.sym.baseok < BASEOKdone)
Expand All @@ -575,6 +623,7 @@ public:
return;
}
baseok = BASEOKdone;

// If no base class, and this is not an Object, use Object as base class
if (!baseClass && ident != Id.Object && !cpp)
{
Expand All @@ -583,12 +632,15 @@ public:
error("missing or corrupt object.d");
fatal();
}

Type t = object.type;
t = t.semantic(loc, sc).toBasetype();
assert(t.ty == Tclass);
TypeClass tc = cast(TypeClass)t;

auto b = new BaseClass(tc, Prot(PROTpublic));
baseclasses.shift(b);

baseClass = tc.sym;
assert(!baseClass.isInterfaceDeclaration());
b.sym = baseClass;
Expand All @@ -597,6 +649,7 @@ public:
{
if (baseClass.storage_class & STCfinal)
error("cannot inherit from final class %s", baseClass.toChars());

// Inherit properties from base class
if (baseClass.isCOMclass())
com = true;
Expand All @@ -607,6 +660,7 @@ public:
enclosing = baseClass.enclosing;
storage_class |= baseClass.storage_class & STC_TYPECTOR;
}

interfaces_dim = baseclasses.dim - (baseClass ? 1 : 0);
interfaces = baseclasses.tdata() + (baseClass ? 1 : 0);
for (size_t i = 0; i < interfaces_dim; i++)
Expand All @@ -618,13 +672,15 @@ public:
com = true;
if (cpp && !b.sym.isCPPinterface())
{
.error(loc, "C++ class '%s' cannot implement D interface '%s'", toPrettyChars(), b.sym.toPrettyChars());
.error(loc, "C++ class '%s' cannot implement D interface '%s'",
toPrettyChars(), b.sym.toPrettyChars());
}
}
interfaceSemantic(sc);
}
Lancestorsdone:
//printf("\tClassDeclaration::semantic(%s) baseok = %d\n", toChars(), baseok);

if (!members) // if opaque declaration
{
semanticRun = PASSsemanticdone;
Expand All @@ -633,6 +689,7 @@ public:
if (!symtab)
{
symtab = new DsymbolTable();

/* Bugzilla 12152: The semantic analysis of base classes should be finished
* before the members semantic analysis of this class, in order to determine
* vtbl in this class. However if a base class refers the member of this class,
Expand All @@ -644,6 +701,7 @@ public:
Dsymbol s = (*members)[i];
s.addMember(sc, this);
}

Scope* sc2 = sc.push(this);
sc2.stc &= STCsafe | STCtrusted | STCsystem;
sc2.parent = this;
Expand All @@ -659,6 +717,7 @@ public:
sc2.explicitProtection = 0;
sc2.structalign = STRUCTALIGN_DEFAULT;
sc2.userAttribDecl = null;

/* Set scope so if there are forward references, we still might be able to
* resolve individual members like enums.
*/
Expand All @@ -668,6 +727,7 @@ public:
//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++)
Expand All @@ -688,15 +748,18 @@ public:
return;
}
}

if (baseok == BASEOKdone)
{
baseok = BASEOKsemanticdone;

// initialize vtbl
if (baseClass)
{
// Copy vtbl[] from base class
vtbl.setDim(baseClass.vtbl.dim);
memcpy(vtbl.tdata(), baseClass.vtbl.tdata(), (void*).sizeof * vtbl.dim);

vthis = baseClass.vthis;
}
else
Expand All @@ -706,6 +769,7 @@ public:
if (vtblOffset())
vtbl.push(this); // leave room for classinfo as first member
}

/* If this is a nested class, add the hidden 'this'
* member which is a pointer to the enclosing scope.
*/
Expand All @@ -714,25 +778,35 @@ public:
// Use the base class's 'this' member
if (storage_class & STCstatic)
error("static class cannot inherit from nested class %s", baseClass.toChars());
if (toParent2() != baseClass.toParent2() && (!toParent2() || !baseClass.toParent2().getType() || !baseClass.toParent2().getType().isBaseOf(toParent2().getType(), null)))
if (toParent2() != baseClass.toParent2() &&
(!toParent2() ||
!baseClass.toParent2().getType() ||
!baseClass.toParent2().getType().isBaseOf(toParent2().getType(), null)))
{
if (toParent2())
{
error("is nested within %s, but super class %s is nested within %s", toParent2().toChars(), baseClass.toChars(), baseClass.toParent2().toChars());
error("is nested within %s, but super class %s is nested within %s",
toParent2().toChars(),
baseClass.toChars(),
baseClass.toParent2().toChars());
}
else
{
error("is not nested, but super class %s is nested within %s", baseClass.toChars(), baseClass.toParent2().toChars());
error("is not nested, but super class %s is nested within %s",
baseClass.toChars(),
baseClass.toParent2().toChars());
}
enclosing = null;
}
}
else
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;
Expand All @@ -755,17 +829,21 @@ public:
sc2.explicitProtection = 0;
sc2.structalign = STRUCTALIGN_DEFAULT;
sc2.userAttribDecl = null;

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

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

finalizeSize(sc2);

if (sizeok == SIZEOKfwd)
{
// semantic() failed due to forward references
Expand All @@ -778,53 +856,58 @@ public:
fields.setDim(0);
structsize = 0;
alignsize = 0;

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
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++)
{
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++)
{
VarDeclaration v = fields[i];
Type tb = v.type.baseElemOf();
if (tb.ty != Tstruct)
continue;
StructDeclaration sd = (cast(TypeStruct)tb).sym;
if (sd.semanticRun >= PASSsemanticdone)
continue;
VarDeclaration v = fields[i];
Type tb = v.type.baseElemOf();
if (tb.ty != Tstruct)
continue;
StructDeclaration sd = (cast(TypeStruct)tb).sym;
if (sd.semanticRun >= PASSsemanticdone)
continue;

sc2.pop();
sc2.pop();

_scope = scx ? scx : sc.copy();
_scope.setNoFree();
_scope._module.addDeferredSemantic(this);
_scope = scx ? scx : sc.copy();
_scope.setNoFree();
_scope._module.addDeferredSemantic(this);

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

/* Look for special member functions.
* They must be in this class, not in a base class.
*/
// Can be in base class
aggNew = cast(NewDeclaration)search(Loc(), Id.classNew);
aggDelete = cast(DeleteDeclaration)search(Loc(), Id.classDelete);

// this->ctor is already set in finalizeSize()

if (!ctor && noDefaultCtor)
{
// A class object is always created by constructor, so this check is legitimate.
Expand All @@ -835,6 +918,7 @@ public:
.error(v.loc, "field %s must be initialized in constructor", v.toChars());
}
}

// If this class has no constructor, but base class has a default
// ctor, create a constructor:
// this() { }
Expand All @@ -860,17 +944,23 @@ public:
}
else
{
error("cannot implicitly generate a default ctor when base class %s is missing a default ctor", baseClass.toPrettyChars());
error("cannot implicitly generate a default ctor when base class %s is missing a default ctor",
baseClass.toPrettyChars());
}
}

dtor = buildDtor(this, sc2);

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

inv = buildInv(this, sc2);

sc2.pop();

if (global.errors != errors)
{
// The type is no good.
Expand All @@ -879,11 +969,13 @@ public:
if (deferred)
deferred.errors = true;
}

if (deferred && !global.gag)
{
deferred.semantic2(sc);
deferred.semantic3(sc);
}

version (none)
{
if (type.ty == Tclass && (cast(TypeClass)type).sym != this)
Expand Down Expand Up @@ -934,8 +1026,10 @@ public:
if (!cd.baseClass && cd._scope)
cd.error("base class is forward referenced by %s", toChars());
}

if (this == cd.baseClass)
return true;

cd = cd.baseClass;
}
return false;
Expand Down Expand Up @@ -964,12 +1058,14 @@ public:
--inuse;
}
}

if (!members || !symtab) // opaque or addMember is not yet done
{
error("is forward referenced when looking for '%s'", ident.toChars());
//*(char*)0=0;
return null;
}

Dsymbol s = ScopeDsymbol.search(loc, ident, flags);
if (!s)
{
Expand Down Expand Up @@ -1017,10 +1113,12 @@ public:
{
if (sizeok != SIZEOKnone)
return;

// Set the offsets of the fields and determine the size of the class
if (baseClass)
{
assert(baseClass.sizeok == SIZEOKdone);

alignsize = baseClass.alignsize;
structsize = baseClass.structsize;
if (cpp && global.params.isWindows)
Expand Down Expand Up @@ -1119,6 +1217,7 @@ public:
//printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars());
FuncDeclaration fdmatch = null;
FuncDeclaration fdambig = null;

ClassDeclaration cd = this;
Dsymbols* vtbl = &cd.vtbl;
while (1)
Expand All @@ -1128,6 +1227,7 @@ public:
FuncDeclaration fd = (*vtbl)[i].isFuncDeclaration();
if (!fd)
continue;

// the first entry might be a ClassInfo
//printf("\t[%d] = %s\n", i, fd->toChars());
if (ident == fd.ident && fd.type.covariant(tf) == 1)
Expand All @@ -1137,39 +1237,43 @@ public:
goto Lfd;
if (fd == fdmatch)
goto Lfdmatch;

{
// Function type matcing: exact > covariant
MATCH m1 = tf.equals(fd.type) ? MATCHexact : MATCHnomatch;
MATCH m2 = tf.equals(fdmatch.type) ? MATCHexact : MATCHnomatch;
if (m1 > m2)
goto Lfd;
else if (m1 < m2)
goto Lfdmatch;
// Function type matcing: exact > covariant
MATCH m1 = tf.equals(fd.type) ? MATCHexact : MATCHnomatch;
MATCH m2 = tf.equals(fdmatch.type) ? MATCHexact : MATCHnomatch;
if (m1 > m2)
goto Lfd;
else if (m1 < m2)
goto Lfdmatch;
}
{
MATCH m1 = (tf.mod == fd.type.mod) ? MATCHexact : MATCHnomatch;
MATCH m2 = (tf.mod == fdmatch.type.mod) ? MATCHexact : MATCHnomatch;
if (m1 > m2)
goto Lfd;
else if (m1 < m2)
goto Lfdmatch;
MATCH m1 = (tf.mod == fd.type.mod) ? MATCHexact : MATCHnomatch;
MATCH m2 = (tf.mod == fdmatch.type.mod) ? MATCHexact : MATCHnomatch;
if (m1 > m2)
goto Lfd;
else if (m1 < m2)
goto Lfdmatch;
}
{
// The way of definition: non-mixin > mixin
MATCH m1 = fd.parent.isClassDeclaration() ? MATCHexact : MATCHnomatch;
MATCH m2 = fdmatch.parent.isClassDeclaration() ? MATCHexact : MATCHnomatch;
if (m1 > m2)
goto Lfd;
else if (m1 < m2)
goto Lfdmatch;
// The way of definition: non-mixin > mixin
MATCH m1 = fd.parent.isClassDeclaration() ? MATCHexact : MATCHnomatch;
MATCH m2 = fdmatch.parent.isClassDeclaration() ? MATCHexact : MATCHnomatch;
if (m1 > m2)
goto Lfd;
else if (m1 < m2)
goto Lfdmatch;
}

fdambig = fd;
//printf("Lambig fdambig = %s %s [%s]\n", fdambig->toChars(), fdambig->type->toChars(), fdambig->loc.toChars());
continue;

Lfd:
fdmatch = fd, fdambig = null;
//printf("Lfd fdmatch = %s %s [%s]\n", fdmatch->toChars(), fdmatch->type->toChars(), fdmatch->loc.toChars());
continue;

Lfdmatch:
continue;
}
Expand All @@ -1182,6 +1286,7 @@ public:
}
if (fdambig)
error("ambiguous virtual function %s", fdambig.toChars());

return fdmatch;
}

Expand All @@ -1200,23 +1305,28 @@ public:
final uint setBaseInterfaceOffsets(uint baseOffset)
{
assert(vtblInterfaces); // Bugzilla 12984

// set the offset of base interfaces from this (most derived) class/interface.
uint offset = baseOffset;

//if (vtblInterfaces->dim) printf("\n%s->finalizeSize()\n", toChars());
for (size_t i = 0; i < vtblInterfaces.dim; i++)
{
BaseClass* b = (*vtblInterfaces)[i];
uint thissize = Target.ptrsize;

alignmember(STRUCTALIGN_DEFAULT, thissize, &offset);
b.offset = offset;
//printf("\tvtblInterfaces[%d] b->sym = %s, offset = %d\n", i, b->sym->toChars(), b->offset);

// Take care of single inheritance offsets
while (b.baseInterfaces_dim)
{
b = &b.baseInterfaces[0];
b.offset = offset;
//printf("\tvtblInterfaces[%d] + sym = %s, offset = %d\n", i, b->sym->toChars(), b->offset);
}

offset += thissize;
if (alignsize < thissize)
alignsize = thissize;
Expand Down Expand Up @@ -1324,7 +1434,9 @@ public:

override Dsymbol syntaxCopy(Dsymbol s)
{
InterfaceDeclaration id = s ? cast(InterfaceDeclaration)s : new InterfaceDeclaration(loc, ident, null);
InterfaceDeclaration id =
s ? cast(InterfaceDeclaration)s
: new InterfaceDeclaration(loc, ident, null);
return ClassDeclaration.syntaxCopy(id);
}

Expand All @@ -1334,34 +1446,41 @@ public:
if (semanticRun >= PASSsemanticdone)
return;
int errors = global.errors;

Scope* scx = null;
if (_scope)
{
sc = _scope;
scx = _scope; // save so we don't make redundant copies
_scope = null;
}

if (!parent)
{
assert(sc.parent && sc.func);
parent = sc.parent;
}
assert(parent && !isAnonymous());

type = type.semantic(loc, sc);
if (type.ty == Tclass && (cast(TypeClass)type).sym != this)
{
TemplateInstance ti = (cast(TypeClass)type).sym.isInstantiated();
if (ti && isError(ti))
(cast(TypeClass)type).sym = this;
}

// Ungag errors when not speculative
Ungag ungag = ungagSpeculative();

if (semanticRun == PASSinit)
{
protection = sc.protection;

storage_class |= sc.stc;
if (storage_class & STCdeprecated)
isdeprecated = true;

userAttribDecl = sc.userAttribDecl;
}
else if (symtab)
Expand All @@ -1373,17 +1492,22 @@ public:
}
}
semanticRun = PASSsemantic;

if (baseok < BASEOKdone)
{
baseok = BASEOKin;

// Expand any tuples in baseclasses[]
for (size_t i = 0; i < baseclasses.dim;)
{
_scope = scx ? scx : sc.copy();
_scope.setNoFree();

BaseClass* b = (*baseclasses)[i];
b.type = b.type.semantic(loc, sc);

_scope = null;

Type tb = b.type.toBasetype();
if (tb.ty == Ttuple)
{
Expand All @@ -1401,16 +1525,20 @@ public:
else
i++;
}

if (baseok >= BASEOKdone)
{
//printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun);
if (semanticRun >= PASSsemanticdone)
return;
goto Lancestorsdone;
}

if (!baseclasses.dim && sc.linkage == LINKcpp)
cpp = true;

objc_InterfaceDeclaration_semantic_objcExtern(this, sc);

// Check for errors, handle forward references
for (size_t i = 0; i < baseclasses.dim;)
{
Expand All @@ -1424,6 +1552,7 @@ public:
baseclasses.remove(i);
continue;
}

// Check for duplicate interfaces
for (size_t j = 0; j < i; j++)
{
Expand All @@ -1450,7 +1579,9 @@ public:
tc.checkDeprecated(loc, sc);
}
}

b.sym = tc.sym;

if (tc.sym._scope && tc.sym.baseok < BASEOKdone)
tc.sym.semantic(null); // Try to resolve forward reference
if (tc.sym.baseok < BASEOKdone)
Expand All @@ -1471,6 +1602,7 @@ public:
return;
}
baseok = BASEOKdone;

interfaces_dim = baseclasses.dim;
interfaces = baseclasses.tdata();
for (size_t i = 0; i < interfaces_dim; i++)
Expand All @@ -1483,16 +1615,19 @@ public:
if (b.sym.isCPPinterface())
cpp = true;
}

interfaceSemantic(sc);
}
Lancestorsdone:

if (!members) // if opaque declaration
{
semanticRun = PASSsemanticdone;
return;
}
if (!symtab)
symtab = new DsymbolTable();

for (size_t i = 0; i < baseclasses.dim; i++)
{
BaseClass* b = (*baseclasses)[i];
Expand All @@ -1510,22 +1645,27 @@ public:
return;
}
}

if (baseok == BASEOKdone)
{
baseok = BASEOKsemanticdone;

// initialize vtbl
if (vtblOffset())
vtbl.push(this); // leave room at vtbl[0] for classinfo

// Cat together the vtbl[]'s from base interfaces
for (size_t i = 0; i < interfaces_dim; i++)
{
BaseClass* b = interfaces[i];

// Skip if b has already appeared
for (size_t k = 0; k < i; k++)
{
if (b == interfaces[k])
goto Lcontinue;
}

// Copy vtbl[] from base class
if (b.sym.vtblOffset())
{
Expand All @@ -1541,14 +1681,17 @@ public:
{
vtbl.append(&b.sym.vtbl);
}

Lcontinue:
}
}

for (size_t i = 0; i < members.dim; i++)
{
Dsymbol s = (*members)[i];
s.addMember(sc, this);
}

Scope* sc2 = sc.push(this);
sc2.stc &= STCsafe | STCtrusted | STCsystem;
sc2.parent = this;
Expand All @@ -1563,7 +1706,9 @@ public:
sc2.explicitProtection = 0;
sc2.structalign = STRUCTALIGN_DEFAULT;
sc2.userAttribDecl = null;

finalizeSize(sc2);

/* Set scope so if there are forward references, we still might be able to
* resolve individual members like enums.
*/
Expand All @@ -1573,25 +1718,32 @@ public:
//printf("setScope %s %s\n", s->kind(), s->toChars());
s.setScope(sc2);
}

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

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

semanticRun = PASSsemanticdone;

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 @@ -1607,6 +1759,7 @@ public:
{
structsize = Target.ptrsize * 2;
sizeok = SIZEOKdone;

// set the offset of base interfaces
setBaseInterfaceOffsets(0);
}
Expand Down Expand Up @@ -1637,6 +1790,7 @@ public:
*poffset = b.offset;
if (j && cd.isInterfaceDeclaration())
*poffset = OFFSET_RUNTIME;

/* TODO: Even though it's an interface to base interface upcast,
* I think we can avoid runtime offset determination ultimately.
* (I doubt that it was just a workaround for the bug in the
Expand All @@ -1657,6 +1811,7 @@ public:
}
if (cd.baseClass && isBaseOf(cd.baseClass, poffset))
return true;

if (poffset)
*poffset = 0;
return false;
Expand All @@ -1683,6 +1838,7 @@ public:
return true;
}
}

if (poffset)
*poffset = 0;
return false;
Expand Down
88 changes: 80 additions & 8 deletions src/dstruct.d
Original file line number Diff line number Diff line change
Expand Up @@ -258,49 +258,61 @@ public:

override Dsymbol syntaxCopy(Dsymbol s)
{
StructDeclaration sd = s ? cast(StructDeclaration)s : new StructDeclaration(loc, ident);
StructDeclaration sd =
s ? cast(StructDeclaration)s
: new StructDeclaration(loc, ident);
return ScopeDsymbol.syntaxCopy(sd);
}

override final void semantic(Scope* sc)
{
//printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok);

//static int count; if (++count == 20) assert(0);

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

Scope* scx = null;
if (_scope)
{
sc = _scope;
scx = _scope; // save so we don't make redundant copies
_scope = null;
}

if (!parent)
{
assert(sc.parent && sc.func);
parent = sc.parent;
}
assert(parent && !isAnonymous());

type = type.semantic(loc, sc);
if (type.ty == Tstruct && (cast(TypeStruct)type).sym != this)
{
TemplateInstance ti = (cast(TypeStruct)type).sym.isInstantiated();
if (ti && isError(ti))
(cast(TypeStruct)type).sym = this;
}

// Ungag errors when not speculative
Ungag ungag = ungagSpeculative();

if (semanticRun == PASSinit)
{
protection = sc.protection;

alignment = sc.structalign;

storage_class |= sc.stc;
if (storage_class & STCdeprecated)
isdeprecated = true;
if (storage_class & STCabstract)
error("structs, unions cannot be abstract");

userAttribDecl = sc.userAttribDecl;
}
else if (symtab && !scx)
Expand All @@ -309,13 +321,15 @@ public:
return;
}
semanticRun = PASSsemantic;

if (!members) // if opaque declaration
{
semanticRun = PASSsemanticdone;
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++)
Expand All @@ -325,6 +339,7 @@ public:
s.addMember(sc, this);
}
}

Scope* sc2 = sc.push(this);
sc2.stc &= STCsafe | STCtrusted | STCsystem;
sc2.parent = this;
Expand All @@ -334,9 +349,11 @@ public:
sc2.explicitProtection = 0;
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.
*/
Expand All @@ -346,17 +363,21 @@ public:
//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];
s.importAll(sc2);
}

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

finalizeSize(sc2);

if (sizeok == SIZEOKfwd)
{
// semantic() failed because of forward references.
Expand All @@ -369,16 +390,20 @@ public:
fields.setDim(0);
structsize = 0;
alignsize = 0;

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.
Expand All @@ -392,17 +417,21 @@ public:
StructDeclaration sd = (cast(TypeStruct)tb).sym;
if (sd.semanticRun >= PASSsemanticdone)
continue;

sc2.pop();

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

/* Look for special member functions.
*/
aggNew = cast(NewDeclaration)search(Loc(), Id.classNew);
aggDelete = cast(DeleteDeclaration)search(Loc(), Id.classDelete);

// this->ctor is already set in finalizeSize()

dtor = buildDtor(this, sc2);
Expand All @@ -426,7 +455,9 @@ public:
* See semanticTypeInfo().
*/
inv = buildInv(this, sc2);

sc2.pop();

if (ctor)
{
Dsymbol scall = search(Loc(), Id.call);
Expand All @@ -439,15 +470,18 @@ public:
FuncDeclaration fcall = resolveFuncCall(loc, sc, scall, null, null, null, 1);
sc = sc.pop();
global.endGagging(xerrors);

if (fcall && fcall.isStatic())
{
error(fcall.loc, "static opCall is hidden by constructors and can never be called");
errorSupplemental(fcall.loc, "Please use a factory method instead, or replace all constructors with static opCall.");
}
}
}

Module.dprogress++;
semanticRun = PASSsemanticdone;

TypeTuple tup = toArgTypes(type);
size_t dim = tup.arguments.dim;
if (dim >= 1)
Expand All @@ -457,8 +491,10 @@ public:
if (dim == 2)
arg2type = (*tup.arguments)[1].type;
}

if (sc.func)
semantic2(sc);

if (global.errors != errors)
{
// The type is no good.
Expand All @@ -467,11 +503,13 @@ public:
if (deferred)
deferred.errors = true;
}

if (deferred && !global.gag)
{
deferred.semantic2(sc);
deferred.semantic3(sc);
}

version (none)
{
if (type.ty == Tstruct && (cast(TypeStruct)type).sym != this)
Expand All @@ -485,34 +523,51 @@ public:

final void semanticTypeInfoMembers()
{
if (xeq && xeq._scope && xeq.semanticRun < PASSsemantic3done)
if (xeq &&
xeq._scope &&
xeq.semanticRun < PASSsemantic3done)
{
uint errors = global.startGagging();
xeq.semantic3(xeq._scope);
if (global.endGagging(errors))
xeq = xerreq;
}
if (xcmp && xcmp._scope && xcmp.semanticRun < PASSsemantic3done)

if (xcmp &&
xcmp._scope &&
xcmp.semanticRun < PASSsemantic3done)
{
uint errors = global.startGagging();
xcmp.semantic3(xcmp._scope);
if (global.endGagging(errors))
xcmp = xerrcmp;
}

FuncDeclaration ftostr = search_toString(this);
if (ftostr && ftostr._scope && ftostr.semanticRun < PASSsemantic3done)
if (ftostr &&
ftostr._scope &&
ftostr.semanticRun < PASSsemantic3done)
{
ftostr.semantic3(ftostr._scope);
}
if (xhash && xhash._scope && xhash.semanticRun < PASSsemantic3done)

if (xhash &&
xhash._scope &&
xhash.semanticRun < PASSsemantic3done)
{
xhash.semantic3(xhash._scope);
}
if (postblit && postblit._scope && postblit.semanticRun < PASSsemantic3done)

if (postblit &&
postblit._scope &&
postblit.semanticRun < PASSsemantic3done)
{
postblit.semantic3(postblit._scope);
}
if (dtor && dtor._scope && dtor.semanticRun < PASSsemantic3done)

if (dtor &&
dtor._scope &&
dtor.semanticRun < PASSsemantic3done)
{
dtor.semantic3(dtor._scope);
}
Expand All @@ -523,11 +578,13 @@ public:
//printf("%s.StructDeclaration::search('%s')\n", toChars(), ident->toChars());
if (_scope && !symtab)
semantic(_scope);

if (!members || !symtab) // opaque or semantic() is not yet called
{
error("is forward referenced when looking for '%s'", ident.toChars());
return null;
}

return ScopeDsymbol.search(loc, ident, flags);
}

Expand Down Expand Up @@ -634,13 +691,15 @@ public:
{
if (!elements)
return true;

size_t nfields = fields.dim - isNested();
size_t offset = 0;
for (size_t i = 0; i < elements.dim; i++)
{
Expression e = (*elements)[i];
if (!e)
continue;

e = resolveProperties(sc, e);
if (i >= nfields)
{
Expand All @@ -659,11 +718,13 @@ public:
return false;
}
offset = cast(uint)(v.offset + v.type.size());

Type t = v.type;
if (stype)
t = t.addMod(stype.mod);
Type origType = t;
Type tb = t.toBasetype();

/* Look for case of initializing a static array with a too-short
* string literal, such as:
* char[5] foo = "abc";
Expand All @@ -675,12 +736,16 @@ public:
StringExp se = cast(StringExp)e;
Type typeb = se.type.toBasetype();
TY tynto = tb.nextOf().ty;
if (!se.committed && (typeb.ty == Tarray || typeb.ty == Tsarray) && (tynto == Tchar || tynto == Twchar || tynto == Tdchar) && se.length(cast(int)tb.nextOf().size()) < (cast(TypeSArray)tb).dim.toInteger())
if (!se.committed &&
(typeb.ty == Tarray || typeb.ty == Tsarray) &&
(tynto == Tchar || tynto == Twchar || tynto == Tdchar) &&
se.length(cast(int)tb.nextOf().size()) < (cast(TypeSArray)tb).dim.toInteger())
{
e = se.castTo(sc, t);
goto L1;
}
}

while (!e.implicitConvTo(t) && tb.ty == Tsarray)
{
/* Static array initialization, as in:
Expand All @@ -691,10 +756,12 @@ public:
}
if (!e.implicitConvTo(t))
t = origType; // restore type for better diagnostic

e = e.implicitCastTo(sc, t);
L1:
if (e.op == TOKerror)
return false;

(*elements)[i] = e.isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);
}
return true;
Expand All @@ -713,9 +780,12 @@ public:
// If we've already determined whether this struct is POD.
if (ispod != ISPODfwd)
return (ispod == ISPODyes);

ispod = ISPODyes;

if (enclosing || postblit || dtor)
ispod = ISPODno;

// Recursively check all fields are POD.
for (size_t i = 0; i < fields.dim; i++)
{
Expand All @@ -725,6 +795,7 @@ public:
ispod = ISPODno;
break;
}

Type tv = v.type.baseElemOf();
if (tv.ty == Tstruct)
{
Expand All @@ -737,6 +808,7 @@ public:
}
}
}

return (ispod == ISPODyes);
}

Expand Down