diff options
Diffstat (limited to 'gcc/d/dmd/expressionsem.d')
-rw-r--r-- | gcc/d/dmd/expressionsem.d | 218 |
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); } |