Skip to content

Commit

Permalink
Add AggregateDeclaration.checkOverlappedFields()
Browse files Browse the repository at this point in the history
- Extract that work from StructDeclaration.fill().
- Assume that `StructDeclaration.fill()` gets non-null `elements`.
  • Loading branch information
9rnsr committed Sep 12, 2015
1 parent 2736fb4 commit 2131cb8
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 53 deletions.
73 changes: 73 additions & 0 deletions src/aggregate.d
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

module ddmd.aggregate;

import core.stdc.stdio;
import ddmd.access;
import ddmd.arraytypes;
import ddmd.backend;
Expand All @@ -19,6 +20,7 @@ import ddmd.dscope;
import ddmd.dstruct;
import ddmd.dsymbol;
import ddmd.dtemplate;
import ddmd.errors;
import ddmd.expression;
import ddmd.func;
import ddmd.globals;
Expand Down Expand Up @@ -280,6 +282,77 @@ public:

abstract void finalizeSize(Scope* sc);

/***************************************
* Calculate field[i].overlapped, and check that all of explicit
* field initializers have unique memory space on instance.
* Returns:
* true if any errors happen.
*/
final bool checkOverlappedFields()
{
//printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
assert(sizeok == SIZEOKdone);
size_t nfields = fields.dim;
if (isNested())
{
auto cd = isClassDeclaration();
if (!cd || !cd.baseClass || !cd.baseClass.isNested())
nfields--;
}
bool errors = false;

// Fill in missing any elements with default initializers
foreach (i; 0 .. nfields)
{
auto vd = fields[i];
auto vx = vd;
if (vd._init && vd._init.isVoidInitializer())
vx = null;

// Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
foreach (j; 0 .. nfields)
{
if (i == j)
continue;
auto v2 = fields[j];
if (!vd.isOverlappedWith(v2))
continue;

// vd and v2 are overlapping. If either has destructors, postblits, etc., then error
//printf("overlapping fields %s and %s\n", vd->toChars(), v2->toChars());
foreach (k; 0.. 2)
{
auto v = k == 0 ? vd : v2;
Type tv = v.type.baseElemOf();
Dsymbol sv = tv.toDsymbol(null);
if (!sv || errors)
continue;
StructDeclaration sd = sv.isStructDeclaration();
if (sd && (sd.dtor || sd.inv || sd.postblit))
{
error("destructors, postblits and invariants are not allowed in overlapping fields %s and %s",
vd.toChars(), v2.toChars());
errors = true;
break;
}
}
vd.overlapped = true;

if (!vx)
continue;
if (v2._init && v2._init.isVoidInitializer())
continue;

if (vx._init && v2._init)
{
.error(loc, "overlapping default initialization for field %s and %s", v2.toChars(), vd.toChars());
errors = true;
}
}
}
return errors;
}

/****************************
* Do byte or word alignment as necessary.
* Align sizes of 0, as we may not know array sizes yet.
Expand Down
1 change: 1 addition & 0 deletions src/aggregate.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ class AggregateDeclaration : public ScopeDsymbol
void semantic3(Scope *sc);
unsigned size(Loc loc);
virtual void finalizeSize(Scope *sc) = 0;
bool checkOverlappedFields();
static void alignmember(structalign_t salign, unsigned size, unsigned *poffset);
static unsigned placeField(unsigned *nextoffset,
unsigned memsize, unsigned memalignsize, structalign_t memalign,
Expand Down
6 changes: 6 additions & 0 deletions src/dclass.d
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,7 @@ public:
else
structsize = Target.ptrsize * 2; // allow room for __vptr and __monitor
}

uint offset = structsize;
for (size_t i = 0; i < members.dim; i++)
{
Expand All @@ -1032,9 +1033,14 @@ public:
}
if (sizeok == SIZEOKfwd)
return;

// Add vptr's for any interfaces implemented by this class
structsize += setBaseInterfaceOffsets(structsize);
sizeok = SIZEOKdone;

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

// Look for the constructor
ctor = searchCtor();
if (ctor && ctor.toParent() != this)
Expand Down
95 changes: 42 additions & 53 deletions src/dstruct.d
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ public:
//printf("StructDeclaration::finalizeSize() %s\n", toChars());
if (sizeok != SIZEOKnone)
return;

// Set the offsets of the fields and determine the size of the struct
uint offset = 0;
bool isunion = isUnionDeclaration() !is null;
Expand All @@ -519,12 +520,14 @@ public:
}
if (sizeok == SIZEOKfwd)
return;

// 0 sized struct's are set to 1 byte
if (structsize == 0)
{
structsize = 1;
alignsize = 1;
}

// Round struct size up to next alignsize boundary.
// This will ensure that arrays of structs will get their internals
// aligned properly.
Expand All @@ -533,8 +536,10 @@ public:
else
structsize = (structsize + alignment - 1) & ~(alignment - 1);
sizeok = SIZEOKdone;
// Calculate fields[i]->overlapped
fill(loc, null, true);

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

// Determine if struct is all zeros or not
zeroInit = 1;
for (size_t i = 0; i < fields.dim; i++)
Expand All @@ -558,6 +563,7 @@ public:
}
}
}

// Look for the constructor, for the struct literal/constructor call expression
ctor = searchCtor();
if (ctor)
Expand Down Expand Up @@ -675,88 +681,73 @@ public:
{
//printf("StructDeclaration::fill() %s\n", toChars());
assert(sizeok == SIZEOKdone);
assert(elements);
size_t nfields = fields.dim - isNested();
bool errors = false;
if (elements)
{
size_t dim = elements.dim;
elements.setDim(nfields);
for (size_t i = dim; i < nfields; i++)
(*elements)[i] = null;
}

size_t dim = elements.dim;
elements.setDim(nfields);
for (size_t i = dim; i < nfields; i++)
(*elements)[i] = null;

// Fill in missing any elements with default initializers
for (size_t i = 0; i < nfields; i++)
foreach (i; 0 .. nfields)
{
if (elements && (*elements)[i])
if ((*elements)[i])
continue;
VarDeclaration vd = fields[i];
VarDeclaration vx = vd;

auto vd = fields[i];
auto vx = vd;
if (vd._init && vd._init.isVoidInitializer())
vx = null;

// Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
size_t fieldi = i;
for (size_t j = 0; j < nfields; j++)
foreach (j; 0 .. nfields)
{
if (i == j)
continue;
VarDeclaration v2 = fields[j];
auto v2 = fields[j];
if (!vd.isOverlappedWith(v2))
continue;
// vd and v2 are overlapping. If either has destructors, postblits, etc., then error
//printf("overlapping fields %s and %s\n", vd->toChars(), v2->toChars());
VarDeclaration v = vd;
for (int k = 0; k < 2; ++k, v = v2)
{
Type tv = v.type.baseElemOf();
Dsymbol sv = tv.toDsymbol(null);
if (sv && !errors)
{
StructDeclaration sd = sv.isStructDeclaration();
if (sd && (sd.dtor || sd.inv || sd.postblit))
{
error("destructors, postblits and invariants are not allowed in overlapping fields %s and %s", vd.toChars(), v2.toChars());
errors = true;
break;
}
}
}
if (elements)
{
if ((*elements)[j])
{
vx = null;
break;
}
}
else

if ((*elements)[j])
{
vd.overlapped = true;
vx = null;
break;
}
if (v2._init && v2._init.isVoidInitializer())
continue;
if (elements)

version (all)
{
/* Prefer first found non-void-initialized field
* union U { int a; int b = 2; }
* U u; // Error: overlapping initialization for field a and b
*/
if (!vx)
{
vx = v2, fieldi = j;
}
else if (v2._init)
{
.error(loc, "overlapping initialization for field %s and %s", v2.toChars(), vd.toChars());
errors = true;
}
}
else
{
// Will fix Bugzilla 1432 by enabling this path always

/* Prefer explicitly initialized field
* union U { int a; int b = 2; }
* U u; // OK (u.b == 2)
*/
if (!vx || !vx._init && v2._init)
{
vx = v2, fieldi = j;
else if (vx != vd && !(vx.offset < v2.offset + v2.type.size() && v2.offset < vx.offset + vx.type.size()))
}
else if (vx != vd && !vx.isOverlappedWith(v2))
{
// Both vx and v2 fills vd, but vx and v2 does not overlap
}
Expand All @@ -768,7 +759,7 @@ public:
assert(vx._init || !vx._init && !v2._init);
}
}
if (elements && vx)
if (vx)
{
Expression e;
if (vx.type.size() == 0)
Expand Down Expand Up @@ -809,15 +800,13 @@ public:
(*elements)[fieldi] = e;
}
}
if (elements)
for (size_t i = 0; i < elements.dim; i++)
{
for (size_t i = 0; i < elements.dim; i++)
{
Expression e = (*elements)[i];
if (e && e.op == TOKerror)
return false;
}
Expression e = (*elements)[i];
if (e && e.op == TOKerror)
return false;
}

return !errors;
}

Expand Down
2 changes: 2 additions & 0 deletions src/expression.d
Original file line number Diff line number Diff line change
Expand Up @@ -5566,6 +5566,8 @@ public:
}
else
{
if (!arguments)
arguments = new Expressions();
if (!sd.fit(loc, sc, arguments, tb))
return new ErrorExp();
if (!sd.fill(loc, arguments, false))
Expand Down

0 comments on commit 2131cb8

Please sign in to comment.