@@ -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 */
1827018326private 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;
0 commit comments