diff options
Diffstat (limited to 'gcc/d/dmd')
51 files changed, 861 insertions, 487 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 95ea67d..1cff48a 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -28a3b24c2e45de39cd3df528142fd06b6456e8fd +17ccd12af386543c0b9935bf7e0a8e701b903105 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 57f56f3..79215b7 100644 --- a/gcc/d/dmd/README.md +++ b/gcc/d/dmd/README.md @@ -99,7 +99,7 @@ Note that these groups have no strict meaning, the category assignments are a bi | [strictvisitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/strictvisitor.d) | Visitor that forces derived classes to implement `visit` for every possible node | | [visitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor.d) | A visitor implementing `visit` for all nodes present in the compiler | | [transitivevisitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/transitivevisitor.d) | Provide a mixin template with visit methods for the parse time AST | -| [apply.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/apply.d) | Depth-first expression visitor | +| [postordervisitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/postordervisitor.d) | Depth-first expression visitor | | [sapply.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/sapply.d) | Depth-first statement visitor | | [statement_rewrite_walker.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statement_rewrite_walker.d) | Statement visitor that allows replacing the currently visited node | diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 7cf9127..d5aee89 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.104.0-beta.1 +v2.104.0 diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index 1306a10..42b926b 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -18,7 +18,6 @@ import core.stdc.stdio; import core.checkedint; import dmd.aliasthis; -import dmd.apply; import dmd.arraytypes; import dmd.astenums; import dmd.attrib; @@ -764,21 +763,18 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol if (s) { // Finish all constructors semantics to determine this.noDefaultCtor. - struct SearchCtor + static int searchCtor(Dsymbol s, void*) { - extern (C++) static int fp(Dsymbol s, void* ctxt) - { - auto f = s.isCtorDeclaration(); - if (f && f.semanticRun == PASS.initial) - f.dsymbolSemantic(null); - return 0; - } + auto f = s.isCtorDeclaration(); + if (f && f.semanticRun == PASS.initial) + f.dsymbolSemantic(null); + return 0; } for (size_t i = 0; i < members.length; i++) { auto sm = (*members)[i]; - sm.apply(&SearchCtor.fp, null); + sm.apply(&searchCtor, null); } } return s; @@ -814,3 +810,36 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol v.visit(this); } } + +/********************************* + * Iterate this dsymbol or members of this scoped dsymbol, then + * call `fp` with the found symbol and `params`. + * Params: + * symbol = the dsymbol or parent of members to call fp on + * fp = function pointer to process the iterated symbol. + * If it returns nonzero, the iteration will be aborted. + * ctx = context parameter passed to fp. + * Returns: + * nonzero if the iteration is aborted by the return value of fp, + * or 0 if it's completed. + */ +int apply(Dsymbol symbol, int function(Dsymbol, void*) fp, void* ctx) +{ + if (auto nd = symbol.isNspace()) + { + return nd.members.foreachDsymbol( (s) { return s && s.apply(fp, ctx); } ); + } + if (auto ad = symbol.isAttribDeclaration()) + { + return ad.include(ad._scope).foreachDsymbol( (s) { return s && s.apply(fp, ctx); } ); + } + if (auto tm = symbol.isTemplateMixin()) + { + if (tm._scope) // if fwd reference + dsymbolSemantic(tm, null); // try to resolve it + + return tm.members.foreachDsymbol( (s) { return s && s.apply(fp, ctx); } ); + } + + return fp(symbol, ctx); +} diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d index 7dfec8a..09d39ca 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -14,7 +14,6 @@ module dmd.canthrow; import dmd.aggregate; -import dmd.apply; import dmd.arraytypes; import dmd.attrib; import dmd.astenums; @@ -26,6 +25,7 @@ import dmd.func; import dmd.globals; import dmd.init; import dmd.mtype; +import dmd.postordervisitor; import dmd.root.rootobject; import dmd.tokens; import dmd.visitor; @@ -133,16 +133,9 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN */ if (ce.f && ce.f == func) return; - Type t = ce.e1.type.toBasetype(); - auto tf = t.isTypeFunction(); + const tf = ce.calledFunctionType(); if (tf && tf.isnothrow) return; - else - { - auto td = t.isTypeDelegate(); - if (td && td.nextOf().isTypeFunction().isnothrow) - return; - } if (ce.f) checkFuncThrows(ce, ce.f); diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d index 21a1b5e..feaa3c7 100644 --- a/gcc/d/dmd/chkformat.d +++ b/gcc/d/dmd/chkformat.d @@ -177,6 +177,8 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre errorMsg(null, e, (c_longsize == 4 ? "uint" : "ulong"), t); else errorMsg(null, e, (c_longsize == 4 ? "int" : "long"), t); + if (t.isintegral() && t.size() != c_longsize) + errorSupplemental(e.loc, "C `long` is %d bytes on your system", c_longsize); } break; diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index 60e373c..3586f20 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -106,18 +106,18 @@ FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc) scope er = new NullExp(ad.loc, ad.type); // dummy rvalue scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue el.type = ad.type; - auto a = Expressions(1); + auto a = new Expressions(1); const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it. sc = sc.push(); sc.tinst = null; sc.minst = null; - a[0] = er; - auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(&a), FuncResolveFlag.quiet); + (*a)[0] = er; + auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(a), FuncResolveFlag.quiet); if (!f) { - a[0] = el; - f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(&a), FuncResolveFlag.quiet); + (*a)[0] = el; + f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(a), FuncResolveFlag.quiet); } sc = sc.pop(); @@ -465,7 +465,7 @@ private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc) */ scope er = new NullExp(ad.loc, null); // dummy rvalue scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue - auto a = Expressions(1); + auto a = new Expressions(1); bool hasIt(Type tthis) { @@ -476,9 +476,9 @@ private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc) FuncDeclaration rfc(Expression e) { - a[0] = e; - a[0].type = tthis; - return resolveFuncCall(ad.loc, sc, eq, null, tthis, ArgumentList(&a), FuncResolveFlag.quiet); + (*a)[0] = e; + (*a)[0].type = tthis; + return resolveFuncCall(ad.loc, sc, eq, null, tthis, ArgumentList(a), FuncResolveFlag.quiet); } f = rfc(er); diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index c40936c..fcb50e0 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -259,7 +259,7 @@ extern (C++) final class StaticForeach : RootObject auto sdecl = new StructDeclaration(loc, sid, false); sdecl.storage_class |= STC.static_; sdecl.members = new Dsymbols(); - auto fid = Identifier.idPool(tupleFieldName.ptr, tupleFieldName.length); + auto fid = Identifier.idPool(tupleFieldName); auto ty = new TypeTypeof(loc, new TupleExp(loc, e)); sdecl.members.push(new VarDeclaration(loc, ty, fid, null, 0)); auto r = cast(TypeStruct)sdecl.type; diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 9b7db1f..33669e3 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -324,6 +324,8 @@ final class CParser(AST) : Parser!AST // atomic-type-specifier or type_qualifier case TOK._Atomic: + case TOK.__attribute__: + Ldeclaration: { cparseDeclaration(LVL.local); @@ -2356,6 +2358,8 @@ final class CParser(AST) : Parser!AST cparseGnuAttributes(tagSpecifier); else if (token.value == TOK.__declspec) cparseDeclspec(tagSpecifier); + else if (token.value == TOK.__pragma) + uupragmaDirective(sloc); else break; } @@ -2710,7 +2714,7 @@ final class CParser(AST) : Parser!AST * * Params: * declarator = declarator kind - * t = base type to start with + * tbase = base type to start with * pident = set to Identifier if there is one, null if not * specifier = specifiers in and out * Returns: @@ -2718,12 +2722,26 @@ final class CParser(AST) : Parser!AST * symbol table for the parameter-type-list, which will contain any * declared struct, union or enum tags. */ - private AST.Type cparseDeclarator(DTR declarator, AST.Type t, + private AST.Type cparseDeclarator(DTR declarator, AST.Type tbase, out Identifier pident, ref Specifier specifier) { //printf("cparseDeclarator(%d, %p)\n", declarator, t); AST.Types constTypes; // all the Types that will need `const` applied to them + /* Insert tx -> t into + * ts -> ... -> t + * so that + * ts -> ... -> tx -> t + */ + static void insertTx(ref AST.Type ts, AST.Type tx, AST.Type t) + { + AST.Type* pt; + for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next) + { + } + *pt = tx; + } + AST.Type parseDecl(AST.Type t) { AST.Type ts; @@ -2789,20 +2807,6 @@ final class CParser(AST) : Parser!AST // parse DeclaratorSuffixes while (1) { - /* Insert tx -> t into - * ts -> ... -> t - * so that - * ts -> ... -> tx -> t - */ - static void insertTx(ref AST.Type ts, AST.Type tx, AST.Type t) - { - AST.Type* pt; - for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next) - { - } - *pt = tx; - } - switch (token.value) { case TOK.leftBracket: @@ -2915,7 +2919,17 @@ final class CParser(AST) : Parser!AST return ts; } - t = parseDecl(t); + auto t = parseDecl(tbase); + + if (specifier.vector_size) + { + auto length = new AST.IntegerExp(token.loc, specifier.vector_size / tbase.size(), AST.Type.tuns32); + auto tsa = new AST.TypeSArray(tbase, length); + AST.Type tv = new AST.TypeVector(tsa); + specifier.vector_size = 0; // used it up + + insertTx(t, tv, tbase); // replace tbase with tv + } /* Because const is transitive, cannot assemble types from * fragments. Instead, types to be annotated with const are put @@ -3553,7 +3567,19 @@ final class CParser(AST) : Parser!AST { nextToken(); check(TOK.leftParenthesis); - cparseConstantExp(); // TODO implement + if (token.value == TOK.int32Literal) + { + const n = token.unsvalue; + if (n < 1 || n & (n - 1) || ushort.max < n) + error("__attribute__((vector_size(%lld))) must be an integer positive power of 2 and be <= 32,768", cast(ulong)n); + specifier.vector_size = cast(uint) n; + nextToken(); + } + else + { + error("value for vector_size expected, not `%s`", token.toChars()); + nextToken(); + } check(TOK.rightParenthesis); } else @@ -3852,6 +3878,10 @@ final class CParser(AST) : Parser!AST else if (!tag) error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion)); + // many ways and places to declare alignment + if (packalign.isUnknown() && !this.packalign.isUnknown()) + packalign.set(this.packalign.get()); + /* Need semantic information to determine if this is a declaration, * redeclaration, or reference to existing declaration. * Defer to the semantic() pass with a TypeTag. @@ -4694,6 +4724,7 @@ final class CParser(AST) : Parser!AST // atomic-type-specifier case TOK._Atomic: case TOK.typeof_: + case TOK.__attribute__: t = peek(t); if (t.value != TOK.leftParenthesis || !skipParens(t, &t)) @@ -4959,6 +4990,7 @@ final class CParser(AST) : Parser!AST bool dllexport; /// dllexport attribute bool _deprecated; /// deprecated attribute AST.Expression depMsg; /// deprecated message + uint vector_size; /// positive power of 2 multipe of base type size SCW scw; /// storage-class specifiers MOD mod; /// type qualifiers @@ -5400,6 +5432,24 @@ final class CParser(AST) : Parser!AST pragmaDirective(scanloc); return true; } + else if (n.ident == Id.ident) // #ident "string" + { + scan(&n); + if (n.value == TOK.string_ && n.ptr[0] == '"' && n.postfix == 0) + { + /* gcc inserts string into the .comment section in the object file. + * Just ignore it for now, but can support it later by writing + * the string to obj_exestr() + */ + //auto comment = n.ustring; + + scan(&n); + if (n.value == TOK.endOfFile || n.value == TOK.endOfLine) + return true; + } + error("\"string\" expected after `#ident`"); + return false; + } } if (n.ident != Id.undef) error("C preprocessor directive `#%s` is not supported", n.toChars()); @@ -5416,20 +5466,39 @@ final class CParser(AST) : Parser!AST private void uupragmaDirective(const ref Loc startloc) { const loc = startloc; - nextToken(); + nextToken(); // move past __pragma if (token.value != TOK.leftParenthesis) { - error(loc, "left parenthesis expected to follow `__pragma`"); + error(loc, "left parenthesis expected to follow `__pragma` instead of `%s`", token.toChars()); + nextToken(); return; } nextToken(); - if (token.value == TOK.identifier && token.ident == Id.pack) - pragmaPack(startloc, false); + + if (token.value == TOK.identifier) + { + if (token.ident == Id.pack) + pragmaPack(startloc, false); + else + { + nextToken(); + if (token.value == TOK.leftParenthesis) + cparseParens(); + } + + } + else if (token.value == TOK.endOfFile) + { + } + else if (token.value == TOK.rightParenthesis) + { + } else - error(loc, "unrecognized __pragma"); + error(loc, "unrecognized `__pragma(%s)`", token.toChars()); + if (token.value != TOK.rightParenthesis) { - error(loc, "right parenthesis expected to close `__pragma(...)`"); + error(loc, "right parenthesis expected to close `__pragma(...)` instead of `%s`", token.toChars()); return; } nextToken(); diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index 40092c3..ee1340d 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/dmd/cppmangle.d @@ -446,7 +446,15 @@ private final class CppMangleVisitor : Visitor if (this.context.res.dyncast() == DYNCAST.dsymbol) parentti = this.context.res.asFuncDecl().parent.isTemplateInstance(); else - parentti = this.context.res.asType().toDsymbol(null).parent.isTemplateInstance(); + { + auto parent = this.context.res.asType().toDsymbol(null).parent; + parentti = parent.isTemplateInstance(); + // https://issues.dlang.org/show_bug.cgi?id=22760 + // The template instance may sometimes have the form + // S1!int.S1, therefore the above instruction might yield null + if (parentti is null && parent.parent) + parentti = parent.parent.isTemplateInstance(); + } return (*parentti.tiargs)[arg]; }()); scope (exit) this.context.pop(prev); diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 8ffbef3c..6fcc280 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -71,6 +71,8 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t) if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t)) { + // no need for an extra cast when matching is exact + if (match == MATCH.convert && e.type.isTypeNoreturn()) { return specialNoreturnCast(e, t); @@ -88,6 +90,8 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t) auto ad = isAggregate(e.type); if (ad && ad.aliasthis) { + if (!ad.type || ad.type.isTypeError()) + return e; auto ts = ad.type.isTypeStruct(); const adMatch = ts ? ts.implicitConvToWithoutAliasThis(t) diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index e458593..1b8e8ef 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -17,7 +17,6 @@ import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; -import dmd.apply; import dmd.arraytypes; import dmd.astenums; import dmd.attrib; @@ -867,7 +866,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration * Resolve forward references to all class member functions, * and determine whether this class is abstract. */ - static int func(Dsymbol s) + static int func(Dsymbol s, void*) { auto fd = s.isFuncDeclaration(); if (!fd) @@ -883,7 +882,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration for (size_t i = 0; i < members.length; i++) { auto s = (*members)[i]; - if (s.apply(&func)) + if (s.apply(&func, null)) { return yes(); } @@ -910,7 +909,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration * each of the virtual functions, * which will fill in the vtbl[] overrides. */ - static int virtualSemantic(Dsymbol s) + static int virtualSemantic(Dsymbol s, void*) { auto fd = s.isFuncDeclaration(); if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration()) @@ -921,7 +920,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration for (size_t i = 0; i < members.length; i++) { auto s = (*members)[i]; - s.apply(&virtualSemantic); + s.apply(&virtualSemantic,null); } } diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 0e5df5e..cfa6988 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -44,6 +44,10 @@ import dmd.tokens; import dmd.typesem; import dmd.visitor; +version (IN_GCC) {} +else version (IN_LLVM) {} +else version = MARS; + /************************************ * Check to see the aggregate type is nested and its context pointer is * accessible from the current scope. @@ -633,9 +637,7 @@ extern (C++) final class TupleDeclaration : Declaration version (none) { buf.printf("_%s_%d", ident.toChars(), i); - const len = buf.offset; - const name = buf.extractSlice().ptr; - auto id = Identifier.idPool(name, len); + auto id = Identifier.idPool(buf.extractSlice()); auto arg = new Parameter(STC.in_, t, id, null); } else diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 7a69382..197091e 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -534,22 +534,19 @@ enum class BUILTIN : unsigned char Expression *eval_builtin(const Loc &loc, FuncDeclaration *fd, Expressions *arguments); BUILTIN isBuiltin(FuncDeclaration *fd); +struct ContractInfo; + class FuncDeclaration : public Declaration { public: - Statements *frequires; // in contracts - Ensures *fensures; // out contracts - Statement *frequire; // lowered in contract - Statement *fensure; // lowered out contract Statement *fbody; FuncDeclarations foverrides; // functions this function overrides - FuncDeclaration *fdrequire; // function that does the in contract - FuncDeclaration *fdensure; // function that does the out contract - Expressions *fdrequireParams; // argument list for __require - Expressions *fdensureParams; // argument list for __ensure +private: + ContractInfo *contracts; // contract information +public: const char *mangleString; // mangled symbol created from mangleExact() VarDeclaration *vresult; // result variable for out contracts @@ -686,6 +683,22 @@ public: static FuncDeclaration *create(const Loc &loc, const Loc &endloc, Identifier *id, StorageClass storage_class, Type *type, bool noreturn = false); FuncDeclaration *syntaxCopy(Dsymbol *) override; + Statements *frequires(); + Ensures *fensures(); + Statement *frequire(); + Statement *fensure(); + FuncDeclaration *fdrequire(); + FuncDeclaration *fdensure(); + Expressions *fdrequireParams(); + Expressions *fdensureParams(); + Statements *frequires(Statements *frs); + Ensures *fensures(Statements *fes); + Statement *frequire(Statement *fr); + Statement *fensure(Statement *fe); + FuncDeclaration *fdrequire(FuncDeclaration *fdr); + FuncDeclaration *fdensure(FuncDeclaration *fde); + Expressions *fdrequireParams(Expressions *fdrp); + Expressions *fdensureParams(Expressions *fdep); bool functionSemantic(); bool functionSemantic3(); bool equals(const RootObject * const o) const override final; diff --git a/gcc/d/dmd/delegatize.d b/gcc/d/dmd/delegatize.d index fd95691..b135bfa 100644 --- a/gcc/d/dmd/delegatize.d +++ b/gcc/d/dmd/delegatize.d @@ -14,7 +14,6 @@ module dmd.delegatize; import core.stdc.stdio; -import dmd.apply; import dmd.astenums; import dmd.declaration; import dmd.dscope; @@ -27,6 +26,7 @@ import dmd.init; import dmd.initsem; import dmd.location; import dmd.mtype; +import dmd.postordervisitor; import dmd.statement; import dmd.tokens; import dmd.visitor; diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d index 221250b..87b40b8 100644 --- a/gcc/d/dmd/denum.d +++ b/gcc/d/dmd/denum.d @@ -169,7 +169,12 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol return defaultval; } //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars()); - if (defaultval) + // https://issues.dlang.org/show_bug.cgi?id=23904 + // Return defaultval only if it is not ErrorExp. + // A speculative context may set defaultval to ErrorExp; + // subsequent non-speculative contexts need to be able + // to print the error. + if (defaultval && !defaultval.isErrorExp()) return defaultval; if (isCsymbol()) diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d index b653d9b..c4d5ddb 100644 --- a/gcc/d/dmd/dimport.d +++ b/gcc/d/dmd/dimport.d @@ -26,6 +26,7 @@ import dmd.location; import dmd.mtype; import dmd.visitor; +import core.stdc.stdio; /*********************************************************** */ extern (C++) final class Import : Dsymbol @@ -232,7 +233,20 @@ extern (C++) final class Import : Dsymbol * most likely because of parsing errors. * Therefore we cannot trust the resulting AST. */ - if (load(sc)) return; + if (load(sc)) + { + // https://issues.dlang.org/show_bug.cgi?id=23873 + // For imports that are not at module or function level, + // e.g. aggregate level, the import symbol is added to the + // symbol table and later semantic is performed on it. + // This leads to semantic analysis on an malformed AST + // which causes all kinds of segfaults. + // The fix is to note that the module has errors and avoid + // semantic analysis on it. + if(mod) + mod.errors = true; + return; + } if (!mod) return; // Failed diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 4ef6a39..5b27a07 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -16,7 +16,6 @@ module dmd.dinterpret; import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.string; -import dmd.apply; import dmd.arraytypes; import dmd.astenums; import dmd.attrib; diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index 7674f77..3e60dc4 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -429,9 +429,9 @@ extern(C++) void gendocfile(Module m) if (m.filetype == FileType.ddoc) { const ploc = m.md ? &m.md.loc : &m.loc; - const loc = Loc(ploc.filename ? ploc.filename : srcfilename.ptr, - ploc.linnum, - ploc.charnum); + Loc loc = *ploc; + if (!loc.filename) + loc.filename = srcfilename.ptr; size_t commentlen = strlen(cast(char*)m.comment); Dsymbols a; @@ -4151,7 +4151,7 @@ private size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, con private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t offset) { const incrementLoc = loc.linnum == 0 ? 1 : 0; - loc.linnum += incrementLoc; + loc.linnum = loc.linnum + incrementLoc; loc.charnum = 0; //printf("highlightText()\n"); bool leadingBlank = true; @@ -4256,7 +4256,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s lineQuoted = false; tableRowDetected = false; iLineStart = i + 1; - loc.linnum += incrementLoc; + loc.linnum = loc.linnum + incrementLoc; // update the paragraph start if we just entered a macro if (previousMacroLevel < macroLevel && iParagraphStart < iLineStart) diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 506946f..a5cd63b 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -17,7 +17,6 @@ import core.stdc.string; import dmd.aggregate; import dmd.aliasthis; -import dmd.apply; import dmd.arraytypes; import dmd.astcodegen; import dmd.astenums; @@ -78,6 +77,10 @@ import dmd.templateparamsem; import dmd.typesem; import dmd.visitor; +version (IN_GCC) {} +else version (IN_LLVM) {} +else version = MARS; + enum LOG = false; private uint setMangleOverride(Dsymbol s, const(char)[] sym) @@ -484,7 +487,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Infering the type requires running semantic, // so mark the scope as ctfe if required - bool needctfe = (dsym.storage_class & (STC.manifest | STC.static_)) != 0; + bool needctfe = (dsym.storage_class & (STC.manifest | STC.static_)) != 0 || !sc.func; if (needctfe) { sc.flags |= SCOPE.condition; @@ -1366,9 +1369,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { static if (LOG) { - printf("Import::semantic('%s') %s\n", toPrettyChars(), id.toChars()); + printf("Import::semantic('%s') %s\n", imp.toPrettyChars(), imp.id.toChars()); scope(exit) - printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); + printf("-Import::semantic('%s'), pkg = %p\n", imp.toChars(), imp.pkg); } if (imp.semanticRun > PASS.initial) return; @@ -1434,7 +1437,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor imp.addPackageAccess(scopesym); } - imp.mod.dsymbolSemantic(null); + // if a module has errors it means that parsing has failed. + if (!imp.mod.errors) + imp.mod.dsymbolSemantic(null); if (imp.mod.needmoduleinfo) { @@ -1463,7 +1468,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else { Dsymbol s = imp.mod.search_correct(imp.names[i]); - if (s) + // https://issues.dlang.org/show_bug.cgi?id=23908 + // Don't suggest symbols from the importer's module + if (s && s.parent != importer) imp.mod.error(imp.loc, "import `%s` not found, did you mean %s `%s`?", imp.names[i].toChars(), s.kind(), s.toPrettyChars()); else imp.mod.error(imp.loc, "import `%s` not found", imp.names[i].toChars()); @@ -7124,8 +7131,9 @@ bool determineFields(AggregateDeclaration ad) // determineFields can be called recursively from one of the fields's v.semantic ad.fields.setDim(0); - static int func(Dsymbol s, AggregateDeclaration ad) + static int func(Dsymbol s, void* ctx) { + auto ad = cast(AggregateDeclaration)ctx; auto v = s.isVarDeclaration(); if (!v) return 0; @@ -7141,7 +7149,7 @@ bool determineFields(AggregateDeclaration ad) if (v.aliasTuple) { // If this variable was really a tuple, process each element. - return v.aliasTuple.foreachVar(tv => tv.apply(&func, ad)); + return v.aliasTuple.foreachVar(tv => tv.apply(&func, cast(void*) ad)); } if (v.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.ctfe | STC.templateparameter)) @@ -7173,7 +7181,7 @@ bool determineFields(AggregateDeclaration ad) for (size_t i = 0; i < ad.members.length; i++) { auto s = (*ad.members)[i]; - if (s.apply(&func, ad)) + if (s.apply(&func, cast(void *)ad)) { if (ad.sizeok != Sizeok.none) { diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index ef743d6..5b98d2f 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -4141,185 +4141,207 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param goto Lnomatch; L2: - for (size_t i = 0; 1; i++) + if (!resolveTemplateInstantiation(t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, dedtypes)) + goto Lnomatch; + } + visit(cast(Type)t); + return; + + Lnomatch: + //printf("no match\n"); + result = MATCH.nomatch; + } + + /******************** + * Match template `parameters` to the target template instance. + * Example: + * struct Temp(U, int Z) {} + * void foo(T)(Temp!(T, 3)); + * foo(Temp!(int, 3)()); + * Input: + * this.parameters = template params of foo -> [T] + * tiargs = <Temp!(int, 3)>.tiargs -> [int, 3] + * tdtypes = <Temp!(int, 3)>.tdtypes -> [int, 3] + * tempdecl = <struct Temp!(T, int Z)> -> [T, Z] + * tp = <Temp!(T, 3)> + * Output: + * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int] + */ + private bool resolveTemplateInstantiation(Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes) + { + for (size_t i = 0; 1; i++) + { + //printf("\ttest: tempinst.tiargs[%zu]\n", i); + RootObject o1 = null; + if (i < tiargs.length) + o1 = (*tiargs)[i]; + else if (i < tdtypes.length && i < tp.tempinst.tiargs.length) { - //printf("\ttest: tempinst.tiargs[%zu]\n", i); - RootObject o1 = null; - if (i < t.tempinst.tiargs.length) - o1 = (*t.tempinst.tiargs)[i]; - else if (i < t.tempinst.tdtypes.length && i < tp.tempinst.tiargs.length) - { - // Pick up default arg - o1 = t.tempinst.tdtypes[i]; - } - else if (i >= tp.tempinst.tiargs.length) - break; - //printf("\ttest: o1 = %s\n", o1.toChars()); - if (i >= tp.tempinst.tiargs.length) + // Pick up default arg + o1 = (*tdtypes)[i]; + } + else if (i >= tp.tempinst.tiargs.length) + break; + //printf("\ttest: o1 = %s\n", o1.toChars()); + if (i >= tp.tempinst.tiargs.length) + { + size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0); + while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) { - size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0); - while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) - { - i++; - } - if (i >= dim) - break; // match if all remained parameters are dependent - goto Lnomatch; + i++; } + if (i >= dim) + break; // match if all remained parameters are dependent + return false; + } - RootObject o2 = (*tp.tempinst.tiargs)[i]; - Type t2 = isType(o2); - //printf("\ttest: o2 = %s\n", o2.toChars()); - size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1) - ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; - if (j != IDX_NOTFOUND && j == parameters.length - 1 && - (*parameters)[j].isTemplateTupleParameter()) - { - /* Given: + RootObject o2 = (*tp.tempinst.tiargs)[i]; + Type t2 = isType(o2); + //printf("\ttest: o2 = %s\n", o2.toChars()); + size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1) + ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; + if (j != IDX_NOTFOUND && j == parameters.length - 1 && + (*parameters)[j].isTemplateTupleParameter()) + { + /* Given: * struct A(B...) {} * alias A!(int, float) X; * static if (is(X Y == A!(Z), Z...)) {} * deduce that Z is a tuple(int, float) */ - /* Create tuple from remaining args + /* Create tuple from remaining args */ - size_t vtdim = (tempdecl.isVariadic() ? t.tempinst.tiargs.length : t.tempinst.tdtypes.length) - i; - auto vt = new Tuple(vtdim); - for (size_t k = 0; k < vtdim; k++) - { - RootObject o; - if (k < t.tempinst.tiargs.length) - o = (*t.tempinst.tiargs)[i + k]; - else // Pick up default arg - o = t.tempinst.tdtypes[i + k]; - vt.objects[k] = o; - } - - Tuple v = cast(Tuple)(*dedtypes)[j]; - if (v) - { - if (!match(v, vt)) - goto Lnomatch; - } - else - (*dedtypes)[j] = vt; - break; - } - else if (!o1) - break; - - Type t1 = isType(o1); - Dsymbol s1 = isDsymbol(o1); - Dsymbol s2 = isDsymbol(o2); - Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); - Expression e2 = isExpression(o2); - version (none) + size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i; + auto vt = new Tuple(vtdim); + for (size_t k = 0; k < vtdim; k++) { - Tuple v1 = isTuple(o1); - Tuple v2 = isTuple(o2); - if (t1) - printf("t1 = %s\n", t1.toChars()); - if (t2) - printf("t2 = %s\n", t2.toChars()); - if (e1) - printf("e1 = %s\n", e1.toChars()); - if (e2) - printf("e2 = %s\n", e2.toChars()); - if (s1) - printf("s1 = %s\n", s1.toChars()); - if (s2) - printf("s2 = %s\n", s2.toChars()); - if (v1) - printf("v1 = %s\n", v1.toChars()); - if (v2) - printf("v2 = %s\n", v2.toChars()); + RootObject o; + if (k < tiargs.length) + o = (*tiargs)[i + k]; + else // Pick up default arg + o = (*tdtypes)[i + k]; + vt.objects[k] = o; } - if (t1 && t2) + Tuple v = cast(Tuple)(*dedtypes)[j]; + if (v) { - if (!deduceType(t1, sc, t2, parameters, dedtypes)) - goto Lnomatch; + if (!match(v, vt)) + return false; } - else if (e1 && e2) - { - Le: - e1 = e1.ctfeInterpret(); + else + (*dedtypes)[j] = vt; + break; + } + else if (!o1) + break; - /* If it is one of the template parameters for this template, + Type t1 = isType(o1); + Dsymbol s1 = isDsymbol(o1); + Dsymbol s2 = isDsymbol(o2); + Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); + Expression e2 = isExpression(o2); + version (none) + { + Tuple v1 = isTuple(o1); + Tuple v2 = isTuple(o2); + if (t1) + printf("t1 = %s\n", t1.toChars()); + if (t2) + printf("t2 = %s\n", t2.toChars()); + if (e1) + printf("e1 = %s\n", e1.toChars()); + if (e2) + printf("e2 = %s\n", e2.toChars()); + if (s1) + printf("s1 = %s\n", s1.toChars()); + if (s2) + printf("s2 = %s\n", s2.toChars()); + if (v1) + printf("v1 = %s\n", v1.toChars()); + if (v2) + printf("v2 = %s\n", v2.toChars()); + } + + if (t1 && t2) + { + if (!deduceType(t1, sc, t2, parameters, dedtypes)) + return false; + } + else if (e1 && e2) + { + Le: + e1 = e1.ctfeInterpret(); + + /* If it is one of the template parameters for this template, * we should not attempt to interpret it. It already has a value. */ - if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter)) - { - /* + if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter)) + { + /* * (T:Number!(e2), int e2) */ - j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters); - if (j != IDX_NOTFOUND) - goto L1; - // The template parameter was not from this template - // (it may be from a parent template, for example) - } - - e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 - e2 = e2.ctfeInterpret(); + j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters); + if (j != IDX_NOTFOUND) + goto L1; + // The template parameter was not from this template + // (it may be from a parent template, for example) + } - //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); - //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); - if (!e1.equals(e2)) - { - if (!e2.implicitConvTo(e1.type)) - goto Lnomatch; + e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 + e2 = e2.ctfeInterpret(); - e2 = e2.implicitCastTo(sc, e1.type); - e2 = e2.ctfeInterpret(); - if (!e1.equals(e2)) - goto Lnomatch; - } - } - else if (e1 && t2 && t2.ty == Tident) + //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); + //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); + if (!e1.equals(e2)) { - j = templateParameterLookup(t2, parameters); - L1: - if (j == IDX_NOTFOUND) - { - t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); - if (e2) - goto Le; - goto Lnomatch; - } - if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null)) - goto Lnomatch; + if (!e2.implicitConvTo(e1.type)) + return false; + + e2 = e2.implicitCastTo(sc, e1.type); + e2 = e2.ctfeInterpret(); + if (!e1.equals(e2)) + return false; } - else if (s1 && s2) + } + else if (e1 && t2 && t2.ty == Tident) + { + j = templateParameterLookup(t2, parameters); + L1: + if (j == IDX_NOTFOUND) { - Ls: - if (!s1.equals(s2)) - goto Lnomatch; + t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); + if (e2) + goto Le; + return false; } - else if (s1 && t2 && t2.ty == Tident) + if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null)) + return false; + } + else if (s1 && s2) + { + Ls: + if (!s1.equals(s2)) + return false; + } + else if (s1 && t2 && t2.ty == Tident) + { + j = templateParameterLookup(t2, parameters); + if (j == IDX_NOTFOUND) { - j = templateParameterLookup(t2, parameters); - if (j == IDX_NOTFOUND) - { - t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); - if (s2) - goto Ls; - goto Lnomatch; - } - if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null)) - goto Lnomatch; + t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); + if (s2) + goto Ls; + return false; } - else - goto Lnomatch; + if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null)) + return false; } + else + return false; } - visit(cast(Type)t); - return; - - Lnomatch: - //printf("no match\n"); - result = MATCH.nomatch; + return true; } override void visit(TypeStruct t) diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 4f1edaa..c0dd17f 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -377,13 +377,18 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId, desc ~ " `%s` assigned to non-scope parameter calling `assert()`", v); return; } + + bool isThis = fdc && fdc.needThis() && fdc.vthis == vPar; // implicit `this` parameter to member function + const(char)* msg = + (isThis) ? (desc ~ " `%s` calling non-scope member function `%s.%s()`") : (fdc && parId) ? (desc ~ " `%s` assigned to non-scope parameter `%s` calling `%s`") : (fdc && !parId) ? (desc ~ " `%s` assigned to non-scope anonymous parameter calling `%s`") : (!fdc && parId) ? (desc ~ " `%s` assigned to non-scope parameter `%s`") : (desc ~ " `%s` assigned to non-scope anonymous parameter"); - if (sc.setUnsafeDIP1000(gag, arg.loc, msg, v, parId ? parId : fdc, fdc)) + auto param = isThis ? v : (parId ? parId : fdc); + if (sc.setUnsafeDIP1000(gag, arg.loc, msg, v, param, fdc)) { result = true; printScopeFailure(previewSupplementalFunc(sc.isDeprecated(), global.params.useDIP1000), vPar, 10); @@ -1746,20 +1751,8 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re /* Check each argument that is * passed as 'return scope'. */ - Type t1 = e.e1.type.toBasetype(); - TypeFunction tf; - TypeDelegate dg; - if (t1.ty == Tdelegate) - { - dg = t1.isTypeDelegate(); - tf = dg.next.isTypeFunction(); - } - else if (t1.ty == Tfunction) - tf = t1.isTypeFunction(); - else - return; - - if (!e.type.hasPointers()) + TypeFunction tf = e.calledFunctionType(); + if (!tf || !e.type.hasPointers()) return; if (e.arguments && e.arguments.length) @@ -1815,6 +1808,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re } } // If 'this' is returned, check it too + Type t1 = e.e1.type.toBasetype(); if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction) { DotVarExp dve = e.e1.isDotVarExp(); @@ -1880,7 +1874,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re /* If returning the result of a delegate call, the .ptr * field of the delegate must be checked. */ - if (dg) + if (t1.isTypeDelegate()) { if (tf.isreturn) escapeByValue(e.e1, er, live, retRefTransition); @@ -2066,13 +2060,8 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR /* If the function returns by ref, check each argument that is * passed as 'return ref'. */ - Type t1 = e.e1.type.toBasetype(); - TypeFunction tf; - if (t1.ty == Tdelegate) - tf = t1.isTypeDelegate().next.isTypeFunction(); - else if (t1.ty == Tfunction) - tf = t1.isTypeFunction(); - else + TypeFunction tf = e.calledFunctionType(); + if (!tf) return; if (tf.isref) { @@ -2107,6 +2096,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR } } // If 'this' is returned by ref, check it too + Type t1 = e.e1.type.toBasetype(); if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction) { DotVarExp dve = e.e1.isDotVarExp(); diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 067d22f..473efb8 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -19,7 +19,6 @@ import core.stdc.string; import dmd.aggregate; import dmd.aliasthis; -import dmd.apply; import dmd.arrayop; import dmd.arraytypes; import dmd.astenums; @@ -56,6 +55,7 @@ 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; @@ -699,6 +699,20 @@ VarDeclaration expToVariable(Expression e) case EXP.super_: return (cast(ThisExp)e).var.isVarDeclaration(); + // Temporaries for rvalues that need destruction + // are of form: (T s = rvalue, s). For these cases + // we can just return var declaration of `s`. However, + // this is intentionally not calling `Expression.extractLast` + // because at this point we cannot infer the var declaration + // of more complex generated comma expressions such as the + // one for the array append hook. + case EXP.comma: + { + if (auto ve = e.isCommaExp().e2.isVarExp()) + return ve.var.isVarDeclaration(); + + return null; + } default: return null; } @@ -723,7 +737,6 @@ extern (C++) abstract class Expression : ASTNode Type type; // !=null means that semantic() has been run Loc loc; // file location const EXP op; // to minimize use of dynamic_cast - bool parens; // if this is a parenthesized expression extern (D) this(const ref Loc loc, EXP op) scope { @@ -1530,6 +1543,11 @@ extern (C++) abstract class Expression : ASTNode return false; if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) return false; + /* The original expression (`new S(...)`) will be verified instead. This + * is to keep errors related to the original code and not the lowering. + */ + if (f.ident == Id._d_newitemT) + return false; if (!f.isNogc()) { @@ -2338,6 +2356,7 @@ extern (C++) final class ComplexExp : Expression extern (C++) class IdentifierExp : Expression { Identifier ident; + bool parens; // if it appears as (identifier) extern (D) this(const ref Loc loc, Identifier ident) scope { @@ -3520,6 +3539,8 @@ extern (C++) final class CompoundLiteralExp : Expression */ extern (C++) final class TypeExp : Expression { + bool parens; // if this is a parenthesized expression + extern (D) this(const ref Loc loc, Type type) { super(loc, EXP.type); @@ -3672,7 +3693,7 @@ extern (C++) final class NewExp : Expression bool onstack; // allocate on stack bool thrownew; // this NewExp is the expression of a ThrowStatement - Expression lowering; // lowered druntime hook: `_d_newclass` + Expression lowering; // lowered druntime hook: `_d_new{class,itemT}` /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around. /// The fields are still separate for backwards compatibility @@ -5188,6 +5209,7 @@ extern (C++) final class CallExp : UnaExp bool directcall; // true if a virtual call is devirtualized bool inDebugStatement; /// true if this was in a debug statement bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code) + bool isUfcsRewrite; /// the first argument was pushed in here by a UFCS rewrite VarDeclaration vthis2; // container for multi-context /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around. @@ -5329,6 +5351,26 @@ extern (C++) final class CallExp : UnaExp } } +/** + * Get the called function type from a call expression + * Params: + * ce = function call expression. Must have had semantic analysis done. + * Returns: called function type, or `null` if error / no semantic analysis done + */ +TypeFunction calledFunctionType(CallExp ce) +{ + Type t = ce.e1.type; + if (!t) + return null; + t = t.toBasetype(); + if (auto tf = t.isTypeFunction()) + return tf; + else if (auto td = t.isTypeDelegate()) + return td.nextOf().isTypeFunction(); + else + return null; +} + FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null) { if (auto ae = e.isAddrExp()) @@ -7058,9 +7100,7 @@ extern (C++) final class FileInitExp : DefaultInitExp s = loc.isValid() ? loc.filename : sc._module.ident.toChars(); Expression e = new StringExp(loc, s.toDString()); - e = e.expressionSemantic(sc); - e = e.castTo(sc, type); - return e; + return e.expressionSemantic(sc); } override void accept(Visitor v) @@ -7082,8 +7122,7 @@ extern (C++) final class LineInitExp : DefaultInitExp override Expression resolveLoc(const ref Loc loc, Scope* sc) { Expression e = new IntegerExp(loc, loc.linnum, Type.tint32); - e = e.castTo(sc, type); - return e; + return e.expressionSemantic(sc); } override void accept(Visitor v) @@ -7106,9 +7145,7 @@ extern (C++) final class ModuleInitExp : DefaultInitExp { const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString(); Expression e = new StringExp(loc, s); - e = e.expressionSemantic(sc); - e = e.castTo(sc, type); - return e; + return e.expressionSemantic(sc); } override void accept(Visitor v) @@ -7137,9 +7174,7 @@ extern (C++) final class FuncInitExp : DefaultInitExp else s = ""; Expression e = new StringExp(loc, s.toDString()); - e = e.expressionSemantic(sc); - e.type = Type.tstring; - return e; + return e.expressionSemantic(sc); } override void accept(Visitor v) diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index a4b18b9..770c3e7 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -83,7 +83,6 @@ public: Type *type; // !=NULL means that semantic() has been run Loc loc; // file location EXP op; // to minimize use of dynamic_cast - d_bool parens; // if this is a parenthesized expression size_t size() const; static void _init(); @@ -316,6 +315,7 @@ class IdentifierExp : public Expression { public: Identifier *ident; + d_bool parens; static IdentifierExp *create(const Loc &loc, Identifier *ident); bool isLvalue() override final; @@ -839,6 +839,7 @@ public: d_bool directcall; // true if a virtual call is devirtualized d_bool inDebugStatement; // true if this was in a debug statement d_bool ignoreAttributes; // don't enforce attributes (e.g. call @gc function in @nogc code) + d_bool isUfcsRewrite; // the first argument was pushed in here by a UFCS rewrite VarDeclaration *vthis2; // container for multi-context static CallExp *create(const Loc &loc, Expression *e, Expressions *exps); diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index cf4aac4..8ac8866 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -653,7 +653,7 @@ private Expression resolveUFCS(Scope* sc, CallExp ce) if (!ce.names) ce.names = new Identifiers(); ce.names.shift(null); - + ce.isUfcsRewrite = true; return null; } @@ -1254,12 +1254,12 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = return ErrorExp.get(); e2 = resolveProperties(sc, e2); - Expressions a; + Expressions* a = new Expressions(); a.push(e2); for (size_t i = 0; i < os.a.length; i++) { - if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet)) + if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet)) { if (f.errors) return ErrorExp.get(); @@ -1378,10 +1378,10 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = return ErrorExp.get(); e2 = resolveProperties(sc, e2); - Expressions a; + Expressions* a = new Expressions(); a.push(e2); - FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet); + FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet); if (fd && fd.type) { if (fd.errors) @@ -3574,6 +3574,51 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = exp; } + /** + * Sets the `lowering` field of a `NewExp` to a call to `_d_newitemT` unless + * compiling with `-betterC` or within `__traits(compiles)`. + * + * Params: + * ne = the `NewExp` to lower + */ + private void tryLowerToNewItem(NewExp ne) + { + if (global.params.betterC || !sc.needsCodegen()) + return; + + auto hook = global.params.tracegc ? Id._d_newitemTTrace : Id._d_newitemT; + if (!verifyHookExist(ne.loc, *sc, hook, "new struct")) + return; + + /* Lower the memory allocation and initialization of `new T()` to + * `_d_newitemT!T()`. + */ + Expression id = new IdentifierExp(ne.loc, Id.empty); + id = new DotIdExp(ne.loc, id, Id.object); + auto tiargs = new Objects(); + /* + * Remove `inout`, `const`, `immutable` and `shared` to reduce the + * number of generated `_d_newitemT` instances. + */ + auto t = ne.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ | + MODFlags.immutable_ | MODFlags.shared_); + tiargs.push(t); + id = new DotTemplateInstanceExp(ne.loc, id, hook, tiargs); + + auto arguments = new Expressions(); + if (global.params.tracegc) + { + auto funcname = (sc.callsc && sc.callsc.func) ? + sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); + arguments.push(new StringExp(ne.loc, ne.loc.filename.toDString())); + arguments.push(new IntegerExp(ne.loc, ne.loc.linnum, Type.tint32)); + arguments.push(new StringExp(ne.loc, funcname.toDString())); + } + id = new CallExp(ne.loc, id, arguments); + + ne.lowering = id.expressionSemantic(sc); + } + override void visit(NewExp exp) { static if (LOGSEMANTIC) @@ -4007,6 +4052,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } exp.type = exp.type.pointerTo(); + tryLowerToNewItem(exp); } else if (tb.ty == Tarray) { @@ -4078,6 +4124,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } exp.type = exp.type.pointerTo(); + tryLowerToNewItem(exp); } else if (tb.ty == Taarray) { @@ -5192,7 +5239,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { s = (cast(TemplateExp)exp.e1).td; L2: - exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList, FuncResolveFlag.standard); + exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList, + exp.isUfcsRewrite ? FuncResolveFlag.ufcs : FuncResolveFlag.standard); if (!exp.f || exp.f.errors) return setError(); if (exp.f.needThis()) @@ -5301,6 +5349,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor buf.writeByte(')'); //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); + if (exp.isUfcsRewrite) + { + const arg = (*exp.argumentList.arguments)[0]; + .error(exp.loc, "no property `%s` for `%s` of type `%s`", exp.f.ident.toChars(), arg.toChars(), arg.type.toChars()); + .errorSupplemental(exp.loc, "the following error occured while looking for a UFCS match"); + } + .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); if (failMessage) @@ -6733,7 +6788,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.ident != Id.__sizeof) { - result = fieldLookup(exp.e1, sc, exp.ident); + result = fieldLookup(exp.e1, sc, exp.ident, exp.arrow); return; } } @@ -9068,7 +9123,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp()) { auto die = e1x.isDotIdExp(); - e1x = fieldLookup(die.e1, sc, die.ident); + e1x = fieldLookup(die.e1, sc, die.ident, die.arrow); } else if (auto die = e1x.isDotIdExp()) { @@ -11023,7 +11078,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be * used with `-betterC`, but only during CTFE. */ - if (global.params.betterC) + if (global.params.betterC || !sc.needsCodegen()) return; if (auto ce = exp.isCatExp()) @@ -13175,10 +13230,20 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag) Expression se = new ScopeExp(exp.loc, imp.pkg); return se.expressionSemantic(sc); } + + if (auto attr = s.isAttribDeclaration()) + { + if (auto sm = ie.sds.search(exp.loc, exp.ident, flags)) + { + auto es = new DsymbolExp(exp.loc, sm); + return es; + } + } + // BUG: handle other cases like in IdentifierExp::semantic() debug { - printf("s = '%s', kind = '%s'\n", s.toChars(), s.kind()); + printf("s = %p '%s', kind = '%s'\n", s, s.toChars(), s.kind()); } assert(0); } diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/foreachvar.d index 7a96469..1293057 100644 --- a/gcc/d/dmd/foreachvar.d +++ b/gcc/d/dmd/foreachvar.d @@ -15,7 +15,6 @@ import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.string; -import dmd.apply; import dmd.arraytypes; import dmd.astenums; import dmd.attrib; @@ -33,6 +32,7 @@ import dmd.identifier; import dmd.init; import dmd.initsem; import dmd.mtype; +import dmd.postordervisitor; import dmd.printast; import dmd.root.array; import dmd.root.rootobject; diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 8e11ab1..a714d2d 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -59,6 +59,10 @@ import dmd.statementsem; import dmd.tokens; import dmd.visitor; +version (IN_GCC) {} +else version (IN_LLVM) {} +else version = MARS; + /// Inline Status enum ILS : ubyte { @@ -259,21 +263,30 @@ extern (C++) struct Ensure } /*********************************************************** + * Most functions don't have contracts, so save memory by grouping + * this information into a separate struct */ -extern (C++) class FuncDeclaration : Declaration +private struct ContractInfo { Statements* frequires; /// in contracts Ensures* fensures; /// out contracts Statement frequire; /// lowered in contract Statement fensure; /// lowered out contract - Statement fbody; /// function body - - FuncDeclarations foverrides; /// functions this function overrides FuncDeclaration fdrequire; /// function that does the in contract FuncDeclaration fdensure; /// function that does the out contract - Expressions* fdrequireParams; /// argument list for __require Expressions* fdensureParams; /// argument list for __ensure +} + +/*********************************************************** + */ +extern (C++) class FuncDeclaration : Declaration +{ + Statement fbody; /// function body + + FuncDeclarations foverrides; /// functions this function overrides + + private ContractInfo* contracts; /// contract information const(char)* mangleString; /// mangled symbol created from mangleExact() @@ -403,6 +416,44 @@ extern (C++) class FuncDeclaration : Declaration return new FuncDeclaration(loc, endloc, id, storage_class, type, noreturn); } + final nothrow pure @safe + { + private ref ContractInfo getContracts() + { + if (!contracts) + contracts = new ContractInfo(); + return *contracts; + } + + // getters + inout(Statements*) frequires() inout { return contracts ? contracts.frequires : null; } + inout(Ensures*) fensures() inout { return contracts ? contracts.fensures : null; } + inout(Statement) frequire() inout { return contracts ? contracts.frequire: null; } + inout(Statement) fensure() inout { return contracts ? contracts.fensure : null; } + inout(FuncDeclaration) fdrequire() inout { return contracts ? contracts.fdrequire : null; } + inout(FuncDeclaration) fdensure() inout { return contracts ? contracts.fdensure: null; } + inout(Expressions*) fdrequireParams() inout { return contracts ? contracts.fdrequireParams: null; } + inout(Expressions*) fdensureParams() inout { return contracts ? contracts.fdensureParams: null; } + + extern (D) private static string generateContractSetter(string field, string type) + { + return type ~ " " ~ field ~ "(" ~ type ~ " param)" ~ + "{ + if (!param && !contracts) return null; + return getContracts()." ~ field ~ " = param; + }"; + } + + mixin(generateContractSetter("frequires", "Statements*")); + mixin(generateContractSetter("fensures", "Ensures*")); + mixin(generateContractSetter("frequire", "Statement")); + mixin(generateContractSetter("fensure", "Statement")); + mixin(generateContractSetter("fdrequire", "FuncDeclaration")); + mixin(generateContractSetter("fdensure", "FuncDeclaration")); + mixin(generateContractSetter("fdrequireParams", "Expressions*")); + mixin(generateContractSetter("fdensureParams", "Expressions*")); + } + override FuncDeclaration syntaxCopy(Dsymbol s) { //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); @@ -2717,7 +2768,7 @@ extern (C++) class FuncDeclaration : Declaration */ static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0) { - return genCfunc(fparams, treturn, Identifier.idPool(name, cast(uint)strlen(name)), stc); + return genCfunc(fparams, treturn, Identifier.idPool(name[0 .. strlen(name)]), stc); } static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0) @@ -3199,6 +3250,7 @@ enum FuncResolveFlag : ubyte quiet = 1, /// do not issue error message on no match, just return `null`. overloadOnly = 2, /// only resolve overloads, i.e. do not issue error on ambiguous /// matches and need explicit this. + ufcs = 4, /// trying to resolve UFCS call } /******************************************* @@ -3316,12 +3368,22 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, } // no match, generate an error messages + if (flags & FuncResolveFlag.ufcs) + { + auto arg = (*fargs)[0]; + .error(loc, "no property `%s` for `%s` of type `%s`", s.ident.toChars(), arg.toChars(), arg.type.toChars()); + .errorSupplemental(loc, "the following error occured while looking for a UFCS match"); + } + if (!fd) { // all of overloads are templates if (td) { - .error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`", + const(char)* msg = "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`"; + if (!od && !td.overnext) + msg = "%s `%s.%s` is not callable using argument types `!(%s)%s`"; + .error(loc, msg, td.kind(), td.parent.toPrettyChars(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 45b4528..0ac6042 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -26,6 +26,10 @@ import dmd.location; import dmd.lexer : CompileEnv; import dmd.utils; +version (IN_GCC) {} +else version (IN_LLVM) {} +else version = MARS; + /// Defines a setting for how compiler warnings and deprecations are handled enum DiagnosticReporting : ubyte { diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 902cf83..66345ac 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -353,10 +353,11 @@ typedef unsigned long long uinteger_t; // file location struct Loc { - const char *filename; // either absolute or relative to cwd - unsigned linnum; - unsigned charnum; - +private: + unsigned _linnum; + unsigned short _charnum; + unsigned short fileIndex; +public: static void set(bool showColumns, MessageStyle messageStyle); static bool showColumns; @@ -364,18 +365,25 @@ struct Loc Loc() { - linnum = 0; - charnum = 0; - filename = NULL; + _linnum = 0; + _charnum = 0; + fileIndex = 0; } Loc(const char *filename, unsigned linnum, unsigned charnum) { - this->linnum = linnum; - this->charnum = charnum; - this->filename = filename; + this->linnum(linnum); + this->charnum(charnum); + this->filename(filename); } + uint32_t charnum() const; + uint32_t charnum(uint32_t num); + uint32_t linnum() const; + uint32_t linnum(uint32_t num); + const char *filename() const; + void filename(const char *name); + const char *toChars( bool showColumns = Loc::showColumns, MessageStyle messageStyle = Loc::messageStyle) const; diff --git a/gcc/d/dmd/gluelayer.d b/gcc/d/dmd/gluelayer.d index 7b52eff..1793700 100644 --- a/gcc/d/dmd/gluelayer.d +++ b/gcc/d/dmd/gluelayer.d @@ -48,25 +48,6 @@ version (NoBackend) } } } -else version (MARS) -{ - public import dmd.backend.cc : block, Blockx, Symbol; - public import dmd.backend.type : type; - public import dmd.backend.el : elem; - public import dmd.backend.code_x86 : code; - - extern (C++) - { - Statement asmSemantic(AsmStatement s, Scope* sc); - - void toObjFile(Dsymbol ds, bool multiobj); - - extern(C++) abstract class ObjcGlue - { - static void initialize(); - } - } -} else version (IN_GCC) { extern (C++) union tree_node; @@ -88,4 +69,12 @@ else version (IN_GCC) } } else - static assert(false, "Unsupported compiler backend"); +{ + public import dmd.backend.cc : block, Blockx, Symbol; + public import dmd.backend.type : type; + public import dmd.backend.el : elem; + public import dmd.backend.code_x86 : code; + public import dmd.iasm : asmSemantic; + public import dmd.objc_glue : ObjcGlue; + public import dmd.toobj : toObjFile; +} diff --git a/gcc/d/dmd/iasm.d b/gcc/d/dmd/iasm.d index 66829da..1fdfe40 100644 --- a/gcc/d/dmd/iasm.d +++ b/gcc/d/dmd/iasm.d @@ -23,13 +23,14 @@ import dmd.tokens; import dmd.statement; import dmd.statementsem; -version (MARS) +version (IN_GCC) { - import dmd.iasmdmd; + import dmd.iasmgcc; } -else version (IN_GCC) +else { - import dmd.iasmgcc; + import dmd.iasmdmd; + version = MARS; } /************************ AsmStatement ***************************************/ diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index a2271d5..a2daf60 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -315,6 +315,8 @@ immutable Msgtable[] msgtable = { "_d_newThrowable" }, { "_d_newclassT" }, { "_d_newclassTTrace" }, + { "_d_newitemT" }, + { "_d_newitemTTrace" }, { "_d_assert_fail" }, { "dup" }, { "_aaApply" }, @@ -549,6 +551,7 @@ immutable Msgtable[] msgtable = { "_pure", "pure" }, { "define" }, { "undef" }, + { "ident" }, ]; diff --git a/gcc/d/dmd/identifier.d b/gcc/d/dmd/identifier.d index 2233d77..b1c421c 100644 --- a/gcc/d/dmd/identifier.d +++ b/gcc/d/dmd/identifier.d @@ -274,12 +274,7 @@ nothrow: return idPool(s[0 .. len]); } - extern (D) static Identifier idPool(const(char)[] s) - { - return idPool(s, false); - } - - extern (D) private static Identifier idPool(const(char)[] s, bool isAnonymous) + extern (D) static Identifier idPool(const(char)[] s, bool isAnonymous = false) { auto sv = stringtable.update(s); auto id = sv.value; @@ -291,18 +286,18 @@ nothrow: return id; } - extern (D) static Identifier idPool(const(char)* s, size_t len, int value) - { - return idPool(s[0 .. len], value); - } - - extern (D) static Identifier idPool(const(char)[] s, int value) + /****************************************** + * Used for inserting keywords into the string table. + * Params: + * s = string for keyword + * value = TOK.xxxx for the keyword + */ + extern (D) static void idPool(const(char)[] s, TOK value) { auto sv = stringtable.insert(s, null); assert(sv); auto id = new Identifier(sv.toString(), value); sv.value = id; - return id; } /********************************** diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index 97710b8..fe0aa17 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -108,11 +108,12 @@ Expression arrayFuncConv(Expression e, Scope* sc) * e = evaluates to an instance of a struct * sc = context * id = identifier of a field in that struct + * arrow = -> was used * Returns: * if successful `e.ident` * if not then `ErrorExp` and message is printed */ -Expression fieldLookup(Expression e, Scope* sc, Identifier id) +Expression fieldLookup(Expression e, Scope* sc, Identifier id, bool arrow) { e = e.expressionSemantic(sc); if (e.isErrorExp()) @@ -123,6 +124,9 @@ Expression fieldLookup(Expression e, Scope* sc, Identifier id) if (t.isTypePointer()) { t = t.isTypePointer().next; + auto pe = e.toChars(); + if (!arrow) + e.error("since `%s` is a pointer, use `%s->%s` instead of `%s.%s`", pe, pe, id.toChars(), pe, id.toChars()); e = new PtrExp(e.loc, e); } if (auto ts = t.isTypeStruct()) @@ -237,15 +241,16 @@ Expression castCallAmbiguity(Expression e, Scope* sc) case EXP.call: auto ce = (*pe).isCallExp(); - if (ce.e1.parens) + auto ie = ce.e1.isIdentifierExp(); + if (ie && ie.parens) { - ce.e1 = expressionSemantic(ce.e1, sc); + ce.e1 = expressionSemantic(ie, sc); if (ce.e1.op == EXP.type) { const numArgs = ce.arguments ? ce.arguments.length : 0; if (numArgs >= 1) { - ce.e1.parens = false; + ie.parens = false; Expression arg; foreach (a; (*ce.arguments)[]) { diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 893d2a6..ca770bd 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -587,6 +587,9 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ */ t = t.toBasetype(); + if (auto tv = t.isTypeVector()) + t = tv.basetype; + /* If `{ expression }` return the expression initializer */ ExpInitializer isBraceExpression() diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index 0ec468b..a878cc9 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -119,7 +119,7 @@ class Lexer this(const(char)* filename, const(char)* base, size_t begoffset, size_t endoffset, bool doDocComment, bool commentToken, ErrorSink errorSink, - const CompileEnv* compileEnv) pure scope + const CompileEnv* compileEnv) scope { scanloc = Loc(filename, 1, 1); // debug printf("Lexer::Lexer(%p)\n", base); @@ -573,7 +573,7 @@ class Lexer } break; } - Identifier id = Identifier.idPool(cast(char*)t.ptr, cast(uint)(p - t.ptr)); + Identifier id = Identifier.idPool((cast(char*)t.ptr)[0 .. p - t.ptr], false); t.ident = id; t.value = cast(TOK)id.getValue(); @@ -2672,9 +2672,9 @@ class Lexer return result; } - final Loc loc() pure @nogc + final Loc loc() @nogc { - scanloc.charnum = cast(uint)(1 + p - line); + scanloc.charnum = cast(ushort)(1 + p - line); version (LocOffset) scanloc.fileOffset = cast(uint)(p - base); return scanloc; @@ -3098,9 +3098,9 @@ class Lexer /************************** * `p` should be at start of next line */ - private void endOfLine() pure @nogc @safe + private void endOfLine() @nogc @safe { - scanloc.linnum++; + scanloc.linnum = scanloc.linnum + 1; line = p; } } diff --git a/gcc/d/dmd/location.d b/gcc/d/dmd/location.d index 020d297..b2b3661 100644 --- a/gcc/d/dmd/location.d +++ b/gcc/d/dmd/location.d @@ -11,7 +11,10 @@ module dmd.location; +import core.stdc.stdio; + import dmd.common.outbuffer; +import dmd.root.array; import dmd.root.filename; version (DMDLIB) @@ -34,10 +37,9 @@ debug info etc. */ struct Loc { - /// zero-terminated filename string, either absolute or relative to cwd - const(char)* filename; - uint linnum; /// line number, starting from 1 - uint charnum; /// utf8 code unit index relative to start of line, starting from 1 + private uint _linnum; + private ushort _charnum; + private ushort fileIndex; // index into filenames[], starting from 1 (0 means no filename) version (LocOffset) uint fileOffset; /// utf8 code unit index relative to start of file, starting from 0 @@ -46,6 +48,8 @@ struct Loc extern (C++) __gshared bool showColumns; extern (C++) __gshared MessageStyle messageStyle; + __gshared Array!(const(char)*) filenames; + nothrow: /******************************* @@ -60,19 +64,69 @@ nothrow: this.messageStyle = messageStyle; } - extern (D) this(const(char)* filename, uint linnum, uint charnum) pure + extern (D) this(const(char)* filename, uint linnum, uint charnum) { - this.linnum = linnum; - this.charnum = charnum; + this._linnum = linnum; + this._charnum = cast(ushort) charnum; this.filename = filename; } + /// utf8 code unit index relative to start of line, starting from 1 + extern (C++) uint charnum() const @nogc @safe + { + return _charnum; + } + + /// ditto + extern (C++) uint charnum(uint num) @nogc @safe + { + return _charnum = cast(ushort) num; + } + + /// line number, starting from 1 + extern (C++) uint linnum() const @nogc @safe + { + return _linnum; + } + + /// ditto + extern (C++) uint linnum(uint num) @nogc @safe + { + return _linnum = num; + } + + /*** + * Returns: filename for this location, null if none + */ + extern (C++) const(char)* filename() const @nogc + { + return fileIndex ? filenames[fileIndex - 1] : null; + } + + /*** + * Set file name for this location + * Params: + * name = file name for location, null for no file name + */ + extern (C++) void filename(const(char)* name) + { + if (name) + { + //printf("setting %s\n", name); + filenames.push(name); + fileIndex = cast(ushort)filenames.length; + assert(fileIndex); // no overflow + } + else + fileIndex = 0; + } + extern (C++) const(char)* toChars( bool showColumns = Loc.showColumns, - MessageStyle messageStyle = Loc.messageStyle) const pure nothrow + MessageStyle messageStyle = Loc.messageStyle) const nothrow { OutBuffer buf; - if (filename) + if (fileIndex) { buf.writestring(filename); } @@ -126,7 +180,7 @@ nothrow: * may lead to multiple equivalent filenames (`foo.d-mixin-<line>`), * e.g., for test/runnable/test18880.d. */ - extern (D) bool opEquals(ref const(Loc) loc) const @trusted pure nothrow @nogc + extern (D) bool opEquals(ref const(Loc) loc) const @trusted nothrow @nogc { import core.stdc.string : strcmp; @@ -137,7 +191,7 @@ nothrow: } /// ditto - extern (D) size_t toHash() const @trusted pure nothrow + extern (D) size_t toHash() const @trusted nothrow { import dmd.root.string : toDString; @@ -153,6 +207,6 @@ nothrow: */ bool isValid() const pure { - return filename !is null; + return fileIndex != 0; } } diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index badc579..cb3e6cd 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -2448,7 +2448,7 @@ extern (C++) abstract class Type : ASTNode //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); assert(0 < length && length < namelen); // don't overflow the buffer - auto id = Identifier.idPool(name, length); + auto id = Identifier.idPool(name[0 .. length]); if (name != namebuf.ptr) free(name); @@ -7119,9 +7119,9 @@ bool isCopyable(Type t) assert(ctor); scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue el.type = cast() ts; - Expressions args; + Expressions* args = new Expressions(); args.push(el); - FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(&args), FuncResolveFlag.quiet); + FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet); if (!f || f.storage_class & STC.disable) return false; } diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index a0f3e60..9a8f242 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -16,7 +16,6 @@ module dmd.nogc; import core.stdc.stdio; import dmd.aggregate; -import dmd.apply; import dmd.astenums; import dmd.declaration; import dmd.dscope; @@ -26,6 +25,7 @@ import dmd.func; import dmd.globals; import dmd.init; import dmd.mtype; +import dmd.postordervisitor; import dmd.tokens; import dmd.visitor; diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index 89728b6..56243a0 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -20,7 +20,6 @@ import dmd.root.rootobject; import dmd.root.rmem; import dmd.aggregate; -import dmd.apply; import dmd.arraytypes; import dmd.astenums; import dmd.declaration; diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index d7b90d7..0e64d9c 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -607,8 +607,6 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) //printf("BinExp::op_overload() (%s)\n", e.toChars()); Identifier id = opId(e); Identifier id_r = opId_r(e); - Expressions args1; - Expressions args2; int argsset = 0; AggregateDeclaration ad1 = isAggregate(e.e1.type); AggregateDeclaration ad2 = isAggregate(e.e2.type); @@ -701,6 +699,8 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) } } } + Expressions* args1 = new Expressions(); + Expressions* args2 = new Expressions(); if (s || s_r) { /* Try: @@ -709,16 +709,16 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) * and see which is better. */ args1.setDim(1); - args1[0] = e.e1; - expandTuples(&args1); + (*args1)[0] = e.e1; + expandTuples(args1); args2.setDim(1); - args2[0] = e.e2; - expandTuples(&args2); + (*args2)[0] = e.e2; + expandTuples(args2); argsset = 1; MatchAccumulator m; if (s) { - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2)); + functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -727,7 +727,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) FuncDeclaration lastf = m.lastf; if (s_r) { - functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(&args1)); + functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -791,16 +791,16 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (!argsset) { args1.setDim(1); - args1[0] = e.e1; - expandTuples(&args1); + (*args1)[0] = e.e1; + expandTuples(args1); args2.setDim(1); - args2[0] = e.e2; - expandTuples(&args2); + (*args2)[0] = e.e2; + expandTuples(args2); } MatchAccumulator m; if (s_r) { - functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2)); + functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -809,7 +809,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) FuncDeclaration lastf = m.lastf; if (s) { - functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, ArgumentList(&args1)); + functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -1197,7 +1197,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) return ErrorExp.get(); } Identifier id = opId(e); - Expressions args2; + Expressions* args2 = new Expressions(); AggregateDeclaration ad1 = isAggregate(e.e1.type); Dsymbol s = null; Objects* tiargs = null; @@ -1240,10 +1240,10 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) * a.opOpAssign(b) */ args2.setDim(1); - args2[0] = e.e2; - expandTuples(&args2); + (*args2)[0] = e.e2; + expandTuples(args2); MatchAccumulator m; - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2)); + functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -1322,12 +1322,12 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop * b.opEquals(a) * and see which is better. */ - Expressions args1 = Expressions(1); - args1[0] = e.e1; - expandTuples(&args1); - Expressions args2 = Expressions(1); - args2[0] = e.e2; - expandTuples(&args2); + Expressions* args1 = new Expressions(1); + (*args1)[0] = e.e1; + expandTuples(args1); + Expressions* args2 = new Expressions(1); + (*args2)[0] = e.e2; + expandTuples(args2); MatchAccumulator m; if (0 && s && s_r) { @@ -1336,7 +1336,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop } if (s) { - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2)); + functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) return ErrorExp.get(); } @@ -1344,7 +1344,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop int count = m.count; if (s_r) { - functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(&args1)); + functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) return ErrorExp.get(); } diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 61c385f..335310d 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -769,11 +769,8 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) return; if (e.arguments) { - Type t1 = e.e1.type.toBasetype(); - if (auto td = t1.isTypeDelegate()) - t1 = td.next; // t1 can apparently be void for __ArrayDtor(T) calls - if (auto tf = t1.isTypeFunction()) + if (auto tf = e.calledFunctionType()) { foreach (i, ref arg; (*e.arguments)[]) { diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 68a2506..b7e0791 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -4515,10 +4515,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } if (_init) { - if (isThis) - error(token.loc, "cannot use syntax `alias this = %s`, use `alias %s this` instead", _init.toChars(), _init.toChars()); - else - error("alias cannot have initializer"); + error("alias cannot have initializer"); } v = new AST.AliasDeclaration(aliasLoc, ident, t); @@ -4780,23 +4777,20 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer addComment(s, comment); return a; } - version (none) + /* Look for: + * alias this = identifier; + */ + if (token.value == TOK.this_ && peekNext() == TOK.assign && peekNext2() == TOK.identifier) { - /* Look for: - * alias this = identifier; - */ - if (token.value == TOK.this_ && peekNext() == TOK.assign && peekNext2() == TOK.identifier) - { - check(TOK.this_); - check(TOK.assign); - auto s = new AliasThis(loc, token.ident); - nextToken(); - check(TOK.semicolon, "`alias this = Identifier`"); - auto a = new Dsymbols(); - a.push(s); - addComment(s, comment); - return a; - } + check(TOK.this_); + check(TOK.assign); + auto s = new AST.AliasThis(loc, token.ident); + nextToken(); + check(TOK.semicolon, "`alias this = Identifier`"); + auto a = new AST.Dsymbols(); + a.push(s); + addComment(s, comment); + return a; } /* Look for: * alias identifier = type; @@ -5032,7 +5026,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer stc = STC.ref_; nextToken(); } - if (token.value != TOK.leftParenthesis && token.value != TOK.leftCurly) + if (token.value != TOK.leftParenthesis && token.value != TOK.leftCurly && + token.value != TOK.goesTo) { // function type (parameters) { statements... } // delegate type (parameters) { statements... } @@ -5331,7 +5326,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer error("cannot use function constraints for non-template functions. Use `static if` instead"); } else - error("semicolon expected following function declaration"); + error("semicolon expected following function declaration, not `%s`", token.toChars()); } break; } @@ -7081,7 +7076,7 @@ LagainStc: private void checkParens(TOK value, AST.Expression e) { - if (precedence[e.op] == PREC.rel && !e.parens) + if (precedence[e.op] == PREC.rel) error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(value)); } @@ -8485,7 +8480,6 @@ LagainStc: // ( expression ) nextToken(); e = parseExpression(); - e.parens = true; check(loc, TOK.rightParenthesis); break; } @@ -8806,9 +8800,9 @@ LagainStc: nextToken(); return AST.ErrorExp.get(); } - e = new AST.TypeExp(loc, t); - e.parens = true; - e = parsePostExp(e); + auto te = new AST.TypeExp(loc, t); + te.parens = true; + e = parsePostExp(te); } else { @@ -9115,14 +9109,18 @@ LagainStc: private AST.Expression parseAndExp() { Loc loc = token.loc; + bool parens = token.value == TOK.leftParenthesis; auto e = parseCmpExp(); while (token.value == TOK.and) { - checkParens(TOK.and, e); - nextToken(); + if (!parens) + checkParens(TOK.and, e); + parens = nextToken() == TOK.leftParenthesis; auto e2 = parseCmpExp(); - checkParens(TOK.and, e2); + if (!parens) + checkParens(TOK.and, e2); e = new AST.AndExp(loc, e, e2); + parens = true; // don't call checkParens() for And loc = token.loc; } return e; @@ -9130,32 +9128,42 @@ LagainStc: private AST.Expression parseXorExp() { - const loc = token.loc; + Loc loc = token.loc; + bool parens = token.value == TOK.leftParenthesis; auto e = parseAndExp(); while (token.value == TOK.xor) { - checkParens(TOK.xor, e); - nextToken(); + if (!parens) + checkParens(TOK.xor, e); + parens = nextToken() == TOK.leftParenthesis; auto e2 = parseAndExp(); - checkParens(TOK.xor, e2); + if (!parens) + checkParens(TOK.xor, e2); e = new AST.XorExp(loc, e, e2); + parens = true; + loc = token.loc; } return e; } private AST.Expression parseOrExp() { - const loc = token.loc; + Loc loc = token.loc; + bool parens = token.value == TOK.leftParenthesis; auto e = parseXorExp(); while (token.value == TOK.or) { - checkParens(TOK.or, e); - nextToken(); + if (!parens) + checkParens(TOK.or, e); + parens = nextToken() == TOK.leftParenthesis; auto e2 = parseXorExp(); - checkParens(TOK.or, e2); + if (!parens) + checkParens(TOK.or, e2); e = new AST.OrExp(loc, e, e2); + parens = true; + loc = token.loc; } return e; } @@ -9206,6 +9214,7 @@ LagainStc: AST.Expression parseAssignExp() { + bool parens = token.value == TOK.leftParenthesis; AST.Expression e; e = parseCondExp(); if (e is null) @@ -9214,7 +9223,7 @@ LagainStc: // require parens for e.g. `t ? a = 1 : b = 2` void checkRequiredParens() { - if (e.op == EXP.question && !e.parens) + if (e.op == EXP.question && !parens) eSink.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(token.value)); } diff --git a/gcc/d/dmd/apply.d b/gcc/d/dmd/postordervisitor.d index d18b81f..a0c7115 100644 --- a/gcc/d/dmd/apply.d +++ b/gcc/d/dmd/postordervisitor.d @@ -9,11 +9,9 @@ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/apply.d */ -module dmd.apply; +module dmd.postordervisitor; import dmd.arraytypes; -import dmd.dsymbol; -import dmd.dsymbolsem; import dmd.dtemplate; import dmd.expression; import dmd.root.array; @@ -26,39 +24,6 @@ bool walkPostorder(Expression e, StoppableVisitor v) return v.stop; } -/********************************* - * Iterate this dsymbol or members of this scoped dsymbol, then - * call `fp` with the found symbol and `params`. - * Params: - * symbol = the dsymbol or parent of members to call fp on - * fp = function pointer to process the iterated symbol. - * If it returns nonzero, the iteration will be aborted. - * params = any parameters passed to fp. - * Returns: - * nonzero if the iteration is aborted by the return value of fp, - * or 0 if it's completed. - */ -int apply(FP, Params...)(Dsymbol symbol, FP fp, Params params) -{ - if (auto nd = symbol.isNspace()) - { - return nd.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } ); - } - if (auto ad = symbol.isAttribDeclaration()) - { - return ad.include(ad._scope).foreachDsymbol( (s) { return s && s.apply(fp, params); } ); - } - if (auto tm = symbol.isTemplateMixin()) - { - if (tm._scope) // if fwd reference - dsymbolSemantic(tm, null); // try to resolve it - - return tm.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } ); - } - - return fp(symbol, params); -} - /************************************** * An Expression tree walker that will visit each Expression e in the tree, * in depth-first evaluation order, and call fp(e,param) on it. diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index ee268d9..c40e72c 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -447,14 +447,12 @@ private extern(C++) final class Semantic2Visitor : Visitor const sameParams = tf1.parameterList == tf2.parameterList; // Allow the hack to declare overloads with different parameters/STC's - // @@@DEPRECATED_2.104@@@ - // Deprecated in 2020-08, make this an error in 2.104 if (parent1.isModule() && linkage1 != LINK.d && linkage1 != LINK.cpp && (!sameAttr || !sameParams) ) { - f2.deprecation("cannot overload `extern(%s)` function at %s", + f2.error("cannot overload `extern(%s)` function at %s", linkageToChars(f1._linkage), f1.loc.toChars()); return 0; diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index 3f3e7e6..90b86df 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/dmd/sideeffect.d @@ -11,7 +11,6 @@ module dmd.sideeffect; -import dmd.apply; import dmd.astenums; import dmd.declaration; import dmd.dscope; @@ -22,6 +21,7 @@ import dmd.globals; import dmd.identifier; import dmd.init; import dmd.mtype; +import dmd.postordervisitor; import dmd.tokens; import dmd.visitor; @@ -101,9 +101,11 @@ extern (C++) bool hasSideEffect(Expression e, bool assumeImpureCalls = false) int callSideEffectLevel(FuncDeclaration f) { /* https://issues.dlang.org/show_bug.cgi?id=12760 - * ctor call always has side effects. + * https://issues.dlang.org/show_bug.cgi?id=16384 + * + * ctor calls and invariant calls always have side effects */ - if (f.isCtorDeclaration()) + if (f.isCtorDeclaration() || f.isInvariantDeclaration()) return 0; assert(f.type.ty == Tfunction); TypeFunction tf = cast(TypeFunction)f.type; diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index f849ce1..f0454163 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -1273,8 +1273,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } else if (auto td = sfront.isTemplateDeclaration()) { - Expressions a; - if (auto f = resolveFuncCall(loc, sc, td, null, tab, ArgumentList(&a), FuncResolveFlag.quiet)) + if (auto f = resolveFuncCall(loc, sc, td, null, tab, ArgumentList(), FuncResolveFlag.quiet)) tfront = f.type; } else if (auto d = sfront.toAlias().isDeclaration()) @@ -2733,7 +2732,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) tbret = tret.toBasetype(); } - if (inferRef) // deduce 'auto ref' + // https://issues.dlang.org/show_bug.cgi?id=23914 + if (inferRef && !resType.isTypeNoreturn()) // deduce 'auto ref' tf.isref = false; if (tbret.ty != Tvoid && !resType.isTypeNoreturn()) // if non-void return @@ -3593,6 +3593,11 @@ Statement statementSemanticVisit(Statement s, Scope* sc) cas.error("`asm` statement is assumed to be impure - mark it with `pure` if it is not"); if (!(cas.stc & STC.nogc) && sc.func.setGC(cas.loc, "`asm` statement in %s `%s` is assumed to use the GC - mark it with `@nogc` if it does not")) cas.error("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not"); + // @@@DEPRECATED_2.114@@@ + // change deprecation() to error(), add `else` and remove `| STC.safe` + // to turn deprecation into an error when deprecation cycle is over + if (cas.stc & STC.safe) + cas.deprecation("`asm` statement cannot be marked `@safe`, use `@system` or `@trusted` instead"); if (!(cas.stc & (STC.trusted | STC.safe))) { sc.setUnsafe(false, cas.loc, "`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not"); @@ -4045,6 +4050,13 @@ void catchSemantic(Catch c, Scope* sc) // reference .object.Throwable c.type = getThrowable(); } + else if (!c.type.isNaked() && !c.type.isConst()) + { + // @@@DEPRECATED_2.113@@@ + // Deprecated in 2.103, change into an error & uncomment in 2.113 + deprecation(c.loc, "can only catch mutable or const qualified types, not `%s`", c.type.toChars()); + //c.errors = true; + } c.type = c.type.typeSemantic(c.loc, sc); if (c.type == Type.terror) { diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 352c89e..5871762 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -593,7 +593,7 @@ shared static this() nothrow foreach (kw; keywords) { //printf("keyword[%d] = '%s'\n",kw, Token.tochars[kw].ptr); - Identifier.idPool(Token.tochars[kw].ptr, Token.tochars[kw].length, cast(uint)kw); + Identifier.idPool(Token.tochars[kw], kw); } } diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index 0f36353..53c8fb0 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -1215,7 +1215,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) { if (fd.overnext) { - deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not overload sets such as: `%s`", fd.toChars()); + deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not the overload set `%s`", fd.toChars()); deprecationSupplemental(e.loc, "the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from"); } } @@ -1225,7 +1225,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) { if (td.overnext || td.funcroot) { - deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not overload sets such as: `%s`", td.ident.toChars()); + deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not the overload set `%s`", td.ident.toChars()); deprecationSupplemental(e.loc, "the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from"); } } diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d index c588270..a82a268 100644 --- a/gcc/d/dmd/transitivevisitor.d +++ b/gcc/d/dmd/transitivevisitor.d @@ -161,6 +161,16 @@ package mixin template ParseVisitMethods(AST) s._body.accept(this); } + override void visit(AST.StaticForeachStatement s) + { + // printf("Visiting StaticForeachStatement\n"); + if (s.sfe.aggrfe) + s.sfe.aggrfe.accept(this); + + if (s.sfe.rangefe) + s.sfe.rangefe.accept(this); + } + override void visit(AST.IfStatement s) { //printf("Visiting IfStatement\n"); diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index f0decf2..09eef83 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -163,7 +163,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb /* Look for what user might have intended */ const p = mt.mutableOf().unSharedOf().toChars(); - auto id = Identifier.idPool(p, cast(uint)strlen(p)); + auto id = Identifier.idPool(p[0 .. strlen(p)]); if (const n = importHint(id.toString())) error(loc, "`%s` is not defined, perhaps `import %.*s;` ?", p, cast(int)n.length, n.ptr); else if (auto s2 = sc.search_correct(id)) |