diff options
Diffstat (limited to 'gcc/d/dmd/expressionsem.d')
-rw-r--r-- | gcc/d/dmd/expressionsem.d | 173 |
1 files changed, 117 insertions, 56 deletions
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 8a4a13c..f899bd7 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -353,6 +353,37 @@ extern(D) bool arrayExpressionSemantic( return err; } +/* +Checks if `exp` contains a direct access to a `noreturn` +variable. If that is the case, an `assert(0)` expression +is generated and returned. This function should be called +only after semantic analysis has been performed on `exp`. + +Params: + exp = expression that is checked + +Returns: + An `assert(0)` expression if `exp` contains a `noreturn` + variable access, `exp` otherwise. +*/ + +Expression checkNoreturnVarAccess(Expression exp) +{ + assert(exp.type); + + Expression result = exp; + if (exp.type.isTypeNoreturn() && !exp.isAssertExp() && + !exp.isThrowExp() && !exp.isCallExp()) + { + auto msg = new StringExp(exp.loc, "Accessed expression of type `noreturn`"); + msg.type = Type.tstring; + result = new AssertExp(exp.loc, IntegerExp.literal!0, msg); + result.type = exp.type; + } + + return result; +} + /****************************** * Check the tail CallExp is really property function call. * Bugs: @@ -848,6 +879,18 @@ Lagain: if (d) d.checkDisabled(loc, sc); } + + if (auto sd = s.isDeclaration()) + { + if (sd.isSystem()) + { + if (sc.setUnsafePreview(global.params.systemVariables, false, loc, + "cannot access `@system` variable `%s` in @safe code", sd)) + { + return ErrorExp.get(); + } + } + } } if (auto em = s.isEnumMember()) @@ -1714,7 +1757,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, if (sc._module) sc._module.hasAlwaysInlines = true; if (sc.func) - sc.func.flags |= FUNCFLAG.hasAlwaysInline; + sc.func.hasAlwaysInlines = true; } const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration(); @@ -2200,14 +2243,14 @@ private bool functionParameters(const ref Loc loc, Scope* sc, /* If calling C scanf(), printf(), or any variants, check the format string against the arguments */ const isVa_list = tf.parameterList.varargs == VarArg.none; - if (fd && fd.flags & FUNCFLAG.printf) + if (fd && fd.printf) { if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp()) { checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list); } } - else if (fd && fd.flags & FUNCFLAG.scanf) + else if (fd && fd.scanf) { if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp()) { @@ -4628,8 +4671,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else if (exp.arguments.dim == 1) { e = (*exp.arguments)[0]; - e = e.implicitCastTo(sc, t1); - e = new CastExp(exp.loc, e, t1); + if (!e.type.isTypeNoreturn()) + e = e.implicitCastTo(sc, t1); } else { @@ -7474,6 +7517,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } + if (exp.e1.type.isTypeNoreturn() && (!exp.to || !exp.to.isTypeNoreturn())) + { + result = exp.e1; + return; + } if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction()) exp.e1 = exp.e1.arrayFuncConv(sc); @@ -7889,7 +7937,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } } - else if (t1b.ty == Tvector) + else if (t1b.ty == Tvector && exp.e1.isLvalue()) { // Convert e1 to corresponding static array TypeVector tv1 = cast(TypeVector)t1b; @@ -8896,7 +8944,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.e1 = e1x; assert(exp.e1.type); } - Type t1 = exp.e1.type.toBasetype(); + Type t1 = exp.e1.type.isTypeEnum() ? exp.e1.type : exp.e1.type.toBasetype(); /* Run this.e2 semantic. * Different from other binary expressions, the analysis of e2 @@ -8918,14 +8966,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor e2x.checkSharedAccess(sc)) return setError(); - if (e2x.type.isTypeNoreturn() && !e2x.isAssertExp() && !e2x.isThrowExp() && !e2x.isCallExp()) - { - auto msg = new StringExp(e2x.loc, "Accessed expression of type `noreturn`"); - msg.type = Type.tstring; - e2x = new AssertExp(e2x.loc, IntegerExp.literal!0, msg); - e2x.type = Type.tnoreturn; - return setResult(e2x); - } + auto etmp = checkNoreturnVarAccess(e2x); + if (etmp != e2x) + return setResult(etmp); + exp.e2 = e2x; } @@ -9890,14 +9934,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.type = exp.e1.type; assert(exp.type); + auto assignElem = exp.e2; auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp; - Expression tmp; /* https://issues.dlang.org/show_bug.cgi?id=22366 * * `reorderSettingAAElem` creates a tree of comma expressions, however, * `checkAssignExp` expects only AssignExps. */ - checkAssignEscape(sc, Expression.extractLast(res, tmp), false, false); + if (res == exp) // no `AA[k] = v` rewrite was performed + checkAssignEscape(sc, res, false, false); + else + checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap if (auto ae = res.isConstructExp()) { @@ -9905,40 +9952,48 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (t1b.ty != Tsarray && t1b.ty != Tarray) return setResult(res); - /* Do not lower Rvalues and references, as they need to be moved, - * not copied. - * Skip the lowering when the RHS is an array literal, as e2ir - * already handles such cases more elegantly. - */ - const isArrayCtor = - (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) && - ae.e2.isLvalue && - !(ae.e1.isVarExp && - ae.e1.isVarExp.var.isVarDeclaration.isReference) && - (ae.e2.isVarExp || - ae.e2.isSliceExp || - (ae.e2.type.ty == Tsarray && !ae.e2.isArrayLiteralExp)) && - ae.e1.type.nextOf && - ae.e2.type.nextOf && - ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf); - - /* Unlike isArrayCtor above, lower all Rvalues. If the RHS is a literal, - * then we do want to make a temporary for it and call its destructor. - */ - const isArraySetCtor = - (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) && - (ae.e2.type.ty == Tstruct || ae.e2.type.ty == Tsarray) && - ae.e1.type.nextOf && - ae.e1.type.nextOf.equivalent(ae.e2.type); + // only non-trivial array constructions may need to be lowered (non-POD elements basically) + Type t1e = t1b.nextOf(); + TypeStruct ts = t1e.baseElemOf().isTypeStruct(); + if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor)) + return setResult(res); - if (isArrayCtor || isArraySetCtor) + // don't lower ref-constructions etc. + if (!(t1b.ty == Tsarray || ae.e1.isSliceExp) || + (ae.e1.isVarExp && ae.e1.isVarExp.var.isVarDeclaration.isReference)) + return setResult(res); + + // Construction from an equivalent other array? + // Only lower with lvalue RHS elements; let the glue layer move rvalue elements. + Type t2b = ae.e2.type.toBasetype(); + // skip over a (possibly implicit) cast of a static array RHS to a slice + Expression rhs = ae.e2; + Type rhsType = t2b; + if (t2b.ty == Tarray) { - const ts = t1b.nextOf().baseElemOf().isTypeStruct(); - if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor)) - return setResult(res); + if (auto ce = rhs.isCastExp()) + { + auto ct = ce.e1.type.toBasetype(); + if (ct.ty == Tsarray) + { + rhs = ce.e1; + rhsType = ct; + } + } + } + const lowerToArrayCtor = + ( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) || + (rhsType.ty == Tsarray && rhs.isLvalue) ) && + t1e.equivalent(t2b.nextOf); + + // Construction from a single element? + // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times). + const lowerToArraySetCtor = !lowerToArrayCtor && t1e.equivalent(t2b); - auto func = isArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor; - const other = isArrayCtor ? "other array" : "value"; + if (lowerToArrayCtor || lowerToArraySetCtor) + { + auto func = lowerToArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor; + const other = lowerToArrayCtor ? "other array" : "value"; if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object)) return setError(); @@ -9948,18 +10003,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor id = new DotIdExp(exp.loc, id, func); auto arguments = new Expressions(); - arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf).expressionSemantic(sc)); - if (isArrayCtor) + arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc)); + if (lowerToArrayCtor) { - arguments.push(new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf).expressionSemantic(sc)); + arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc)); Expression ce = new CallExp(exp.loc, id, arguments); res = ce.expressionSemantic(sc); } else { Expression e0; - // If ae.e2 is not a variable, construct a temp variable, as _d_arraysetctor requires `ref` access - if (!ae.e2.isVarExp) + // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor + if (!ae.e2.isLvalue) { auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2); e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc); @@ -11759,6 +11814,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = arrayLowering; return; } + + if (t1.isTypeVector()) + exp.type = t1; + result = exp; return; } @@ -12038,6 +12097,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } + if (t1.isTypeVector()) + exp.type = t1; + result = exp; } @@ -12490,8 +12552,7 @@ Expression semanticX(DotIdExp exp, Scope* sc) if (f.checkForwardRef(loc)) return ErrorExp.get(); - if (f.flags & (FUNCFLAG.purityInprocess | FUNCFLAG.safetyInprocess | - FUNCFLAG.nothrowInprocess | FUNCFLAG.nogcInprocess)) + if (f.purityInprocess || f.safetyInprocess || f.nothrowInprocess || f.nogcInprocess) { f.error(loc, "cannot retrieve its `.mangleof` while inferring attributes"); return ErrorExp.get(); @@ -13099,7 +13160,7 @@ Lerr: */ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) { - if (!global.params.noSharedAccess || + if (global.params.noSharedAccess != FeatureState.enabled || sc.intypeof || sc.flags & SCOPE.ctfe) { |