From 8ce08e98f15abb725c702e5bd9df5cd629f4260d Mon Sep 17 00:00:00 2001 From: Nicholas Wilson Date: Sun, 6 Oct 2024 14:31:06 +0800 Subject: [PATCH] move `fill` from `aggregate.d` to `expressionsem.d` --- compiler/src/dmd/aggregate.d | 155 ----------------------------- compiler/src/dmd/aggregate.h | 2 +- compiler/src/dmd/cxxfrontend.d | 7 ++ compiler/src/dmd/e2ir.d | 1 + compiler/src/dmd/expressionsem.d | 156 ++++++++++++++++++++++++++++++ compiler/src/dmd/frontend.h | 1 - compiler/src/tests/cxxfrontend.cc | 2 +- 7 files changed, 166 insertions(+), 158 deletions(-) diff --git a/compiler/src/dmd/aggregate.d b/compiler/src/dmd/aggregate.d index 38e5e07dc057..982e914f9dd3 100644 --- a/compiler/src/dmd/aggregate.d +++ b/compiler/src/dmd/aggregate.d @@ -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) diff --git a/compiler/src/dmd/aggregate.h b/compiler/src/dmd/aggregate.h index c972f0a6631f..8fd12e1d168a 100644 --- a/compiler/src/dmd/aggregate.h +++ b/compiler/src/dmd/aggregate.h @@ -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 @@ -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; diff --git a/compiler/src/dmd/cxxfrontend.d b/compiler/src/dmd/cxxfrontend.d index 05227ec19317..379d8fb51004 100644 --- a/compiler/src/dmd/cxxfrontend.d +++ b/compiler/src/dmd/cxxfrontend.d @@ -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 */ diff --git a/compiler/src/dmd/e2ir.d b/compiler/src/dmd/e2ir.d index 187f0b180beb..430644f3fda4 100644 --- a/compiler/src/dmd/e2ir.d +++ b/compiler/src/dmd/e2ir.d @@ -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; diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 3e4a2fdd4dac..8f748ebf9a6e 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -17508,3 +17508,159 @@ private bool needsTypeInference(TemplateInstance ti, Scope* sc, int flag = 0) //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; + + 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; +} diff --git a/compiler/src/dmd/frontend.h b/compiler/src/dmd/frontend.h index 2654e33a54e4..e3faee687fe5 100644 --- a/compiler/src/dmd/frontend.h +++ b/compiler/src/dmd/frontend.h @@ -6143,7 +6143,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& elements, bool ctorinit); Type* getType() final override; bool isDeprecated() const final override; bool isNested() const; diff --git a/compiler/src/tests/cxxfrontend.cc b/compiler/src/tests/cxxfrontend.cc index eaf4a36936d3..5355aa93f9af 100644 --- a/compiler/src/tests/cxxfrontend.cc +++ b/compiler/src/tests/cxxfrontend.cc @@ -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);