From 13b6c56c07bbd1f3175c5929fb12e871a849b608 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 2 Apr 2018 01:33:16 -0700 Subject: [PATCH] refactor: more use of ctorflow --- src/dmd/ctorflow.d | 22 ++++++++++++++++++++++ src/dmd/dscope.d | 16 ++++++++++++++-- src/dmd/expressionsem.d | 18 +++++++----------- src/dmd/statementsem.d | 31 ++++++++++++------------------- 4 files changed, 55 insertions(+), 32 deletions(-) diff --git a/src/dmd/ctorflow.d b/src/dmd/ctorflow.d index 5580bf65bf0d..a186bf8bf7ab 100644 --- a/src/dmd/ctorflow.d +++ b/src/dmd/ctorflow.d @@ -63,6 +63,28 @@ struct CtorFlow } return fi; } + + /*********************** + * Create a deep copy of `this` + * Returns: + * a copy + */ + CtorFlow clone() + { + return CtorFlow(callSuper, saveFieldInit()); + } + + /********************************** + * Set CSX bits in flow analysis state + * Params: + * csx = bits to set + */ + void orCSX(CSX csx) nothrow pure + { + callSuper |= csx; + foreach (ref u; fieldinit) + u |= csx; + } } diff --git a/src/dmd/dscope.d b/src/dmd/dscope.d index edf6f6e9ac2d..ffc0fca4bf5d 100644 --- a/src/dmd/dscope.d +++ b/src/dmd/dscope.d @@ -266,7 +266,7 @@ struct Scope return pop(); } - extern (C++) void mergeCallSuper(Loc loc, CSX cs) + extern (C++) void mergeCallSuper(const ref Loc loc, CSX cs) { // This does a primitive flow analysis to support the restrictions // regarding when and how constructors can appear. @@ -323,7 +323,7 @@ struct Scope } } - extern (D) void mergeFieldInit(Loc loc, const CSX[] fies) + extern (D) void mergeFieldInit(const ref Loc loc, const CSX[] fies) { if (ctorflow.fieldinit.length && fies.length) { @@ -343,6 +343,18 @@ struct Scope } } + /******************************* + * Merge results of `ctorflow` into `this`. + * Params: + * loc = for error messages + * ctorflow = flow results to merge in + */ + extern (D) void merge(const ref Loc loc, const ref CtorFlow ctorflow) + { + mergeCallSuper(loc, ctorflow.callSuper); + mergeFieldInit(loc, ctorflow.fieldinit); + } + extern (C++) Module instantiatingModule() { // TODO: in speculative context, returning 'module' is correct? diff --git a/src/dmd/expressionsem.d b/src/dmd/expressionsem.d index d2660224c62d..e5514e54f5a3 100644 --- a/src/dmd/expressionsem.d +++ b/src/dmd/expressionsem.d @@ -4373,12 +4373,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.e1.isBool(false)) { + /* This is an `assert(0)` which means halt program execution + */ FuncDeclaration fd = sc.parent.isFuncDeclaration(); if (fd) fd.hasReturnExp |= 4; - sc.ctorflow.callSuper |= CSX.halt; - foreach (ref u; sc.ctorflow.fieldinit) - u |= CSX.halt; + sc.ctorflow.orCSX(CSX.halt); if (global.params.useAssert == CHECKENABLE.off) { @@ -9115,20 +9115,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor ec = resolveProperties(sc, ec); ec = ec.toBoolean(sc); - const cs0 = sc.ctorflow.callSuper; - auto fi0 = sc.ctorflow.saveFieldInit(); + CtorFlow ctorflow_root = sc.ctorflow.clone(); Expression e1x = exp.e1.expressionSemantic(sc); e1x = resolveProperties(sc, e1x); - const cs1 = sc.ctorflow.callSuper; - const fi1 = sc.ctorflow.fieldinit; - sc.ctorflow.callSuper = cs0; - sc.ctorflow.fieldinit = fi0; + CtorFlow ctorflow1 = sc.ctorflow; + sc.ctorflow = ctorflow_root; Expression e2x = exp.e2.expressionSemantic(sc); e2x = resolveProperties(sc, e2x); - sc.mergeCallSuper(exp.loc, cs1); - sc.mergeFieldInit(exp.loc, fi1); + sc.merge(exp.loc, ctorflow1); if (ec.op == TOK.error) { diff --git a/src/dmd/statementsem.d b/src/dmd/statementsem.d index df8a4f09a7aa..9dcd9a1fd2a4 100644 --- a/src/dmd/statementsem.d +++ b/src/dmd/statementsem.d @@ -2124,11 +2124,8 @@ else /* https://dlang.org/spec/statement.html#IfStatement */ - // Evaluate at runtime - CSX cs0 = sc.ctorflow.callSuper; - CSX cs1; - CSX[] fi0 = sc.ctorflow.saveFieldInit(); - CSX[] fi1 = null; + // Save 'root' of two branches (then and else) + CtorFlow ctorflow_root = sc.ctorflow.clone(); // check in syntax level ifs.condition = checkAssignmentAsCondition(ifs.condition); @@ -2187,14 +2184,13 @@ else ifs.ifbody = ifs.ifbody.semanticNoScope(scd); scd.pop(); - cs1 = sc.ctorflow.callSuper; - fi1 = sc.ctorflow.fieldinit; - sc.ctorflow.callSuper = cs0; - sc.ctorflow.fieldinit = fi0; + CtorFlow ctorflow_then = sc.ctorflow; // move flow results + sc.ctorflow = ctorflow_root; // reset flow analysis back to root if (ifs.elsebody) ifs.elsebody = ifs.elsebody.semanticScope(sc, null, null); - sc.mergeCallSuper(ifs.loc, cs1); - sc.mergeFieldInit(ifs.loc, fi1); + + // Merge 'then' results into 'else' results + sc.merge(ifs.loc, ctorflow_then); if (ifs.condition.op == TOK.error || (ifs.ifbody && ifs.ifbody.isErrorStatement()) || @@ -3228,23 +3224,22 @@ else rs.error("`return` without calling constructor"); errors = true; } - sc.ctorflow.callSuper |= CSX.return_; - if (sc.ctorflow.fieldinit.length) + + if (sc.ctorflow.fieldinit.length) // if aggregate fields are being constructed { auto ad = fd.isMember2(); assert(ad); - foreach (i; 0 .. sc.ctorflow.fieldinit.length) + foreach (i, v; ad.fields) { - VarDeclaration v = ad.fields[i]; bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested()); if (mustInit && !(sc.ctorflow.fieldinit[i] & CSX.this_ctor)) { rs.error("an earlier `return` statement skips field `%s` initialization", v.toChars()); errors = true; } - sc.ctorflow.fieldinit[i] |= CSX.return_; } } + sc.ctorflow.orCSX(CSX.return_); if (errors) return setError(); @@ -4004,10 +3999,8 @@ else sc = sc.push(); sc.scopesym = sc.enclosing.scopesym; - sc.ctorflow.callSuper |= CSX.label; - foreach (ref u; sc.ctorflow.fieldinit) - u |= CSX.label; + sc.ctorflow.orCSX(CSX.label); sc.slabel = ls; if (ls.statement)