summaryrefslogtreecommitdiff
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.d218
1 files changed, 124 insertions, 94 deletions
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 7b7c489295a..d4e96bb0f09 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -56,6 +56,7 @@ import dmd.initsem;
import dmd.inline;
import dmd.intrange;
import dmd.mtype;
+import dmd.mustuse;
import dmd.nspace;
import dmd.opover;
import dmd.optimize;
@@ -713,7 +714,7 @@ private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2
*/
Expression resolvePropertiesOnly(Scope* sc, Expression e1)
{
- //printf("e1 = %s %s\n", Token::toChars(e1.op), e1.toChars());
+ //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
Expression handleOverloadSet(OverloadSet os)
{
@@ -2027,15 +2028,19 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
//printf("type: %s\n", arg.type.toChars());
//printf("param: %s\n", p.toChars());
- if (firstArg && p.storageClass & STC.return_)
+ const pStc = tf.parameterStorageClass(tthis, p);
+
+ if (firstArg && (pStc & STC.return_))
{
/* Argument value can be assigned to firstArg.
* Check arg to see if it matters.
*/
if (global.params.useDIP1000 == FeatureState.enabled)
- err |= checkParamArgumentReturn(sc, firstArg, arg, false);
+ err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
}
- else if (tf.parameterEscapes(tthis, p))
+ // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
+ // as lazy parameters to the next function, but that isn't escaping.
+ else if (!(pStc & (STC.scope_ | STC.lazy_)))
{
/* Argument value can escape from the called function.
* Check arg to see if it matters.
@@ -2043,7 +2048,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
if (global.params.useDIP1000 == FeatureState.enabled)
err |= checkParamArgumentEscape(sc, fd, p, arg, false, false);
}
- else if (!(p.storageClass & STC.return_))
+ else if (!(pStc & STC.return_))
{
/* Argument value cannot escape from the called function.
*/
@@ -3228,7 +3233,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
Type t = cle.type.typeSemantic(cle.loc, sc);
auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
- auto e = initializerToExpression(init, t);
+ auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
if (!e)
{
error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
@@ -3261,7 +3266,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// printf("apply fix for issue 9490: add `this.` to `%s`...\n", e.toChars());
e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false);
}
- //printf("e = %s %s\n", Token::toChars(e.op), e.toChars());
+ //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
e = e.expressionSemantic(sc);
}
else if (t)
@@ -5211,13 +5216,30 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (s.ident)
{
VarDeclaration v = s.isVarDeclaration();
- if (v && !(sc.flags & SCOPE.Cfile))
+ if (v)
{
- /* Do semantic() on initializer first so this will be illegal:
- * int a = a;
- */
- e.declaration.dsymbolSemantic(sc);
- s.parent = sc.parent;
+ if (sc.flags & SCOPE.Cfile)
+ {
+ /* Do semantic() on the type before inserting v into the symbol table
+ */
+ if (!v.originalType)
+ v.originalType = v.type.syntaxCopy();
+ Scope* sc2 = sc.push();
+ sc2.stc |= v.storage_class & STC.FUNCATTR;
+ sc2.linkage = LINK.c; // account for the extern(C) in front of the declaration
+ v.inuse++;
+ v.type = v.type.typeSemantic(v.loc, sc2);
+ v.inuse--;
+ sc2.pop();
+ }
+ else
+ {
+ /* Do semantic() on initializer first so this will be illegal:
+ * int a = a;
+ */
+ e.declaration.dsymbolSemantic(sc);
+ s.parent = sc.parent;
+ }
}
if (!sc.insert(s))
@@ -6032,7 +6054,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto fileName = FileName(name.toDString);
if (auto fmResult = global.fileManager.lookup(fileName))
{
- se = new StringExp(e.loc, fmResult.data);
+ se = new StringExp(e.loc, fmResult);
}
else
{
@@ -6047,9 +6069,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// take ownership of buffer (probably leaking)
auto data = readResult.extractSlice();
se = new StringExp(e.loc, data);
-
- FileBuffer* fileBuffer = new FileBuffer(data);
- global.fileManager.add(fileName, fileBuffer);
+ global.fileManager.add(fileName, data);
}
}
}
@@ -6388,7 +6408,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
static if (LOGSEMANTIC)
{
printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
- //printf("e1.op = %d, '%s'\n", e1.op, Token::toChars(e1.op));
+ //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
}
if (sc.flags & SCOPE.Cfile)
@@ -8177,7 +8197,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
if (e.type is Type.tvoid)
+ {
+ checkMustUse(e.e1, sc);
discardValue(e.e1);
+ }
else if (!e.allowCommaExp && !e.isGenerated)
e.error("Using the result of a comma expression is not allowed");
}
@@ -8956,7 +8979,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Parameter arg = Parameter.getNth(tt.arguments, u);
//printf("[%d] iexps.dim = %d, ", u, iexps.dim);
- //printf("e = (%s %s, %s), ", Token::tochars[e.op], e.toChars(), e.type.toChars());
+ //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
//printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
if (!arg || !e.type.implicitConvTo(arg.type))
@@ -9849,7 +9872,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* `reorderSettingAAElem` creates a tree of comma expressions, however,
* `checkAssignExp` expects only AssignExps.
*/
- checkAssignEscape(sc, Expression.extractLast(res, tmp), false);
+ checkAssignEscape(sc, Expression.extractLast(res, tmp), false, false);
if (auto ae = res.isConstructExp())
{
@@ -10124,7 +10147,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
if (isRecursiveAliasThis(exp.att1, exp.e1.type))
return null;
- //printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars());
+ //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
BinExp be = cast(BinExp)exp.copy();
be.e1 = e1;
@@ -10142,7 +10165,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
if (isRecursiveAliasThis(exp.att2, exp.e2.type))
return null;
- //printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars());
+ //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
BinExp be = cast(BinExp)exp.copy();
be.e2 = e2;
@@ -10169,7 +10192,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto res = exp.reorderSettingAAElem(sc);
if ((exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign) &&
global.params.useDIP1000 == FeatureState.enabled)
- checkAssignEscape(sc, res, false);
+ checkAssignEscape(sc, res, false, false);
result = res;
}
@@ -12193,7 +12216,7 @@ Expression semanticX(DotIdExp exp, Scope* sc)
if (Expression ex = unaSemantic(exp, sc))
return ex;
- if (exp.ident == Id._mangleof)
+ if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
{
// symbol.mangleof
@@ -12302,6 +12325,8 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
+ const cfile = (sc.flags & SCOPE.Cfile) != 0;
+
/* Special case: rewrite this.id and super.id
* to be classtype.id and baseclasstype.id
* if we have no this pointer.
@@ -12553,7 +12578,16 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
return ErrorExp.get();
}
- else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum && exp.ident != Id._init && exp.ident != Id.__sizeof && exp.ident != Id.__xalignof && exp.ident != Id.offsetof && exp.ident != Id._mangleof && exp.ident != Id.stringof)
+ else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
+ !(
+ exp.ident == Id.__sizeof ||
+ exp.ident == Id.__xalignof ||
+ !cfile &&
+ (exp.ident == Id._mangleof ||
+ exp.ident == Id.offsetof ||
+ exp.ident == Id._init ||
+ exp.ident == Id.stringof)
+ ))
{
Type t1bn = t1b.nextOf();
if (flag)
@@ -12588,7 +12622,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
return e;
}
- else if (sc.flags & SCOPE.Cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp())
+ else if (cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp())
{
// Sizeof string literal includes the terminating 0
auto se = exp.e1.isStringExp();
@@ -12803,129 +12837,125 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
return false;
}
- //printf("checkSharedAccess() %s\n", e.toChars());
-
- static extern(C++) final class SharedCheckVisitor : SemanticTimeTransitiveVisitor
- {
- /// In case we don't know which expression triggered it,
- /// e.g. for `visit(Type)` overload
- Expression original;
- /// Where the result is stored (`true` == error)
- bool result;
- /// Whether we should allow one level of dereferencing
- bool allowRef;
+ //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
- /// Ctor
- this(Expression oe, bool allowRef_)
- {
- this.original = oe;
- this.allowRef = allowRef_;
- }
+ /* In case we don't know which expression triggered it,
+ * e.g. for `visit(Type)` overload
+ */
+ Expression original = e;
- void sharedError(Expression e)
+ bool check(Expression e, bool allowRef)
+ {
+ bool sharedError(Expression e)
{
// https://dlang.org/phobos/core_atomic.html
e.error("direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
- this.result = true;
+ return true;
}
- /// Introduce base class overrides
- alias visit = SemanticTimeTransitiveVisitor.visit;
-
// Error by default
- override void visit(Expression e)
+ bool visit(Expression e)
{
if (e.type.isShared())
- this.sharedError(e);
+ return sharedError(e);
+ return false;
}
- /// Ditto
- override void visit(Type t)
+ bool visitNew(NewExp e)
{
+ if (e.thisexp)
+ check(e.thisexp, false);
// Note: This handles things like `new shared(Throwable).msg`,
// where accessing `msg` would violate `shared`.
- if (t.isShared())
- this.sharedError(this.original);
+ if (e.newtype.isShared())
+ return sharedError(original);
+ return false;
}
- // Those have no indirections / can be ignored
- override void visit(ErrorExp e) {}
- override void visit(ComplexExp e) {}
- override void visit(IntegerExp e) {}
- override void visit(NullExp e) {}
-
- override void visit(VarExp e)
+ bool visitVar(VarExp e)
{
- if (!this.allowRef && e.var.type.isShared())
- this.sharedError(e);
+ if (!allowRef && e.var.type.isShared())
+ return sharedError(e);
+ return false;
}
- override void visit(AddrExp e)
+ bool visitAddr(AddrExp e)
{
- this.allowRef = true;
- e.e1.accept(this);
+ return check(e.e1, true);
}
- override void visit(PtrExp e)
+ bool visitPtr(PtrExp e)
{
- if (!this.allowRef && e.type.isShared())
- return this.sharedError(e);
+ if (!allowRef && e.type.isShared())
+ return sharedError(e);
if (e.e1.type.isShared())
- return this.sharedError(e);
+ return sharedError(e);
- this.allowRef = false;
- e.e1.accept(this);
+ return check(e.e1, false);
}
- override void visit(DotVarExp e)
+ bool visitDotVar(DotVarExp e)
{
auto fd = e.var.isFuncDeclaration();
const sharedFunc = fd && fd.type.isShared;
- if (!this.allowRef && e.type.isShared() && !sharedFunc)
- return this.sharedError(e);
+ if (!allowRef && e.type.isShared() && !sharedFunc)
+ return sharedError(e);
- // Allow to use `DotVarExp` within value types
- if (e.e1.type.ty == Tsarray || e.e1.type.ty == Tstruct)
- return e.e1.accept(this);
+ // Allow using `DotVarExp` within value types
+ if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
+ return check(e.e1, allowRef);
// If we end up with a single `VarExp`, it might be a `ref` param
// `shared ref T` param == `shared(T)*`.
if (auto ve = e.e1.isVarExp())
{
- this.allowRef = this.allowRef && (ve.var.storage_class & STC.ref_);
- return e.e1.accept(this);
+ return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
}
- this.allowRef = false;
- return e.e1.accept(this);
+ return check(e.e1, false);
}
- override void visit(IndexExp e)
+ bool visitIndex(IndexExp e)
{
- if (!this.allowRef && e.type.isShared())
- return this.sharedError(e);
+ if (!allowRef && e.type.isShared())
+ return sharedError(e);
if (e.e1.type.isShared())
- return this.sharedError(e);
+ return sharedError(e);
- this.allowRef = false;
- e.e1.accept(this);
+ return check(e.e1, false);
}
- override void visit(CommaExp e)
+ bool visitComma(CommaExp e)
{
// Cannot be `return ref` since we can't use the return,
// but it's better to show that error than an unrelated `shared` one
- this.allowRef = true;
- e.e2.accept(this);
+ return check(e.e2, true);
+ }
+
+ switch (e.op)
+ {
+ default: return visit(e);
+
+ // Those have no indirections / can be ignored
+ case EXP.call:
+ case EXP.error:
+ case EXP.complex80:
+ case EXP.int64:
+ case EXP.null_: return false;
+
+ case EXP.variable: return visitVar(e.isVarExp());
+ case EXP.new_: return visitNew(e.isNewExp());
+ case EXP.address: return visitAddr(e.isAddrExp());
+ case EXP.star: return visitPtr(e.isPtrExp());
+ case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
+ case EXP.index: return visitIndex(e.isIndexExp());
}
}
- scope visitor = new SharedCheckVisitor(e, returnRef);
- e.accept(visitor);
- return visitor.result;
+ return check(e, returnRef);
}