aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/expressionsem.d
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/expressionsem.d')
-rw-r--r--gcc/d/dmd/expressionsem.d173
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)
{