Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

move fill from aggregate.d to expressionsem.d #16953

Merged
merged 1 commit into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -17504,3 +17504,159 @@
//printf("false\n");
return false;
}

/***************************************
* 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;

Check warning on line 17558 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L17558

Added line #L17558 was not covered by tests

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;

Check warning on line 17569 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L17568-L17569

Added lines #L17568 - L17569 were not covered by tests
}
else if (v2._init)
{
.error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
errors = true;

Check warning on line 17574 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L17573-L17574

Added lines #L17573 - L17574 were not covered by tests
}
}
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",

Check warning on line 17627 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L17627

Added line #L17627 was not covered by tests
sd.type.toChars(), vx.toChars());
errors = true;

Check warning on line 17629 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L17629

Added line #L17629 was not covered by tests
}
/* 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;
}
1 change: 0 additions & 1 deletion compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -6142,7 +6142,6 @@ class AggregateDeclaration : public ScopeDsymbol
virtual Scope* newScope(Scope* sc);
virtual void finalizeSize() = 0;
uinteger_t size(const Loc& loc) final override;
bool fill(const Loc& loc, Array<Expression* >& elements, bool ctorinit);
Type* getType() final override;
bool isDeprecated() const final override;
bool isNested() const;
Expand Down
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
Loading