Skip to content

Commit 95ef9e5

Browse files
committed
Implement Static Single Assignment (SSA) DIP
1 parent 81af94b commit 95ef9e5

File tree

9 files changed

+188
-102
lines changed

9 files changed

+188
-102
lines changed

compiler/src/dmd/dcast.d

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import dmd.aggregate;
1717
import dmd.arrayop;
1818
import dmd.arraytypes;
1919
import dmd.astenums;
20-
import dmd.printast;
2120
import dmd.dclass;
2221
import dmd.declaration;
2322
import dmd.denum;
@@ -41,6 +40,7 @@ import dmd.intrange;
4140
import dmd.mtype;
4241
import dmd.opover;
4342
import dmd.optimize;
43+
//import dmd.printast;
4444
import dmd.root.ctfloat;
4545
import dmd.common.outbuffer;
4646
import dmd.root.rmem;
@@ -70,25 +70,25 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t)
7070
{
7171
Expression visit(Expression e)
7272
{
73-
printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
73+
//printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
7474
if (const match = (sc && sc.inCfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t))
7575
{
76-
/* Do not allow taking a mutable pointer to a final
77-
*/
78-
printf("xyzzy\n");
79-
printAST(e);
80-
SymOffExp es = e.isSymOffExp();
81-
if (es && es.var.storage_class & STC.final_)
82-
{
83-
printf("xyzzy2\n");
76+
/* Do not allow taking a mutable pointer to a final
77+
*/
78+
static if (0) // not sure this is needed
79+
{
80+
SymOffExp es = e.isSymOffExp();
81+
if (es && es.var.storage_class & STC.final_ && es.var.isVarDeclaration())
82+
{
8483
Type tob = t.toBasetype();
85-
if (tob.ty == Tpointer && !tob.nextOf().isConst())
86-
{
87-
error(e.loc, "cannot implicitly convert final `%s` to `%s`", es.toChars(), t.toChars());
88-
errorSupplemental(e.loc, "Note: a reference to a final can be done if it is const.");
89-
return ErrorExp.get();
90-
}
91-
}
84+
if (tob.ty == Tpointer && tob.nextOf().isMutable())
85+
{
86+
error(e.loc, "cannot implicitly convert final `%s` to `%s`", es.toChars(), t.toChars());
87+
errorSupplemental(e.loc, "Note: a reference to a final can be done if it is const.");
88+
return ErrorExp.get();
89+
}
90+
}
91+
}
9292

9393
// no need for an extra cast when matching is exact
9494

compiler/src/dmd/dsymbolsem.d

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2326,9 +2326,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
23262326

23272327
if (STC stc = dsym.storage_class & (STC.synchronized_ | STC.override_ | STC.abstract_))
23282328
{
2329-
OutBuffer buf;
2330-
stcToBuffer(buf, stc);
2331-
.error(dsym.loc, "%s `%s` cannot be `%s`", dsym.kind, dsym.toPrettyChars, buf.peekChars());
2329+
OutBuffer buf;
2330+
stcToBuffer(buf, stc);
2331+
.error(dsym.loc, "%s `%s` cannot be `%s`", dsym.kind, dsym.toPrettyChars, buf.peekChars());
23322332
dsym.storage_class &= ~stc; // strip off
23332333
}
23342334

@@ -2748,20 +2748,20 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
27482748
{
27492749
dsym.storage_class |= STC.nodtor;
27502750
exp = exp.expressionSemantic(sc);
2751-
printf("dsymIsRef: ref %s = %s;\n", dsym.toChars(), exp.toChars());
27522751
Type tp = dsym.type;
27532752
Type ta = exp.type;
2754-
if (!tp.isConst() &&
2755-
exp.isVarExp() &&
2756-
exp.isVarExp().var.storage_class & STC.final_)
2757-
{
2758-
.error(dsym.loc, "cannot take mutable ref to final variable `%s`, use `const ref`", exp.toChars());
2759-
exp = ErrorExp.get();
2760-
}
2761-
2762-
if (exp.isErrorExp())
2763-
{
2764-
}
2753+
if (tp.isMutable() &&
2754+
exp.isVarExp() &&
2755+
exp.isVarExp().var.isVarDeclaration() &&
2756+
exp.isVarExp().var.storage_class & STC.final_)
2757+
{
2758+
.error(dsym.loc, "cannot take mutable ref to final variable `%s`, use `const ref`", exp.toChars());
2759+
exp = ErrorExp.get();
2760+
}
2761+
2762+
if (exp.isErrorExp())
2763+
{
2764+
}
27652765
else if (!exp.isLvalue())
27662766
{
27672767
if (dsym.storage_class & STC.autoref)

compiler/src/dmd/expressionsem.d

Lines changed: 97 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3915,7 +3915,7 @@ private bool functionParameters(Loc loc, Scope* sc,
39153915
//printf("functionParameters() fd: %s tf: %s\n", fd ? fd.ident.toChars() : "", toChars(tf));
39163916
assert(arguments);
39173917
assert(fd || tf.next);
3918-
const size_t nparams = tf.parameterList.length;
3918+
const size_t nparams = tf.parameterList.length; // number of parameters
39193919
const olderrors = global.errors;
39203920
bool err = false;
39213921
Expression eprefix = null;
@@ -3937,7 +3937,7 @@ private bool functionParameters(Loc loc, Scope* sc,
39373937
arguments.setDim(0);
39383938
arguments.pushSlice((*resolvedArgs)[]);
39393939
}
3940-
size_t nargs = arguments ? arguments.length : 0;
3940+
size_t nargs = arguments ? arguments.length : 0; // number of arguments
39413941

39423942
if (nargs > nparams && tf.parameterList.varargs == VarArg.none)
39433943
{
@@ -3974,7 +3974,6 @@ private bool functionParameters(Loc loc, Scope* sc,
39743974

39753975
const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
39763976

3977-
const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
39783977

39793978
/* If the function return type has wildcards in it, we'll need to figure out the actual type
39803979
* based on the actual argument types.
@@ -3984,12 +3983,13 @@ private bool functionParameters(Loc loc, Scope* sc,
39843983
MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0;
39853984

39863985
bool done = false;
3986+
const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
39873987
foreach (const i; 0 .. n)
39883988
{
39893989
Expression arg = (i < nargs) ? (*arguments)[i] : null;
39903990

39913991
if (i >= nparams)
3992-
break;
3992+
break; // this loop is not for variadic arguments
39933993

39943994
bool errorArgs()
39953995
{
@@ -3999,7 +3999,7 @@ private bool functionParameters(Loc loc, Scope* sc,
39993999

40004000
Parameter p = tf.parameterList[i];
40014001

4002-
if (!arg)
4002+
if (!arg) // the argument is missing, so use the default arg
40034003
{
40044004
if (!p.defaultArg)
40054005
{
@@ -4033,10 +4033,11 @@ private bool functionParameters(Loc loc, Scope* sc,
40334033
if (MATCH m = arg.implicitConvTo(p.type))
40344034
{
40354035
if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
4036-
goto L2;
4036+
{ }
40374037
else if (nargs != nparams)
40384038
return errorArgs();
4039-
goto L1;
4039+
else
4040+
goto L1;
40404041
}
40414042
L2:
40424043
Type tb = p.type.toBasetype();
@@ -4245,39 +4246,61 @@ private bool functionParameters(Loc loc, Scope* sc,
42454246
// Look for mutable misaligned pointer, etc., in @safe mode
42464247
err |= checkUnsafeAccess(sc, arg, false, true);
42474248
}
4248-
else if (p.storageClass & STC.ref_)
4249+
else if (p.storageClass & (STC.ref_ | STC.out_))
42494250
{
4250-
if (sc.previews.rvalueRefParam &&
4251-
!arg.isLvalue() &&
4252-
targ.isCopyable())
4253-
{ /* allow rvalues to be passed to ref parameters by copying
4254-
* them to a temp, then pass the temp as the argument
4255-
*/
4256-
auto v = copyToTemp(STC.none, "__rvalue", arg);
4257-
Expression ev = new DeclarationExp(arg.loc, v);
4258-
ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
4259-
arg = ev.expressionSemantic(sc);
4251+
if (VarExp ve = arg.isVarExp())
4252+
{
4253+
if (ve.var.storage_class & STC.final_ &&
4254+
ve.var.isVarDeclaration() &&
4255+
p.type.isMutable() &&
4256+
!(p.storageClass & STC.final_))
4257+
{
4258+
/* func(ref int p);
4259+
final int ve = 3;
4260+
func(ve); // error
4261+
*/
4262+
const char* msg = p.storageClass & STC.ref_
4263+
? "cannot modify final `%s` with ref to mutable"
4264+
: "cannot pass final `%s` to `out` parameter";
4265+
error(arg.loc, msg, ve.toErrMsg());
4266+
err = true;
4267+
}
42604268
}
4261-
arg = arg.toLvalue(sc, "create `ref` parameter from");
42624269

4263-
// Look for mutable misaligned pointer, etc., in @safe mode
4264-
err |= checkUnsafeAccess(sc, arg, false, true);
4265-
}
4266-
else if (p.storageClass & STC.out_)
4267-
{
4268-
Type t = arg.type;
4269-
if (!t.isMutable() || !t.isAssignable()) // check blit assignable
4270+
if (p.storageClass & STC.ref_)
42704271
{
4271-
error(arg.loc, "cannot modify struct `%s` with immutable members", arg.toChars());
4272-
err = true;
4272+
if (sc.previews.rvalueRefParam &&
4273+
!arg.isLvalue() &&
4274+
targ.isCopyable())
4275+
{ /* allow rvalues to be passed to ref parameters by copying
4276+
* them to a temp, then pass the temp as the argument
4277+
*/
4278+
auto v = copyToTemp(STC.none, "__rvalue", arg);
4279+
Expression ev = new DeclarationExp(arg.loc, v);
4280+
ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
4281+
arg = ev.expressionSemantic(sc);
4282+
}
4283+
arg = arg.toLvalue(sc, "create `ref` parameter from");
4284+
4285+
// Look for mutable misaligned pointer, etc., in @safe mode
4286+
err |= checkUnsafeAccess(sc, arg, false, true);
42734287
}
4274-
else
4288+
else // STC.out_
42754289
{
4276-
// Look for misaligned pointer, etc., in @safe mode
4277-
err |= checkUnsafeAccess(sc, arg, false, true);
4278-
err |= checkDefCtor(arg.loc, t); // t must be default constructible
4290+
Type t = arg.type;
4291+
if (!t.isMutable() || !t.isAssignable()) // check blit assignable
4292+
{
4293+
error(arg.loc, "cannot modify struct `%s` with immutable members", arg.toChars());
4294+
err = true;
4295+
}
4296+
else
4297+
{
4298+
// Look for misaligned pointer, etc., in @safe mode
4299+
err |= checkUnsafeAccess(sc, arg, false, true);
4300+
err |= checkDefCtor(arg.loc, t); // t must be default constructible
4301+
}
4302+
arg = arg.toLvalue(sc, "create `out` parameter from");
42794303
}
4280-
arg = arg.toLvalue(sc, "create `out` parameter from");
42814304
}
42824305
else if (p.isLazy())
42834306
{
@@ -10063,7 +10086,23 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
1006310086
}
1006410087
}
1006510088

10066-
exp.type = exp.e1.type.pointerTo();
10089+
/* Taking the address of a `final` variable means making a pointer to const
10090+
*/
10091+
bool toConst = false;
10092+
if (exp.e1.type.isMutable())
10093+
{
10094+
if (VarExp ve = exp.e1.isVarExp())
10095+
{
10096+
if (VarDeclaration v = ve.var.isVarDeclaration())
10097+
{
10098+
if (v.storage_class & STC.final_)
10099+
toConst = true;
10100+
}
10101+
}
10102+
}
10103+
10104+
exp.type = toConst ? exp.e1.type.constOf().pointerTo()
10105+
: exp.e1.type.pointerTo();
1006710106

1006810107
// See if this should really be a delegate
1006910108
if (exp.e1.op == EXP.dotVariable)
@@ -10094,16 +10133,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
1009410133
else if (exp.e1.op == EXP.variable)
1009510134
{
1009610135
VarExp ve = cast(VarExp)exp.e1;
10097-
VarDeclaration v = ve.var.isVarDeclaration();
10098-
if (v)
10136+
if (VarDeclaration v = ve.var.isVarDeclaration())
1009910137
{
1010010138
if (!checkAddressVar(sc, exp.e1, v))
1010110139
return setError();
1010210140

1010310141
v.checkPurity(ve.loc, sc);
1010410142
}
10105-
FuncDeclaration f = ve.var.isFuncDeclaration();
10106-
if (f)
10143+
10144+
if (FuncDeclaration f = ve.var.isFuncDeclaration())
1010710145
{
1010810146
/* Because nested functions cannot be overloaded,
1010910147
* mark here that we took its address because castTo()
@@ -17305,7 +17343,7 @@ Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyF
1730517343
case EXP.variable:
1730617344
auto varExp = cast(VarExp)exp;
1730717345

17308-
printf("VarExp::checkModifiable %s\n", varExp.toChars());
17346+
//printf("VarExp::checkModifiable %s\n", varExp.toChars());
1730917347
assert(varExp.type);
1731017348
return varExp.var.checkModify(varExp.loc, sc, null, flag);
1731117349

@@ -17453,6 +17491,7 @@ Expression modifiableLvalue(Expression _this, Scope* sc, Expression eorig = null
1745317491
Expression visit(Expression exp)
1745417492
{
1745517493
//printf("Expression::modifiableLvalue() %s, type = %s\n", exp.toChars(), exp.type.toChars());
17494+
//printAST(exp);
1745617495
// See if this expression is a modifiable lvalue (i.e. not const)
1745717496
if (exp.isBinAssignExp())
1745817497
return exp.toLvalue(sc, "modify");
@@ -17499,7 +17538,7 @@ Expression modifiableLvalue(Expression _this, Scope* sc, Expression eorig = null
1749917538

1750017539
Expression visitVar(VarExp exp)
1750117540
{
17502-
printf("VarExp::modifiableLvalue('%s')\n", exp.var.toChars());
17541+
//printf("VarExp::modifiableLvalue('%s')\n", exp.var.toChars());
1750317542
if (exp.var.storage_class & STC.final_)
1750417543
{
1750517544
error(exp.loc, "cannot modify `final %s`", exp.toErrMsg());
@@ -17534,6 +17573,22 @@ Expression modifiableLvalue(Expression _this, Scope* sc, Expression eorig = null
1753417573
return visit(exp);
1753517574
}
1753617575

17576+
Expression visitIndex(IndexExp exp)
17577+
{
17578+
//printf("IndexExp::modifiableLvalue() %s, type %s\n", exp.toChars(), exp.type.toChars());
17579+
if (auto ve = exp.e1.isVarExp())
17580+
{
17581+
if (ve.type.isTypeSArray() && ve.var.storage_class & STC.final_)
17582+
{
17583+
error(exp.loc, "cannot modify `final %s`", exp.toErrMsg());
17584+
return ErrorExp.get();
17585+
}
17586+
return visit(exp);
17587+
}
17588+
else
17589+
return exp.e1.modifiableLvalue(sc);
17590+
}
17591+
1753717592
Expression visitSlice(SliceExp exp)
1753817593
{
1753917594
error(exp.loc, "slice expression `%s` is not a modifiable lvalue", exp.toErrMsg());
@@ -17582,6 +17637,7 @@ Expression modifiableLvalue(Expression _this, Scope* sc, Expression eorig = null
1758217637
case EXP.string_: return visitString(_this.isStringExp());
1758317638
case EXP.variable: return visitVar(_this.isVarExp());
1758417639
case EXP.star: return visitPtr(_this.isPtrExp());
17640+
case EXP.index: return visitIndex(_this.isIndexExp());
1758517641
case EXP.slice: return visitSlice(_this.isSliceExp());
1758617642
case EXP.comma: return visitComma(_this.isCommaExp());
1758717643
case EXP.delegatePointer: return visitDelegatePtr(_this.isDelegatePtrExp());
@@ -18269,7 +18325,7 @@ enum ModifyFlags
1826918325
*/
1827018326
private Modifiable checkModify(Declaration d, Loc loc, Scope* sc, Expression e1, ModifyFlags flag)
1827118327
{
18272-
printf("checkModify() d: %s, e1: %s, flag: %x\n", d.toChars(), e1 ? e1.toChars() : "null", flag);
18328+
//printf("checkModify() d: %s, e1: %s, flag: %x\n", d.toChars(), e1 ? e1.toChars() : "null", flag);
1827318329
VarDeclaration v = d.isVarDeclaration();
1827418330
if (v && v.canassign)
1827518331
return Modifiable.initialization;

compiler/src/dmd/targetcompiler.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ else version (MARS)
8484
mixin template FuncDeclarationExtra()
8585
{
8686
VarDeclarations* alignSectionVars; /// local variables with alignment needs larger than stackAlign
87-
import dmd.backend.cc : Symbol;
87+
import dmd.backend.cc : Symbol;
8888
Symbol* salignSection; /// pointer to aligned section, if any
8989
}
9090
}

compiler/test/fail_compilation/fail170.d

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)