Hi, This patch merges the D front-end with upstream dmd f4be7f6f7b.
Synchronizing with the upstream development branch as of 2023-10-22. D front-end changes: - Fix bootstrap failure with i686-darwin9. ``` Undefined symbols for architecture i386: "gendocfile", referenced from: __ZL20d_generate_ddoc_fileP6ModuleR9OutBuffer in d-lang.o ld: symbol(s) not found for architecture i386 ``` Bootstrapped and regression tested on x86_64-linux-gnu/-m32, committed to mainline. Regards, Iain. --- gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd f4be7f6f7b. * Make-lang.in (D_FRONTEND_OBJS): Rename d/root-rootobject.o to d/rootobject.o. --- gcc/d/Make-lang.in | 2 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/README.md | 1 + gcc/d/dmd/arraytypes.d | 2 +- gcc/d/dmd/ast_node.d | 2 +- gcc/d/dmd/blockexit.d | 20 +- gcc/d/dmd/cond.d | 2 +- gcc/d/dmd/cppmangle.d | 2 +- gcc/d/dmd/declaration.d | 2 +- gcc/d/dmd/dinterpret.d | 18 +- gcc/d/dmd/dmodule.d | 2 +- gcc/d/dmd/doc.h | 4 +- gcc/d/dmd/dscope.d | 6 - gcc/d/dmd/dsymbol.d | 2 +- gcc/d/dmd/dsymbolsem.d | 8 +- gcc/d/dmd/dtemplate.d | 2 +- gcc/d/dmd/dtoh.d | 2 +- gcc/d/dmd/escape.d | 2 +- gcc/d/dmd/expression.d | 284 +---------------- gcc/d/dmd/expression.h | 1 - gcc/d/dmd/expressionsem.d | 300 ++++++++++++++++-- gcc/d/dmd/foreachvar.d | 2 +- gcc/d/dmd/func.d | 12 +- gcc/d/dmd/hdrgen.d | 2 +- gcc/d/dmd/identifier.d | 2 +- gcc/d/dmd/init.d | 2 +- gcc/d/dmd/json.d | 2 +- gcc/d/dmd/mtype.d | 2 +- gcc/d/dmd/mustuse.d | 23 +- gcc/d/dmd/nogc.d | 2 +- gcc/d/dmd/ob.d | 2 +- gcc/d/dmd/parse.d | 2 +- gcc/d/dmd/{root => }/rootobject.d | 8 +- gcc/d/dmd/semantic2.d | 2 +- gcc/d/dmd/semantic3.d | 2 +- gcc/d/dmd/sideeffect.d | 35 -- gcc/d/dmd/statement.d | 2 +- gcc/d/dmd/statement.h | 3 - gcc/d/dmd/templateparamsem.d | 2 +- gcc/d/dmd/traits.d | 2 +- gcc/d/dmd/transitivevisitor.d | 2 +- gcc/d/dmd/typesem.d | 2 +- gcc/d/dmd/visitor.d | 2 +- .../gdc.test/fail_compilation/fail3882.d | 31 +- gcc/testsuite/gdc.test/runnable/issue24168.d | 31 ++ 45 files changed, 375 insertions(+), 468 deletions(-) rename gcc/d/dmd/{root => }/rootobject.d (88%) create mode 100644 gcc/testsuite/gdc.test/runnable/issue24168.d diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index 264ae03a89e..b3007a96bd0 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -174,11 +174,11 @@ D_FRONTEND_OBJS = \ d/root-port.o \ d/root-region.o \ d/root-rmem.o \ - d/root-rootobject.o \ d/root-speller.o \ d/root-string.o \ d/root-stringtable.o \ d/root-utf.o \ + d/rootobject.o \ d/safe.o \ d/sapply.o \ d/semantic2.o \ diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 794600274a3..bfadeaa0c68 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -4c18eed9674e04c1ca89fbc8bd5c4e483eb5477c +f4be7f6f7bae75f1613b862940cdd533b5ae99b2 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/README.md b/gcc/d/dmd/README.md index d0c75a5b14a..f8ac00117eb 100644 --- a/gcc/d/dmd/README.md +++ b/gcc/d/dmd/README.md @@ -84,6 +84,7 @@ | [astcodegen.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/astcodegen.d) | Namespace of AST nodes of a AST ready for code generation | | [astenums.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/astenums.d) | Enums common to DMD and AST | | [expression.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/expression.d) | Define expression AST nodes | +| [rootobject.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/rootobject.d) | Define an abstract root class | | [statement.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statement.d) | Define statement AST nodes | | [staticassert.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/staticassert.d) | Define a `static assert` AST node | | [aggregate.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/aggregate.d) | Define an aggregate (`struct`, `union` or `class`) AST node | diff --git a/gcc/d/dmd/arraytypes.d b/gcc/d/dmd/arraytypes.d index 34ffa6eb8fd..6634a6af1fc 100644 --- a/gcc/d/dmd/arraytypes.d +++ b/gcc/d/dmd/arraytypes.d @@ -22,7 +22,7 @@ import dmd.identifier; import dmd.init; import dmd.mtype; import dmd.root.array; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.statement; alias Strings = Array!(const(char)*); diff --git a/gcc/d/dmd/ast_node.d b/gcc/d/dmd/ast_node.d index c0dd186628a..313c2bd3691 100644 --- a/gcc/d/dmd/ast_node.d +++ b/gcc/d/dmd/ast_node.d @@ -10,7 +10,7 @@ */ module dmd.ast_node; -import dmd.root.rootobject : RootObject; +import dmd.rootobject : RootObject; import dmd.visitor : Visitor; /// The base class of all AST nodes. diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d index 31a32cf258c..5108ecf7ba7 100644 --- a/gcc/d/dmd/blockexit.d +++ b/gcc/d/dmd/blockexit.d @@ -151,14 +151,7 @@ int blockExit(Statement s, FuncDeclaration func, ErrorSink eSink) } } - if (!(result & BE.fallthru) && !s.comeFrom()) - { - version (none) // this warning is completely useless due to insane false positive rate in real life template code - if (blockExit(s, func, eSink) != BE.halt && s.hasCode() && - s.loc != Loc.initial) // don't emit warning for generated code - global.errorSink.warning(s.loc, "statement is not reachable"); - } - else + if ((result & BE.fallthru) || s.comeFrom()) { result &= ~BE.fallthru; result |= blockExit(s, func, eSink); @@ -447,17 +440,6 @@ int blockExit(Statement s, FuncDeclaration func, ErrorSink eSink) blockExit(s.finalbody, func, eSink); } - version (none) - { - // https://issues.dlang.org/show_bug.cgi?id=13201 - // Mask to prevent spurious warnings for - // destructor call, exit of synchronized statement, etc. - if (result == BE.halt && finalresult != BE.halt && s.finalbody && s.finalbody.hasCode()) - { - eSink.warning(s.finalbody.loc, "statement is not reachable"); - } - } - if (!(finalresult & BE.fallthru)) result &= ~BE.fallthru; result |= finalresult & ~BE.fallthru; diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index 70a7c882eb3..e4d1096db48 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -30,7 +30,7 @@ import dmd.location; import dmd.mtype; import dmd.typesem; import dmd.common.outbuffer; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.string; import dmd.tokens; import dmd.utils; diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index 230bfec17ea..55844ddf606 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/dmd/cppmangle.d @@ -42,7 +42,7 @@ import dmd.mtype; import dmd.nspace; import dmd.root.array; import dmd.common.outbuffer; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.string; import dmd.target; import dmd.typesem; diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index b65e7e833d4..40463b4d970 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -37,7 +37,7 @@ import dmd.intrange; import dmd.location; import dmd.mtype; import dmd.common.outbuffer; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.target; import dmd.tokens; import dmd.typesem; diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index a43be7d2308..fc5a3aaf62c 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -44,7 +44,7 @@ import dmd.root.rmem; import dmd.root.array; import dmd.root.ctfloat; import dmd.root.region; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.utf; import dmd.statement; import dmd.tokens; @@ -4965,6 +4965,22 @@ public: override void visit(CommaExp e) { + /**************************************** + * Find the first non-comma expression. + * Params: + * e = Expressions connected by commas + * Returns: + * left-most non-comma expression + */ + static inout(Expression) firstComma(inout Expression e) + { + Expression ex = cast()e; + while (ex.op == EXP.comma) + ex = (cast(CommaExp)ex).e1; + return cast(inout)ex; + + } + debug (LOG) { printf("%s CommaExp::interpret() %s\n", e.loc.toChars(), e.toChars()); diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 202630304be..9031b157000 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -45,7 +45,7 @@ import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.port; import dmd.root.rmem; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.string; import dmd.semantic2; import dmd.semantic3; diff --git a/gcc/d/dmd/doc.h b/gcc/d/dmd/doc.h index 562427f1a4d..ebd3094348d 100644 --- a/gcc/d/dmd/doc.h +++ b/gcc/d/dmd/doc.h @@ -10,8 +10,10 @@ #pragma once +#include "root/dcompat.h" // for d_size_t + class Module; class ErrorSink; -void gendocfile(Module *m, const char *ddoctext_ptr, size_t ddoctext_length, +void gendocfile(Module *m, const char *ddoctext_ptr, d_size_t ddoctext_length, const char *datetime, ErrorSink *eSink, OutBuffer &outbuf); diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index 981e093934c..14dbe9c6149 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -479,12 +479,6 @@ extern (C++) struct Scope s = *ps; } } - if (!(flags & (SearchImportsOnly | IgnoreErrors)) && - ident == Id.length && sc.scopesym.isArrayScopeSymbol() && - sc.enclosing && sc.enclosing.search(loc, ident, null, flags)) - { - warning(s.loc, "array `length` hides other `length` name in outer scope"); - } //printMsg("\tfound local", s); if (pscopesym) *pscopesym = sc.scopesym; diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 1f4a4664c3e..6538664eace 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -48,7 +48,7 @@ import dmd.nspace; import dmd.opover; import dmd.root.aav; import dmd.root.rmem; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.speller; import dmd.root.string; import dmd.statement; diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 65c07952e00..4de037c8f68 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -62,7 +62,7 @@ import dmd.root.array; import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.rmem; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.utf; import dmd.semantic2; import dmd.semantic3; @@ -3854,12 +3854,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor */ funcdecl.foverrides.push(fdv); - /* Should we really require 'override' when implementing - * an interface function? - */ - //if (!isOverride()) - // warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv.toPrettyChars()); - if (fdv.tintro) ti = fdv.tintro; else if (!funcdecl.type.equals(fdv.type)) diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 23d1140fe38..ae49dda9315 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -70,7 +70,7 @@ import dmd.mtype; import dmd.opover; import dmd.root.array; import dmd.common.outbuffer; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.semantic2; import dmd.semantic3; import dmd.tokens; diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index f906ee12789..7c76da99d1b 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -1813,7 +1813,7 @@ public: { buf.writestring("::"); - import dmd.root.rootobject; + import dmd.rootobject; // Is this even possible? if (arg.dyncast != DYNCAST.identifier) { diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 8562e2eabd6..3f85ea08320 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -32,7 +32,7 @@ import dmd.init; import dmd.location; import dmd.mtype; import dmd.printast; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.tokens; import dmd.visitor; import dmd.arraytypes; diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 720523174b7..2c55f0ebc94 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -56,14 +56,13 @@ import dmd.nspace; import dmd.objc; import dmd.opover; import dmd.optimize; -import dmd.postordervisitor; import dmd.root.complex; import dmd.root.ctfloat; import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.optional; import dmd.root.rmem; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.string; import dmd.root.utf; import dmd.safe; @@ -113,22 +112,6 @@ enum ModifyFlags fieldAssign = 0x2, } -/**************************************** - * Find the first non-comma expression. - * Params: - * e = Expressions connected by commas - * Returns: - * left-most non-comma expression - */ -inout(Expression) firstComma(inout Expression e) -{ - Expression ex = cast()e; - while (ex.op == EXP.comma) - ex = (cast(CommaExp)ex).e1; - return cast(inout)ex; - -} - /**************************************** * Find the last non-comma expression. * Params: @@ -146,59 +129,6 @@ inout(Expression) lastComma(inout Expression e) } -/***************************************** - * Determine if `this` is available by walking up the enclosing - * scopes until a function is found. - * - * Params: - * sc = where to start looking for the enclosing function - * Returns: - * Found function if it satisfies `isThis()`, otherwise `null` - */ -FuncDeclaration hasThis(Scope* sc) -{ - //printf("hasThis()\n"); - Dsymbol p = sc.parent; - while (p && p.isTemplateMixin()) - p = p.parent; - FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null; - //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : ""); - - // Go upwards until we find the enclosing member function - FuncDeclaration fd = fdthis; - while (1) - { - if (!fd) - { - return null; - } - if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2())) - break; - - Dsymbol parent = fd.parent; - while (1) - { - if (!parent) - return null; - TemplateInstance ti = parent.isTemplateInstance(); - if (ti) - parent = ti.parent; - else - break; - } - fd = parent.isFuncDeclaration(); - } - - if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2())) - { - return null; - } - - assert(fd.vthis); - return fd; - -} - /*********************************** * Determine if a `this` is needed to access `d`. * Params: @@ -396,126 +326,6 @@ TemplateDeclaration getFuncTemplateDecl(Dsymbol s) @safe return null; } -/************************************************ - * If we want the value of this expression, but do not want to call - * the destructor on it. - */ -Expression valueNoDtor(Expression e) -{ - auto ex = lastComma(e); - - if (auto ce = ex.isCallExp()) - { - /* The struct value returned from the function is transferred - * so do not call the destructor on it. - * Recognize: - * ((S _ctmp = S.init), _ctmp).this(...) - * and make sure the destructor is not called on _ctmp - * BUG: if ex is a CommaExp, we should go down the right side. - */ - if (auto dve = ce.e1.isDotVarExp()) - { - if (dve.var.isCtorDeclaration()) - { - // It's a constructor call - if (auto comma = dve.e1.isCommaExp()) - { - if (auto ve = comma.e2.isVarExp()) - { - VarDeclaration ctmp = ve.var.isVarDeclaration(); - if (ctmp) - { - ctmp.storage_class |= STC.nodtor; - assert(!ce.isLvalue()); - } - } - } - } - } - } - else if (auto ve = ex.isVarExp()) - { - auto vtmp = ve.var.isVarDeclaration(); - if (vtmp && (vtmp.storage_class & STC.rvalue)) - { - vtmp.storage_class |= STC.nodtor; - } - } - return e; -} - -/********************************************* - * If e is an instance of a struct, and that struct has a copy constructor, - * rewrite e as: - * (tmp = e),tmp - * Input: - * sc = just used to specify the scope of created temporary variable - * destinationType = the type of the object on which the copy constructor is called; - * may be null if the struct defines a postblit - */ -private Expression callCpCtor(Scope* sc, Expression e, Type destinationType) -{ - if (auto ts = e.type.baseElemOf().isTypeStruct()) - { - StructDeclaration sd = ts.sym; - if (sd.postblit || sd.hasCopyCtor) - { - /* Create a variable tmp, and replace the argument e with: - * (tmp = e),tmp - * and let AssignExp() handle the construction. - * This is not the most efficient, ideally tmp would be constructed - * directly onto the stack. - */ - auto tmp = copyToTemp(STC.rvalue, "__copytmp", e); - if (sd.hasCopyCtor && destinationType) - { - // https://issues.dlang.org/show_bug.cgi?id=22619 - // If the destination type is inout we can preserve it - // only if inside an inout function; if we are not inside - // an inout function, then we will preserve the type of - // the source - if (destinationType.hasWild && !(sc.func.storage_class & STC.wild)) - tmp.type = e.type; - else - tmp.type = destinationType; - } - tmp.storage_class |= STC.nodtor; - tmp.dsymbolSemantic(sc); - Expression de = new DeclarationExp(e.loc, tmp); - Expression ve = new VarExp(e.loc, tmp); - de.type = Type.tvoid; - ve.type = e.type; - return Expression.combine(de, ve); - } - } - return e; -} - -/************************************************ - * Handle the postblit call on lvalue, or the move of rvalue. - * - * Params: - * sc = the scope where the expression is encountered - * e = the expression the needs to be moved or copied (source) - * t = if the struct defines a copy constructor, the type of the destination - * - * Returns: - * The expression that copy constructs or moves the value. - */ -extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null) -{ - if (auto ce = e.isCondExp()) - { - ce.e1 = doCopyOrMove(sc, ce.e1); - ce.e2 = doCopyOrMove(sc, ce.e2); - } - else - { - e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e); - } - return e; -} - /****************************************************************/ /* A type meant as a union of all the Expression types, * to serve essentially as a Variant that will sit on the stack @@ -1461,26 +1271,6 @@ extern (C++) abstract class Expression : ASTNode return false; } - extern (D) final bool checkRightThis(Scope* sc) - { - if (op == EXP.error) - return true; - if (op == EXP.variable && type.ty != Terror) - { - VarExp ve = cast(VarExp)this; - if (isNeedThisScope(sc, ve.var)) - { - //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n", - // sc.intypeof, sc.getStructClassScope(), func, fdthis); - auto t = ve.var.isThis(); - assert(t); - error(loc, "accessing non-static variable `%s` requires an instance of `%s`", ve.var.toChars(), t.toChars()); - return true; - } - } - return false; - } - /******************************* * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not. * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics) @@ -6847,78 +6637,6 @@ extern (C++) final class CondExp : BinExp return toLvalue(sc, this); } - void hookDtors(Scope* sc) - { - extern (C++) final class DtorVisitor : StoppableVisitor - { - alias visit = typeof(super).visit; - public: - Scope* sc; - CondExp ce; - VarDeclaration vcond; - bool isThen; - - extern (D) this(Scope* sc, CondExp ce) @safe - { - this.sc = sc; - this.ce = ce; - } - - override void visit(Expression e) - { - //printf("(e = %s)\n", e.toChars()); - } - - override void visit(DeclarationExp e) - { - auto v = e.declaration.isVarDeclaration(); - if (v && !v.isDataseg()) - { - if (v._init) - { - if (auto ei = v._init.isExpInitializer()) - walkPostorder(ei.exp, this); - } - - if (v.edtor) - walkPostorder(v.edtor, this); - - if (v.needsScopeDtor()) - { - if (!vcond) - { - vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd); - vcond.dsymbolSemantic(sc); - - Expression de = new DeclarationExp(ce.econd.loc, vcond); - de = de.expressionSemantic(sc); - - Expression ve = new VarExp(ce.econd.loc, vcond); - ce.econd = Expression.combine(de, ve); - } - - //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars()); - Expression ve = new VarExp(vcond.loc, vcond); - if (isThen) - v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor); - else - v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor); - v.edtor = v.edtor.expressionSemantic(sc); - //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars()); - } - } - } - } - - scope DtorVisitor v = new DtorVisitor(sc, this); - //printf("+%s\n", toChars()); - v.isThen = true; - walkPostorder(e1, v); - v.isThen = false; - walkPostorder(e2, v); - //printf("-%s\n", toChars()); - } - override void accept(Visitor v) { v.visit(this); diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 5c656ee9353..a92d9ada6f5 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -1326,7 +1326,6 @@ public: bool isLvalue() override; Expression *toLvalue(Scope *sc, Expression *e) override; Expression *modifiableLvalue(Scope *sc, Expression *e) override; - void hookDtors(Scope *sc); void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 0bdcda9fe6e..3472f9254cb 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -63,11 +63,12 @@ import dmd.opover; import dmd.optimize; import dmd.parse; import dmd.printast; +import dmd.postordervisitor; import dmd.root.array; import dmd.root.ctfloat; import dmd.root.filename; import dmd.common.outbuffer; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.string; import dmd.root.utf; import dmd.semantic2; @@ -140,6 +141,58 @@ bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps) return false; } +/***************************************** + * Determine if `this` is available by walking up the enclosing + * scopes until a function is found. + * + * Params: + * sc = where to start looking for the enclosing function + * Returns: + * Found function if it satisfies `isThis()`, otherwise `null` + */ +FuncDeclaration hasThis(Scope* sc) +{ + //printf("hasThis()\n"); + Dsymbol p = sc.parent; + while (p && p.isTemplateMixin()) + p = p.parent; + FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null; + //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : ""); + + // Go upwards until we find the enclosing member function + FuncDeclaration fd = fdthis; + while (1) + { + if (!fd) + { + return null; + } + if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2())) + break; + + Dsymbol parent = fd.parent; + while (1) + { + if (!parent) + return null; + TemplateInstance ti = parent.isTemplateInstance(); + if (ti) + parent = ti.parent; + else + break; + } + fd = parent.isFuncDeclaration(); + } + + if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2())) + { + return null; + } + + assert(fd.vthis); + return fd; + +} /*********************************************************** * Resolve `exp` as a compile-time known string. @@ -355,6 +408,126 @@ extern(D) bool arrayExpressionSemantic( return err; } +/************************************************ + * Handle the postblit call on lvalue, or the move of rvalue. + * + * Params: + * sc = the scope where the expression is encountered + * e = the expression the needs to be moved or copied (source) + * t = if the struct defines a copy constructor, the type of the destination + * + * Returns: + * The expression that copy constructs or moves the value. + */ +extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null) +{ + if (auto ce = e.isCondExp()) + { + ce.e1 = doCopyOrMove(sc, ce.e1); + ce.e2 = doCopyOrMove(sc, ce.e2); + } + else + { + e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e); + } + return e; +} + +/********************************************* + * If e is an instance of a struct, and that struct has a copy constructor, + * rewrite e as: + * (tmp = e),tmp + * Input: + * sc = just used to specify the scope of created temporary variable + * destinationType = the type of the object on which the copy constructor is called; + * may be null if the struct defines a postblit + */ +private Expression callCpCtor(Scope* sc, Expression e, Type destinationType) +{ + if (auto ts = e.type.baseElemOf().isTypeStruct()) + { + StructDeclaration sd = ts.sym; + if (sd.postblit || sd.hasCopyCtor) + { + /* Create a variable tmp, and replace the argument e with: + * (tmp = e),tmp + * and let AssignExp() handle the construction. + * This is not the most efficient, ideally tmp would be constructed + * directly onto the stack. + */ + auto tmp = copyToTemp(STC.rvalue, "__copytmp", e); + if (sd.hasCopyCtor && destinationType) + { + // https://issues.dlang.org/show_bug.cgi?id=22619 + // If the destination type is inout we can preserve it + // only if inside an inout function; if we are not inside + // an inout function, then we will preserve the type of + // the source + if (destinationType.hasWild && !(sc.func.storage_class & STC.wild)) + tmp.type = e.type; + else + tmp.type = destinationType; + } + tmp.storage_class |= STC.nodtor; + tmp.dsymbolSemantic(sc); + Expression de = new DeclarationExp(e.loc, tmp); + Expression ve = new VarExp(e.loc, tmp); + de.type = Type.tvoid; + ve.type = e.type; + return Expression.combine(de, ve); + } + } + return e; +} + +/************************************************ + * If we want the value of this expression, but do not want to call + * the destructor on it. + */ +Expression valueNoDtor(Expression e) +{ + auto ex = lastComma(e); + + if (auto ce = ex.isCallExp()) + { + /* The struct value returned from the function is transferred + * so do not call the destructor on it. + * Recognize: + * ((S _ctmp = S.init), _ctmp).this(...) + * and make sure the destructor is not called on _ctmp + * BUG: if ex is a CommaExp, we should go down the right side. + */ + if (auto dve = ce.e1.isDotVarExp()) + { + if (dve.var.isCtorDeclaration()) + { + // It's a constructor call + if (auto comma = dve.e1.isCommaExp()) + { + if (auto ve = comma.e2.isVarExp()) + { + VarDeclaration ctmp = ve.var.isVarDeclaration(); + if (ctmp) + { + ctmp.storage_class |= STC.nodtor; + assert(!ce.isLvalue()); + } + } + } + } + } + } + else if (auto ve = ex.isVarExp()) + { + auto vtmp = ve.var.isVarDeclaration(); + if (vtmp && (vtmp.storage_class & STC.rvalue)) + { + vtmp.storage_class |= STC.nodtor; + } + } + return e; +} + /* Checks if `exp` contains a direct access to a `noreturn` variable. If that is the case, an `assert(0)` expression @@ -493,6 +666,78 @@ private bool isDotOpDispatch(Expression e) return false; } +private void hookDtors(CondExp ce, Scope* sc) +{ + extern (C++) final class DtorVisitor : StoppableVisitor + { + alias visit = typeof(super).visit; + public: + Scope* sc; + CondExp ce; + VarDeclaration vcond; + bool isThen; + + extern (D) this(Scope* sc, CondExp ce) @safe + { + this.sc = sc; + this.ce = ce; + } + + override void visit(Expression e) + { + //printf("(e = %s)\n", e.toChars()); + } + + override void visit(DeclarationExp e) + { + auto v = e.declaration.isVarDeclaration(); + if (v && !v.isDataseg()) + { + if (v._init) + { + if (auto ei = v._init.isExpInitializer()) + walkPostorder(ei.exp, this); + } + + if (v.edtor) + walkPostorder(v.edtor, this); + + if (v.needsScopeDtor()) + { + if (!vcond) + { + vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd); + vcond.dsymbolSemantic(sc); + + Expression de = new DeclarationExp(ce.econd.loc, vcond); + de = de.expressionSemantic(sc); + + Expression ve = new VarExp(ce.econd.loc, vcond); + ce.econd = Expression.combine(de, ve); + } + + //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars()); + Expression ve = new VarExp(vcond.loc, vcond); + if (isThen) + v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor); + else + v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor); + v.edtor = v.edtor.expressionSemantic(sc); + //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars()); + } + } + } + } + + scope DtorVisitor v = new DtorVisitor(sc, ce); + //printf("+%s\n", toChars()); + v.isThen = true; + walkPostorder(ce.e1, v); + v.isThen = false; + walkPostorder(ce.e2, v); + //printf("-%s\n", toChars()); +} + /****************************** * Pull out callable entity with UFCS. @@ -1516,6 +1761,26 @@ Leprop: return ErrorExp.get(); } +private bool checkRightThis(Expression e, Scope* sc) +{ + if (e.op == EXP.error) + return true; + if (e.op == EXP.variable && e.type.ty != Terror) + { + VarExp ve = cast(VarExp)e; + if (isNeedThisScope(sc, ve.var)) + { + //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n", + // sc.intypeof, sc.getStructClassScope(), func, fdthis); + auto t = ve.var.isThis(); + assert(t); + error(e.loc, "accessing non-static variable `%s` requires an instance of `%s`", ve.var.toChars(), t.toChars()); + return true; + } + } + return false; +} + extern (C++) Expression resolveProperties(Scope* sc, Expression e) { //printf("resolveProperties(%s)\n", e.toChars()); @@ -10085,24 +10350,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - version (none) - { - if (global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign && - e2x.op != EXP.slice && e2x.op != EXP.assign && - e2x.op != EXP.arrayLiteral && e2x.op != EXP.string_ && - !(e2x.op == EXP.add || e2x.op == EXP.min || - e2x.op == EXP.mul || e2x.op == EXP.div || - e2x.op == EXP.mod || e2x.op == EXP.xor || - e2x.op == EXP.and || e2x.op == EXP.or || - e2x.op == EXP.pow || - e2x.op == EXP.tilde || e2x.op == EXP.negate)) - { - const(char)* e1str = exp.e1.toChars(); - const(char)* e2str = e2x.toChars(); - exp.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str, e2str, e1str, e2str); - } - } - Type t2n = t2.nextOf(); Type t1n = t1.nextOf(); int offset; @@ -10149,21 +10396,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else { - version (none) - { - if (global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign && - t1.ty == Tarray && t2.ty == Tsarray && - e2x.op != EXP.slice && - t2.implicitConvTo(t1)) - { - // Disallow ar[] = sa (Converted to ar[] = sa[]) - // Disallow da = sa (Converted to da = sa[]) - const(char)* e1str = exp.e1.toChars(); - const(char)* e2str = e2x.toChars(); - const(char)* atypestr = exp.e1.op == EXP.slice ? "element-wise" : "slice"; - exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str); - } - } if (exp.op == EXP.blit) e2x = e2x.castTo(sc, exp.e1.type); else diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/foreachvar.d index 8af2a95252e..dc4b20bf957 100644 --- a/gcc/d/dmd/foreachvar.d +++ b/gcc/d/dmd/foreachvar.d @@ -35,7 +35,7 @@ import dmd.mtype; import dmd.postordervisitor; import dmd.printast; import dmd.root.array; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.statement; import dmd.tokens; import dmd.visitor; diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 81bb028964f..ac73e70db34 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -48,7 +48,7 @@ import dmd.mtype; import dmd.objc; import dmd.root.aav; import dmd.common.outbuffer; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.string; import dmd.root.stringtable; import dmd.semantic2; @@ -4620,15 +4620,7 @@ bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char) case default_: if (!sc.func) return false; - if (sc.func.isSafeBypassingInference()) - { - if (!gag) - { - version (none) // disable obsolete warning - warning(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : ""); - } - } - else if (!sc.func.safetyViolation) + if (!sc.func.isSafeBypassingInference() && !sc.func.safetyViolation) { import dmd.func : AttributeViolation; sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2); diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 056e486e927..9d585cb898b 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -45,7 +45,7 @@ import dmd.parse; import dmd.root.complex; import dmd.root.ctfloat; import dmd.common.outbuffer; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.string; import dmd.statement; import dmd.staticassert; diff --git a/gcc/d/dmd/identifier.d b/gcc/d/dmd/identifier.d index 3173445fddc..c2b2fbafa25 100644 --- a/gcc/d/dmd/identifier.d +++ b/gcc/d/dmd/identifier.d @@ -17,7 +17,7 @@ import core.stdc.string; import dmd.id; import dmd.location; import dmd.common.outbuffer; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.string; import dmd.root.stringtable; import dmd.root.utf; diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d index ecca5528352..ebcd011f8a1 100644 --- a/gcc/d/dmd/init.d +++ b/gcc/d/dmd/init.d @@ -25,7 +25,7 @@ import dmd.identifier; import dmd.location; import dmd.mtype; import dmd.common.outbuffer; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.tokens; import dmd.visitor; diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d index f1999fd458d..11ab8169099 100644 --- a/gcc/d/dmd/json.d +++ b/gcc/d/dmd/json.d @@ -35,7 +35,7 @@ import dmd.identifier; import dmd.location; import dmd.mtype; import dmd.common.outbuffer; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.string; import dmd.target; import dmd.visitor; diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 01f94a7b04d..70a0c032e65 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -46,7 +46,7 @@ import dmd.opover; import dmd.root.ctfloat; import dmd.common.outbuffer; import dmd.root.rmem; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.stringtable; import dmd.target; import dmd.tokens; diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d index 1d831bbed6b..693464919e0 100644 --- a/gcc/d/dmd/mustuse.d +++ b/gcc/d/dmd/mustuse.d @@ -18,17 +18,6 @@ import dmd.globals; import dmd.identifier; import dmd.location; -// Used in isIncrementOrDecrement -private const StringExp plusPlus, minusMinus; - -// Loc.initial cannot be used in static initializers, so -// these need a static constructor. -shared static this() -{ - plusPlus = new StringExp(Loc.initial, "++"); - minusMinus = new StringExp(Loc.initial, "--"); -} - /** * Check whether discarding an expression would violate the requirements of * @mustuse. If so, emit an error. @@ -173,9 +162,15 @@ private bool isIncrementOrDecrement(Expression e) { if (auto argExp = (*tiargs)[0].isExpression()) { - auto op = argExp.isStringExp(); - if (op && (op.compare(plusPlus) == 0 || op.compare(minusMinus) == 0)) - return true; + if (auto op = argExp.isStringExp()) + { + if (op.len == 2 && op.sz == 1) + { + const s = op.peekString(); + if (s == "++" || s == "--") + return true; + } + } } } } diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index 560606190e0..59bf1d5d1d5 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -256,7 +256,7 @@ private FuncDeclaration stripHookTraceImpl(FuncDeclaration fd) { import dmd.id : Id; import dmd.dsymbol : Dsymbol; - import dmd.root.rootobject : RootObject, DYNCAST; + import dmd.rootobject : RootObject, DYNCAST; if (fd.ident != Id._d_HookTraceImpl) return fd; diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index 8b30681afc0..dc94aecc61b 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -16,7 +16,7 @@ import core.stdc.stdlib; import core.stdc.string; import dmd.root.array; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.rmem; import dmd.aggregate; diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 3821f947a97..9a13d5c254e 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -25,7 +25,7 @@ import dmd.location; import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.rmem; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.string; import dmd.tokens; diff --git a/gcc/d/dmd/root/rootobject.d b/gcc/d/dmd/rootobject.d similarity index 88% rename from gcc/d/dmd/root/rootobject.d rename to gcc/d/dmd/rootobject.d index 65c499ddf4e..7867ad5de31 100644 --- a/gcc/d/dmd/root/rootobject.d +++ b/gcc/d/dmd/rootobject.d @@ -4,12 +4,12 @@ * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/rootobject.d, root/_rootobject.d) - * Documentation: https://dlang.org/phobos/dmd_root_rootobject.html - * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/rootobject.d + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/rootobject.d, _rootobject.d) + * Documentation: https://dlang.org/phobos/dmd_rootobject.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/rootobject.d */ -module dmd.root.rootobject; +module dmd.rootobject; /*********************************************************** */ diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index 6a3795178d3..036560b5407 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -55,7 +55,7 @@ import dmd.parse; import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.rmem; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.utf; import dmd.sideeffect; import dmd.statementsem; diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index e0931409df8..2f1839cdac1 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -58,7 +58,7 @@ import dmd.parse; import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.rmem; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.utf; import dmd.sideeffect; import dmd.statementsem; diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index de92b294c14..465bffe4da0 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/dmd/sideeffect.d @@ -269,41 +269,6 @@ bool discardValue(Expression e) break; } case EXP.call: - /* Issue 3882: */ - if (global.params.warnings != DiagnosticReporting.off && !global.gag) - { - CallExp ce = cast(CallExp)e; - if (e.type.ty == Tvoid) - { - /* Don't complain about calling void-returning functions with no side-effect, - * because purity and nothrow are inferred, and because some of the - * runtime library depends on it. Needs more investigation. - * - * One possible solution is to restrict this message to only be called in hierarchies that - * never call assert (and or not called from inside unittest blocks) - */ - } - else if (ce.e1.type) - { - Type t = ce.e1.type.toBasetype(); - if (t.ty == Tdelegate) - t = (cast(TypeDelegate)t).next; - if (t.ty == Tfunction && (ce.f ? callSideEffectLevel(ce.f) : callSideEffectLevel(ce.e1.type)) > 0) - { - const(char)* s; - if (ce.f) - s = ce.f.toPrettyChars(); - else if (ce.e1.op == EXP.star) - { - // print 'fp' if ce.e1 is (*fp) - s = (cast(PtrExp)ce.e1).e1.toChars(); - } - else - s = ce.e1.toChars(); - warning(e.loc, "calling `%s` without side effects discards return value of type `%s`; prepend a `cast(void)` if intentional", s, e.type.toChars()); - } - } - } return false; case EXP.andAnd: case EXP.orOr: diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d index da26bc980e8..5a31e07dc0f 100644 --- a/gcc/d/dmd/statement.d +++ b/gcc/d/dmd/statement.d @@ -33,7 +33,7 @@ import dmd.identifier; import dmd.location; import dmd.mtype; import dmd.common.outbuffer; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.sapply; import dmd.staticassert; import dmd.tokens; diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h index fe899c6a496..73feb3f912b 100644 --- a/gcc/d/dmd/statement.h +++ b/gcc/d/dmd/statement.h @@ -113,9 +113,6 @@ public: virtual Statement *syntaxCopy(); - void error(const char *format, ...); - void warning(unsigned flag, const char *format, ...); - void deprecation(const char *format, ...); virtual Statement *getRelatedLabeled() { return this; } virtual bool hasBreak() const; virtual bool hasContinue() const; diff --git a/gcc/d/dmd/templateparamsem.d b/gcc/d/dmd/templateparamsem.d index 6b8f949f526..de40c1f2bb2 100644 --- a/gcc/d/dmd/templateparamsem.d +++ b/gcc/d/dmd/templateparamsem.d @@ -19,7 +19,7 @@ import dmd.globals; import dmd.location; import dmd.expression; import dmd.expressionsem; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.mtype; import dmd.typesem; import dmd.visitor; diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index bdc569c8725..254900e6030 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -49,7 +49,7 @@ import dmd.target; import dmd.tokens; import dmd.typesem; import dmd.visitor; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.common.outbuffer; import dmd.root.string; diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d index 376c12fa808..bf1d38e61ca 100644 --- a/gcc/d/dmd/transitivevisitor.d +++ b/gcc/d/dmd/transitivevisitor.d @@ -8,7 +8,7 @@ module dmd.transitivevisitor; import dmd.astenums; import dmd.permissivevisitor; import dmd.tokens; -import dmd.root.rootobject; +import dmd.rootobject; import core.stdc.stdio; diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index c69268a80ed..fe54e293750 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -57,7 +57,7 @@ import dmd.root.complex; import dmd.root.ctfloat; import dmd.root.rmem; import dmd.common.outbuffer; -import dmd.root.rootobject; +import dmd.rootobject; import dmd.root.string; import dmd.root.stringtable; import dmd.safe; diff --git a/gcc/d/dmd/visitor.d b/gcc/d/dmd/visitor.d index 591d3c0c3b4..5722e10d256 100644 --- a/gcc/d/dmd/visitor.d +++ b/gcc/d/dmd/visitor.d @@ -17,7 +17,7 @@ import dmd.parsetimevisitor; import dmd.tokens; import dmd.transitivevisitor; import dmd.expression; -import dmd.root.rootobject; +import dmd.rootobject; /** * Classic Visitor class which implements visit methods for all the AST diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3882.d b/gcc/testsuite/gdc.test/fail_compilation/fail3882.d index 27ddad41604..9647f08805b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail3882.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3882.d @@ -1,18 +1,17 @@ -// REQUIRED_ARGS: -w -// PERMUTE_ARGS: -debug - -/******************************************/ -// https://issues.dlang.org/show_bug.cgi?id=3882 - /* +PERMUTE_ARGS: -debug TEST_OUTPUT: --- -fail_compilation/fail3882.d(23): Warning: calling `fail3882.strictlyPure!int.strictlyPure` without side effects discards return value of type `int`; prepend a `cast(void)` if intentional -fail_compilation/fail3882.d(27): Warning: calling `fp` without side effects discards return value of type `int`; prepend a `cast(void)` if intentional +fail_compilation/fail3882.d(32): Error: `@mustuse` on functions is reserved for future use +fail_compilation/fail3882.d(33): Error: `@mustuse` on functions is reserved for future use --- */ +import core.attribute; + +/******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=3882 -@safe pure nothrow T strictlyPure(T)(T x) +@mustuse @safe pure nothrow T strictlyPure(T)(T x) { return x*x; } @@ -30,18 +29,8 @@ void main() /******************************************/ // bugfix in TypeFunction::purityLevel -/* -TEST_OUTPUT: ---- -fail_compilation/fail3882.d(48): Warning: calling `fail3882.f1` without side effects discards return value of type `int`; prepend a `cast(void)` if intentional -fail_compilation/fail3882.d(49): Warning: calling `fail3882.f2` without side effects discards return value of type `int`; prepend a `cast(void)` if intentional -Error: warnings are treated as errors - Use -wi if you wish to treat warnings only as informational. ---- -*/ - -nothrow pure int f1(immutable(int)[] a) { return 0; } -nothrow pure int f2(immutable(int)* p) { return 0; } +@mustuse nothrow pure int f1(immutable(int)[] a) { return 0; } +@mustuse nothrow pure int f2(immutable(int)* p) { return 0; } void test_bug() { diff --git a/gcc/testsuite/gdc.test/runnable/issue24168.d b/gcc/testsuite/gdc.test/runnable/issue24168.d new file mode 100644 index 00000000000..c21a35bc9d4 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/issue24168.d @@ -0,0 +1,31 @@ +/* +REQUIRED_ARGS: -fPIE +DISABLED: win32 win64 +*/ + +//https://issues.dlang.org/show_bug.cgi?id=24168 + +int i = 42; + +bool foo(ref int a) +{ + return a == 42; +} + +ref int bar() +{ + return i; +} + +bool baz() +{ + static int i = 42; + return foo(i); +} + +void main() +{ + assert(foo(i)); + assert(bar() == 42); + assert(baz()); +} -- 2.39.2