Skip to content

Commit

Permalink
move fill from aggregate.d to expressionsem.d
Browse files Browse the repository at this point in the history
  • Loading branch information
thewilsonator committed Oct 6, 2024
1 parent 2024098 commit 5bb1a2a
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 157 deletions.
155 changes: 0 additions & 155 deletions compiler/src/dmd/aggregate.d
Original file line number Diff line number Diff line change
Expand Up @@ -336,161 +336,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
return errors;
}

/***************************************
* Fill out remainder of elements[] with default initializers for fields[].
* Params:
* loc = location
* elements = explicit arguments which given to construct object.
* ctorinit = true if the elements will be used for default initialization.
* Returns:
* false if any errors occur.
* Otherwise, returns true and the missing arguments will be pushed in elements[].
*/
final bool fill(const ref Loc loc, ref Expressions elements, bool ctorinit)
{
//printf("AggregateDeclaration::fill() %s\n", toChars());
assert(sizeok == Sizeok.done);
const nfields = nonHiddenFields();
bool errors = false;

size_t dim = elements.length;
elements.setDim(nfields);
foreach (size_t i; dim .. nfields)
elements[i] = null;

// Fill in missing any elements with default initializers
foreach (i; 0 .. nfields)
{
if (elements[i])
continue;

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;
foreach (j; 0 .. nfields)
{
if (i == j)
continue;
auto v2 = fields[j];
if (!vd.isOverlappedWith(v2))
continue;

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

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
{
// fixes https://issues.dlang.org/show_bug.cgi?id=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.isOverlappedWith(v2))
{
// Both vx and v2 fills vd, but vx and v2 does not overlap
}
else if (vx._init && v2._init)
{
.error(loc, "overlapping default initialization for field `%s` and `%s`",
v2.toChars(), vd.toChars());
errors = true;
}
else
assert(vx._init || !vx._init && !v2._init);
}
}
if (vx)
{
Expression e;
if (vx.type.size() == 0)
{
e = null;
}
else if (vx._init)
{
assert(!vx._init.isVoidInitializer());
if (vx.inuse) // https://issues.dlang.org/show_bug.cgi?id=18057
{
.error(loc, "%s `%s` recursive initialization of field", vx.kind(), vx.toPrettyChars());
errors = true;
}
else
e = vx.getConstInitializer(false);
}
else
{
if ((vx.storage_class & STC.nodefaultctor) && !ctorinit)
{
.error(loc, "field `%s.%s` must be initialized because it has no default constructor",
type.toChars(), vx.toChars());
errors = true;
}
/* https://issues.dlang.org/show_bug.cgi?id=12509
* Get the element of static array type.
*/
Type telem = vx.type;
if (telem.ty == Tsarray)
{
/* We cannot use Type::baseElemOf() here.
* If the bottom of the Tsarray is an enum type, baseElemOf()
* will return the base of the enum, and its default initializer
* would be different from the enum's.
*/
TypeSArray tsa;
while ((tsa = telem.toBasetype().isTypeSArray()) !is null)
telem = tsa.next;
if (telem.ty == Tvoid)
telem = Type.tuns8.addMod(telem.mod);
}
if (telem.needsNested() && ctorinit)
e = telem.defaultInit(loc);
else
e = telem.defaultInitLiteral(loc);
}
elements[fieldi] = e;
}
}
foreach (e; elements)
{
if (e && e.op == EXP.error)
return false;
}

return !errors;
}

override final Type getType()
{
/* Apply storage classes to forward references. (Issue 22254)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dmd/aggregate.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace dmd
{
FuncDeclaration *search_toString(StructDeclaration *sd);
void semanticTypeInfoMembers(StructDeclaration *sd);
bool fill(StructDeclaration* sd, const Loc &loc, Expressions &elements, bool ctorinit);
}

enum class ClassKind : uint8_t
Expand Down Expand Up @@ -119,7 +120,6 @@ class AggregateDeclaration : public ScopeDsymbol
virtual Scope *newScope(Scope *sc);
virtual void finalizeSize() = 0;
uinteger_t size(const Loc &loc) override final;
bool fill(const Loc &loc, Expressions &elements, bool ctorinit);
Type *getType() override final;
bool isDeprecated() const override final; // is aggregate deprecated?
bool isNested() const;
Expand Down
7 changes: 7 additions & 0 deletions compiler/src/dmd/cxxfrontend.d
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,13 @@ Expression expressionSemantic(Expression e, Scope* sc)
return dmd.expressionsem.expressionSemantic(e, sc);
}

bool fill(StructDeclaration sd, const ref Loc loc,
ref Expressions elements, bool ctorinit)
{
import dmd.expressionsem;
return dmd.expressionsem.fill(sd, loc, elements, ctorinit);
}

/***********************************************************
* funcsem.d
*/
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/e2ir.d
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import dmd.dstruct;
import dmd.dsymbol;
import dmd.dtemplate;
import dmd.expression;
import dmd.expressionsem : fill;
import dmd.func;
import dmd.glue;
import dmd.hdrgen;
Expand Down
156 changes: 156 additions & 0 deletions compiler/src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -17271,3 +17271,159 @@ void semanticTypeInfo(Scope* sc, Type t)
default: semanticTypeInfo(sc, tb.nextOf()); break;
}
}

/***************************************
* Fill out remainder of elements[] with default initializers for fields[].
* Params:
* sd = struct
* loc = location
* elements = explicit arguments which given to construct object.
* ctorinit = true if the elements will be used for default initialization.
* Returns:
* false if any errors occur.
* Otherwise, returns true and the missing arguments will be pushed in elements[].
*/
bool fill(StructDeclaration sd, const ref Loc loc, ref Expressions elements, bool ctorinit)
{
//printf("AggregateDeclaration::fill() %s\n", toChars());
assert(sd.sizeok == Sizeok.done);
const nfields = sd.nonHiddenFields();
bool errors = false;

size_t dim = elements.length;
elements.setDim(nfields);
foreach (size_t i; dim .. nfields)
elements[i] = null;

// Fill in missing any elements with default initializers
foreach (i; 0 .. nfields)
{
if (elements[i])
continue;

auto vd = sd.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;
foreach (j; 0 .. nfields)
{
if (i == j)
continue;
auto v2 = sd.fields[j];
if (!vd.isOverlappedWith(v2))
continue;

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

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
{
// fixes https://issues.dlang.org/show_bug.cgi?id=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.isOverlappedWith(v2))
{
// Both vx and v2 fills vd, but vx and v2 does not overlap
}
else if (vx._init && v2._init)
{
.error(loc, "overlapping default initialization for field `%s` and `%s`",
v2.toChars(), vd.toChars());
errors = true;
}
else
assert(vx._init || !vx._init && !v2._init);
}
}
if (!vx)
continue;

Expression e;
if (vx.type.size() == 0)
{
e = null;
}
else if (vx._init)
{
assert(!vx._init.isVoidInitializer());
if (vx.inuse) // https://issues.dlang.org/show_bug.cgi?id=18057
{
.error(loc, "%s `%s` recursive initialization of field", vx.kind(), vx.toPrettyChars());
errors = true;
}
else
e = vx.getConstInitializer(false);
}
else
{
if ((vx.storage_class & STC.nodefaultctor) && !ctorinit)
{
.error(loc, "field `%s.%s` must be initialized because it has no default constructor",
sd.type.toChars(), vx.toChars());
errors = true;
}
/* https://issues.dlang.org/show_bug.cgi?id=12509
* Get the element of static array type.
*/
Type telem = vx.type;
if (telem.ty == Tsarray)
{
/* We cannot use Type::baseElemOf() here.
* If the bottom of the Tsarray is an enum type, baseElemOf()
* will return the base of the enum, and its default initializer
* would be different from the enum's.
*/
TypeSArray tsa;
while ((tsa = telem.toBasetype().isTypeSArray()) !is null)
telem = tsa.next;
if (telem.ty == Tvoid)
telem = Type.tuns8.addMod(telem.mod);
}
if (telem.needsNested() && ctorinit)
e = telem.defaultInit(loc);
else
e = telem.defaultInitLiteral(loc);
}
elements[fieldi] = e;
}
foreach (e; elements)
{
if (e && e.op == EXP.error)
return false;
}

return !errors;
}
2 changes: 1 addition & 1 deletion compiler/src/tests/cxxfrontend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,7 @@ class MiniGlueVisitor : public Visitor
return;
(void)d->sinit;
StructLiteralExp *sle = StructLiteralExp::create(d->loc, d, NULL);
if (!d->fill(d->loc, *sle->elements, true))
if (!dmd::fill(d, d->loc, *sle->elements, true))
assert(0);
sle->type = d->type;
sle->accept(this);
Expand Down

0 comments on commit 5bb1a2a

Please sign in to comment.