diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2024-03-03 20:28:58 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2024-03-03 23:42:56 +0100 |
commit | bbfbaa792b50ebd75b383be25f50c92f30243256 (patch) | |
tree | 745acbaba5cd3643e8e3ed9797a4ca258d2ae1d8 /gcc | |
parent | 24975a9195743e8eb4ca213f35b9221d4eeb6b59 (diff) | |
download | gcc-bbfbaa792b50ebd75b383be25f50c92f30243256.zip gcc-bbfbaa792b50ebd75b383be25f50c92f30243256.tar.gz gcc-bbfbaa792b50ebd75b383be25f50c92f30243256.tar.bz2 |
d: Merge upstream dmd, druntime f8bae04558, phobos ba2ade9dec
D front-end changes:
- Import dmd v2.108.1-beta-1.
D runtime changes:
- Import druntime v2.108.1-beta-1.
Phobos changes:
- Import phobos v2.108.1-beta-1.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd f8bae04558.
* dmd/VERSION: Bump version to v2.108.0-beta.1.
* d-builtins.cc (build_frontend_type): Update for new front-end
interface.
* d-codegen.cc (build_assert_call): Likewise.
* d-convert.cc (d_array_convert): Likewise.
* decl.cc (get_vtable_decl): Likewise.
* expr.cc (ExprVisitor::visit (EqualExp *)): Likewise.
(ExprVisitor::visit (VarExp *)): Likewise.
(ExprVisitor::visit (ArrayLiteralExp *)): Likewise.
(ExprVisitor::visit (AssocArrayLiteralExp)): Likewise.
* intrinsics.cc (build_shuffle_mask_type): Likewise.
(maybe_warn_intrinsic_mismatch): Likewise.
* runtime.cc (get_libcall_type): Likewise.
* typeinfo.cc (TypeInfoVisitor::layout_string): Likewise.
(TypeInfoVisitor::visit(TypeInfoTupleDeclaration *)): Likewise.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime 02d6d07a69.
* src/MERGE: Merge upstream phobos a2ade9dec.
Diffstat (limited to 'gcc')
30 files changed, 644 insertions, 570 deletions
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index dc50df4..4546c0e 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -197,8 +197,8 @@ build_frontend_type (tree type) length = size_binop (PLUS_EXPR, size_one_node, convert (sizetype, length)); - dtype = - dmd::addMod (dtype->sarrayOf (TREE_INT_CST_LOW (length)), mod); + dtype = dmd::sarrayOf (dtype, TREE_INT_CST_LOW (length)); + dtype = dmd::addMod (dtype, mod); builtin_converted_decls.safe_push (builtin_data (dtype, type)); return dtype; } @@ -214,7 +214,7 @@ build_frontend_type (tree type) if (!dtype) break; - dtype = dmd::addMod (dtype->sarrayOf (nunits), mod); + dtype = dmd::addMod (dmd::sarrayOf (dtype, nunits), mod); if (target.isVectorTypeSupported (dtype->size (), dtype->nextOf ())) break; diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 43d7739f..2b3089b 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -1906,7 +1906,7 @@ build_assert_call (const Loc &loc, libcall_fn libcall, tree msg) tree str = build_string (len, filename); TREE_TYPE (str) = make_array_type (Type::tchar, len); - file = d_array_value (build_ctype (Type::tchar->arrayOf ()), + file = d_array_value (build_ctype (dmd::arrayOf (Type::tchar)), size_int (len), build_address (str)); } else diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc index 4ccbf09..5c79cdf 100644 --- a/gcc/d/d-convert.cc +++ b/gcc/d/d-convert.cc @@ -957,7 +957,7 @@ d_array_convert (Expression *exp) if (tb->ty == TY::Tsarray) { - Type *totype = tb->nextOf ()->arrayOf (); + Type *totype = dmd::arrayOf (tb->nextOf ()); return convert_expr (build_expr (exp), exp->type, totype); } @@ -986,7 +986,7 @@ d_array_convert (Type *etype, Expression *exp) expr = compound_expr (modify_expr (var, expr), var); } - return d_array_value (build_ctype (exp->type->arrayOf ()), + return d_array_value (build_ctype (dmd::arrayOf (exp->type)), size_int (1), build_address (expr)); } else diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 25398a3..3b7627d 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -2211,7 +2211,7 @@ get_vtable_decl (ClassDeclaration *decl) tree ident = mangle_internal_decl (decl, "__vtbl", "Z"); /* Note: Using a static array type for the VAR_DECL, the DECL_INITIAL value will have a different type. However the back-end seems to accept this. */ - tree type = build_ctype (Type::tvoidptr->sarrayOf (decl->vtbl.length)); + tree type = build_ctype (dmd::sarrayOf (Type::tvoidptr, decl->vtbl.length)); Dsymbol *vtblsym = decl->vtblSymbol (); vtblsym->csym = declare_extern_var (ident, type); diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index f11c5fb..4c0a0bc 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -ceff48bf7db05503117f54fdc0cefcb89b711136 +f8bae0455851a1dfc8113d69323415f6de549e39 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/VERSION b/gcc/d/dmd/VERSION index 1880c98..4168076 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.107.1-rc.1 +v2.108.0-beta.1 diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 0686e1b..6ec31d5 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -36,7 +36,7 @@ import dmd.root.utf; import dmd.sideeffect; import dmd.target; import dmd.tokens; -import dmd.typesem : toDsymbol, equivalent; +import dmd.typesem : toDsymbol, equivalent, sarrayOf; private enum LOG = false; diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index e917d2c..aeedb49 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -2155,7 +2155,7 @@ final class CParser(AST) : Parser!AST error("function identifier-list cannot end with `...`"); ft.parameterList.varargs = AST.VarArg.KRvariadic; // but C11 allows extra arguments auto plLength = pl.length; - if (symbols.length != plLength) + if (symbols && symbols.length != plLength) error(token.loc, "%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length); /* Transfer the types and storage classes from symbols[] to pl[] @@ -2176,6 +2176,12 @@ final class CParser(AST) : Parser!AST if (p.type || !(p.storageClass & STC.parameter)) error("storage class and type are not allowed in identifier-list"); + if (!symbols) + { + // Error already given in cparseDeclaration + p.type = AST.Type.terror; + continue; + } foreach (s; (*symbols)[]) // yes, quadratic { auto ad = s.isAttribDeclaration(); diff --git a/gcc/d/dmd/cxxfrontend.d b/gcc/d/dmd/cxxfrontend.d index 1b94a69..8c04634 100644 --- a/gcc/d/dmd/cxxfrontend.d +++ b/gcc/d/dmd/cxxfrontend.d @@ -475,6 +475,18 @@ bool equivalent(Type src, Type t) return dmd.typesem.equivalent(src, t); } +Type sarrayOf(Type type, dinteger_t dim) +{ + import dmd.typesem; + return dmd.typesem.sarrayOf(type, dim); +} + +Type arrayOf(Type type) +{ + import dmd.typesem; + return dmd.typesem.arrayOf(type); +} + Type constOf(Type type) { import dmd.typesem; @@ -535,6 +547,30 @@ Type sharedWildConstOf(Type type) return dmd.typesem.sharedWildConstOf(type); } +Type substWildTo(Type type, uint mod) +{ + import dmd.typesem; + return dmd.typesem.substWildTo(type, mod); +} + +Type unqualify(Type type, uint m) +{ + import dmd.typesem; + return dmd.typesem.unqualify(type, m); +} + +Type toHeadMutable(const(Type) type) +{ + import dmd.typesem; + return dmd.typesem.toHeadMutable(type); +} + +Type aliasthisOf(Type type) +{ + import dmd.typesem; + return dmd.typesem.aliasthisOf(type); +} + Type castMod(Type type, MOD mod) { import dmd.typesem; diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d index 3679976..5c739ee 100644 --- a/gcc/d/dmd/denum.d +++ b/gcc/d/dmd/denum.d @@ -20,7 +20,6 @@ import dmd.astenums; import dmd.attrib; import dmd.gluelayer; import dmd.declaration; -import dmd.dscope; import dmd.dsymbol; import dmd.expression; import dmd.id; diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 467e29f..c492490 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -50,7 +50,7 @@ import dmd.rootobject; import dmd.root.utf; import dmd.statement; import dmd.tokens; -import dmd.typesem : mutableOf, equivalent, pointerTo; +import dmd.typesem : mutableOf, equivalent, pointerTo, sarrayOf, arrayOf; import dmd.utils : arrayCastBigEndian; import dmd.visitor; @@ -3787,7 +3787,7 @@ public: if (v is v2 || !v.isOverlappedWith(v2)) continue; auto e = (*sle.elements)[i]; - if (e.op != EXP.void_) + if (e !is null && e.op != EXP.void_) (*sle.elements)[i] = voidInitLiteral(e.type, v).copy(); } } diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index a77e4f3..58bf3fd 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -1394,6 +1394,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) { enum SourceEncoding { utf16, utf32} enum Endian { little, big} + immutable loc = mod.getLoc(); /* * Convert a buffer from UTF32 to UTF8 @@ -1413,7 +1414,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) if (buf.length & 3) { - .error(mod.loc, "%s `%s` odd length of UTF-32 char source %llu", + .error(loc, "%s `%s` odd length of UTF-32 char source %llu", mod.kind, mod.toPrettyChars, cast(ulong) buf.length); return null; } @@ -1430,7 +1431,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) { if (u > 0x10FFFF) { - .error(mod.loc, "%s `%s` UTF-32 value %08x greater than 0x10FFFF", mod.kind, mod.toPrettyChars, u); + .error(loc, "%s `%s` UTF-32 value %08x greater than 0x10FFFF", mod.kind, mod.toPrettyChars, u); return null; } dbuf.writeUTF8(u); @@ -1460,7 +1461,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) if (buf.length & 1) { - .error(mod.loc, "%s `%s` odd length of UTF-16 char source %llu", mod.kind, mod.toPrettyChars, cast(ulong) buf.length); + .error(loc, "%s `%s` odd length of UTF-16 char source %llu", mod.kind, mod.toPrettyChars, cast(ulong) buf.length); return null; } @@ -1480,13 +1481,13 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) i++; if (i >= eBuf.length) { - .error(mod.loc, "%s `%s` surrogate UTF-16 high value %04x at end of file", mod.kind, mod.toPrettyChars, u); + .error(loc, "%s `%s` surrogate UTF-16 high value %04x at end of file", mod.kind, mod.toPrettyChars, u); return null; } const u2 = readNext(&eBuf[i]); if (u2 < 0xDC00 || 0xE000 <= u2) { - .error(mod.loc, "%s `%s` surrogate UTF-16 low value %04x out of range", mod.kind, mod.toPrettyChars, u2); + .error(loc, "%s `%s` surrogate UTF-16 low value %04x out of range", mod.kind, mod.toPrettyChars, u2); return null; } u = (u - 0xD7C0) << 10; @@ -1494,12 +1495,12 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) } else if (u >= 0xDC00 && u <= 0xDFFF) { - .error(mod.loc, "%s `%s` unpaired surrogate UTF-16 value %04x", mod.kind, mod.toPrettyChars, u); + .error(loc, "%s `%s` unpaired surrogate UTF-16 value %04x", mod.kind, mod.toPrettyChars, u); return null; } else if (u == 0xFFFE || u == 0xFFFF) { - .error(mod.loc, "%s `%s` illegal UTF-16 value %04x", mod.kind, mod.toPrettyChars, u); + .error(loc, "%s `%s` illegal UTF-16 value %04x", mod.kind, mod.toPrettyChars, u); return null; } dbuf.writeUTF8(u); @@ -1558,7 +1559,6 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) // It's UTF-8 if (buf[0] >= 0x80) { - auto loc = mod.getLoc(); .error(loc, "%s `%s` source file must start with BOM or ASCII character, not \\x%02X", mod.kind, mod.toPrettyChars, buf[0]); return null; } diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index b4d5274..db40ae0 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -12357,8 +12357,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return result; } - void handleCatArgument(Expressions *arguments, Expression e) + void handleCatArgument(Expressions *arguments, Expression e, Type catType, bool isRightArg) { + auto tb = e.type.toBasetype(); + + if ((isRightArg && e.parens) || (!isRightArg && !tb.equals(catType))) + { + arguments.push(e); + return; + } + if (auto ce = e.isCatExp()) { Expression lowering = ce.lowering; @@ -12388,8 +12396,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor arguments.push(new StringExp(exp.loc, funcname.toDString())); } - handleCatArgument(arguments, exp.e1); - handleCatArgument(arguments, exp.e2); + handleCatArgument(arguments, exp.e1, exp.type.toBasetype(), false); + handleCatArgument(arguments, exp.e2, exp.type.toBasetype(), true); Expression id = new IdentifierExp(exp.loc, Id.empty); id = new DotIdExp(exp.loc, id, Id.object); diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index d890811..7003c2b 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -34,12 +34,10 @@ import dmd.dmodule; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; -import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.escape; import dmd.expression; -import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -57,7 +55,6 @@ import dmd.semantic2; import dmd.semantic3; import dmd.statement_rewrite_walker; import dmd.statement; -import dmd.statementsem; import dmd.tokens; import dmd.typesem; import dmd.visitor; @@ -115,90 +112,6 @@ enum BUILTIN : ubyte toPrecReal } -/* Tweak all return statements and dtor call for nrvo_var, for correct NRVO. - */ -extern (C++) final class NrvoWalker : StatementRewriteWalker -{ - alias visit = typeof(super).visit; -public: - FuncDeclaration fd; - Scope* sc; - - override void visit(ReturnStatement s) - { - // See if all returns are instead to be replaced with a goto returnLabel; - if (fd.returnLabel) - { - /* Rewrite: - * return exp; - * as: - * vresult = exp; goto Lresult; - */ - auto gs = new GotoStatement(s.loc, Id.returnLabel); - gs.label = fd.returnLabel; - - Statement s1 = gs; - if (s.exp) - s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs); - - replaceCurrent(s1); - } - } - - override void visit(TryFinallyStatement s) - { - DtorExpStatement des; - if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null && - fd.nrvo_var == des.var) - { - if (!(global.params.useExceptions && ClassDeclaration.throwable)) - { - /* Don't need to call destructor at all, since it is nrvo - */ - replaceCurrent(s._body); - s._body.accept(this); - return; - } - - /* Normally local variable dtors are called regardless exceptions. - * But for nrvo_var, its dtor should be called only when exception is thrown. - * - * Rewrite: - * try { s.body; } finally { nrvo_var.edtor; } - * // equivalent with: - * // s.body; scope(exit) nrvo_var.edtor; - * as: - * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; } - * // equivalent with: - * // s.body; scope(failure) nrvo_var.edtor; - */ - Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var); - Identifier id = Identifier.generateId("__o"); - - Statement handler = new PeelStatement(sexception); - if (sexception.blockExit(fd, null) & BE.fallthru) - { - auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id)); - ts.internalThrow = true; - handler = new CompoundStatement(Loc.initial, handler, ts); - } - - auto catches = new Catches(); - auto ctch = new Catch(Loc.initial, getThrowable(), id, handler); - ctch.internalCatch = true; - ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o' - catches.push(ctch); - - Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches); - fd.hasNoEH = false; - replaceCurrent(s2); - s2.accept(this); - } - else - StatementRewriteWalker.visit(s); - } -} - private struct FUNCFLAG { bool purityInprocess; /// working on determining purity @@ -2022,44 +1935,6 @@ extern (C++) class FuncDeclaration : Declaration } /**************************************************** - * Declare result variable lazily. - */ - extern (D) final void buildResultVar(Scope* sc, Type tret) - { - if (!vresult) - { - Loc loc = fensure ? fensure.loc : this.loc; - - /* If inferRetType is true, tret may not be a correct return type yet. - * So, in here it may be a temporary type for vresult, and after - * fbody.dsymbolSemantic() running, vresult.type might be modified. - */ - vresult = new VarDeclaration(loc, tret, Id.result, null); - vresult.storage_class |= STC.nodtor | STC.temp; - if (!isVirtual()) - vresult.storage_class |= STC.const_; - vresult.storage_class |= STC.result; - - // set before the semantic() for checkNestedReference() - vresult.parent = this; - } - - if (sc && vresult.semanticRun == PASS.initial) - { - TypeFunction tf = type.toTypeFunction(); - if (tf.isref) - vresult.storage_class |= STC.ref_; - vresult.type = tret; - - vresult.dsymbolSemantic(sc); - - if (!sc.insert(vresult)) - .error(loc, "%s `%s` out result %s is already defined", kind, toPrettyChars, vresult.toChars()); - assert(vresult.parent == this); - } - } - - /**************************************************** * Merge into this function the 'in' contracts of all it overrides. * 'in's are OR'd together, i.e. only one of them needs to pass. */ @@ -2680,57 +2555,6 @@ extern (C++) class FuncDeclaration : Declaration } } -/******************************************************** - * Generate Expression to call the invariant. - * Input: - * ad aggregate with the invariant - * vthis variable with 'this' - * Returns: - * void expression that calls the invariant - */ -Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis) -{ - Expression e = null; - // Call invariant directly only if it exists - FuncDeclaration inv = ad.inv; - ClassDeclaration cd = ad.isClassDeclaration(); - - while (!inv && cd) - { - cd = cd.baseClass; - if (!cd) - break; - inv = cd.inv; - } - if (inv) - { - version (all) - { - // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394 - // For the correct mangling, - // run attribute inference on inv if needed. - functionSemantic(inv); - } - - //e = new DsymbolExp(Loc.initial, inv); - //e = new CallExp(Loc.initial, e); - //e = e.semantic(sc2); - - /* https://issues.dlang.org/show_bug.cgi?id=13113 - * Currently virtual invariant calls completely - * bypass attribute enforcement. - * Change the behavior of pre-invariant call by following it. - */ - e = new ThisExp(Loc.initial); - e.type = ad.type.addMod(vthis.type.mod); - e = new DotVarExp(Loc.initial, e, inv, false); - e.type = inv.type; - e = new CallExp(Loc.initial, e); - e.type = Type.tvoid; - } - return e; -} - /*************************************************** * Visit each overloaded function/template in turn, and call dg(s) on it. * Exit when no more, or dg(s) returns nonzero. diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d index b8b185c..2cadc40 100644 --- a/gcc/d/dmd/funcsem.d +++ b/gcc/d/dmd/funcsem.d @@ -65,6 +65,90 @@ import dmd.tokens; import dmd.typesem; import dmd.visitor; +/* Tweak all return statements and dtor call for nrvo_var, for correct NRVO. + */ +extern (C++) final class NrvoWalker : StatementRewriteWalker +{ + alias visit = typeof(super).visit; +public: + FuncDeclaration fd; + Scope* sc; + + override void visit(ReturnStatement s) + { + // See if all returns are instead to be replaced with a goto returnLabel; + if (fd.returnLabel) + { + /* Rewrite: + * return exp; + * as: + * vresult = exp; goto Lresult; + */ + auto gs = new GotoStatement(s.loc, Id.returnLabel); + gs.label = fd.returnLabel; + + Statement s1 = gs; + if (s.exp) + s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs); + + replaceCurrent(s1); + } + } + + override void visit(TryFinallyStatement s) + { + DtorExpStatement des; + if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null && + fd.nrvo_var == des.var) + { + if (!(global.params.useExceptions && ClassDeclaration.throwable)) + { + /* Don't need to call destructor at all, since it is nrvo + */ + replaceCurrent(s._body); + s._body.accept(this); + return; + } + + /* Normally local variable dtors are called regardless exceptions. + * But for nrvo_var, its dtor should be called only when exception is thrown. + * + * Rewrite: + * try { s.body; } finally { nrvo_var.edtor; } + * // equivalent with: + * // s.body; scope(exit) nrvo_var.edtor; + * as: + * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; } + * // equivalent with: + * // s.body; scope(failure) nrvo_var.edtor; + */ + Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var); + Identifier id = Identifier.generateId("__o"); + + Statement handler = new PeelStatement(sexception); + if (sexception.blockExit(fd, null) & BE.fallthru) + { + auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id)); + ts.internalThrow = true; + handler = new CompoundStatement(Loc.initial, handler, ts); + } + + auto catches = new Catches(); + auto ctch = new Catch(Loc.initial, getThrowable(), id, handler); + ctch.internalCatch = true; + ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o' + catches.push(ctch); + + Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches); + fd.hasNoEH = false; + replaceCurrent(s2); + s2.accept(this); + } + else + StatementRewriteWalker.visit(s); + } +} + /********************************** * Main semantic routine for functions. */ @@ -1755,3 +1839,87 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) if (constraintsTip) .tip(constraintsTip); } + +/******************************************************** + * Generate Expression to call the invariant. + * Input: + * ad aggregate with the invariant + * vthis variable with 'this' + * Returns: + * void expression that calls the invariant + */ +Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis) +{ + Expression e = null; + // Call invariant directly only if it exists + FuncDeclaration inv = ad.inv; + ClassDeclaration cd = ad.isClassDeclaration(); + + while (!inv && cd) + { + cd = cd.baseClass; + if (!cd) + break; + inv = cd.inv; + } + if (inv) + { + version (all) + { + // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394 + // For the correct mangling, + // run attribute inference on inv if needed. + functionSemantic(inv); + } + + //e = new DsymbolExp(Loc.initial, inv); + //e = new CallExp(Loc.initial, e); + //e = e.semantic(sc2); + + /* https://issues.dlang.org/show_bug.cgi?id=13113 + * Currently virtual invariant calls completely + * bypass attribute enforcement. + * Change the behavior of pre-invariant call by following it. + */ + e = new ThisExp(Loc.initial); + e.type = ad.type.addMod(vthis.type.mod); + e = new DotVarExp(Loc.initial, e, inv, false); + e.type = inv.type; + e = new CallExp(Loc.initial, e); + e.type = Type.tvoid; + } + return e; +} + +/**************************************************** + * Declare result variable lazily. + */ +void buildResultVar(FuncDeclaration fd, Scope* sc, Type tret) +{ + if (!fd.vresult) + { + Loc loc = fd.fensure ? fd.fensure.loc : fd.loc; + /* If inferRetType is true, tret may not be a correct return type yet. + * So, in here it may be a temporary type for vresult, and after + * fbody.dsymbolSemantic() running, vresult.type might be modified. + */ + fd.vresult = new VarDeclaration(loc, tret, Id.result, null); + fd.vresult.storage_class |= STC.nodtor | STC.temp; + if (!fd.isVirtual()) + fd.vresult.storage_class |= STC.const_; + fd.vresult.storage_class |= STC.result; + // set before the semantic() for checkNestedReference() + fd.vresult.parent = fd; + } + if (sc && fd.vresult.semanticRun == PASS.initial) + { + TypeFunction tf = fd.type.toTypeFunction(); + if (tf.isref) + fd.vresult.storage_class |= STC.ref_; + fd.vresult.type = tret; + fd.vresult.dsymbolSemantic(sc); + if (!sc.insert(fd.vresult)) + .error(fd.loc, "%s `%s` out result %s is already defined", fd.kind, fd.toPrettyChars, fd.vresult.toChars()); + assert(fd.vresult.parent == fd); + } +} diff --git a/gcc/d/dmd/location.d b/gcc/d/dmd/location.d index d71ea58..ca6805e 100644 --- a/gcc/d/dmd/location.d +++ b/gcc/d/dmd/location.d @@ -115,15 +115,7 @@ nothrow: //printf("setting %s\n", name); filenames.push(name); fileIndex = cast(uint)filenames.length; - if (!fileIndex) - { - import dmd.globals : global; - import dmd.errors : error, fatal; - - global.gag = 0; // ensure error message gets printed - error(Loc.initial, "internal compiler error: file name index overflow!"); - fatal(); - } + assert(fileIndex, "internal compiler error: file name index overflow"); } else fileIndex = 0; diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 843c402..2c9e058 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -1185,110 +1185,12 @@ extern (C++) abstract class Type : ASTNode return t; } - final Type arrayOf() - { - if (ty == Terror) - return this; - if (!arrayof) - { - Type t = new TypeDArray(this); - arrayof = t.merge(); - } - return arrayof; - } - - // Make corresponding static array type without semantic - final Type sarrayOf(dinteger_t dim) - { - assert(deco); - Type t = new TypeSArray(this, new IntegerExp(Loc.initial, dim, Type.tsize_t)); - // according to TypeSArray::semantic() - t = t.addMod(mod); - t = t.merge(); - return t; - } - final bool hasDeprecatedAliasThis() { auto ad = isAggregate(this); return ad && ad.aliasthis && (ad.aliasthis.isDeprecated || ad.aliasthis.sym.isDeprecated); } - final Type aliasthisOf() - { - auto ad = isAggregate(this); - if (!ad || !ad.aliasthis) - return null; - - auto s = ad.aliasthis.sym; - if (s.isAliasDeclaration()) - s = s.toAlias(); - - if (s.isTupleDeclaration()) - return null; - - if (auto vd = s.isVarDeclaration()) - { - auto t = vd.type; - if (vd.needThis()) - t = t.addMod(this.mod); - return t; - } - Dsymbol callable = s.isFuncDeclaration(); - callable = callable ? callable : s.isTemplateDeclaration(); - if (callable) - { - auto fd = resolveFuncCall(Loc.initial, null, callable, null, this, ArgumentList(), FuncResolveFlag.quiet); - if (!fd || fd.errors || !functionSemantic(fd)) - return Type.terror; - - auto t = fd.type.nextOf(); - if (!t) // https://issues.dlang.org/show_bug.cgi?id=14185 - return Type.terror; - t = t.substWildTo(mod == 0 ? MODFlags.mutable : mod); - return t; - } - if (auto d = s.isDeclaration()) - { - assert(d.type); - return d.type; - } - if (auto ed = s.isEnumDeclaration()) - { - return ed.type; - } - - //printf("%s\n", s.kind()); - return null; - } - - /** - * Check whether this type has endless `alias this` recursion. - * Returns: - * `true` if this type has an `alias this` that can be implicitly - * converted back to this type itself. - */ - extern (D) final bool checkAliasThisRec() - { - Type tb = toBasetype(); - AliasThisRec* pflag; - if (tb.ty == Tstruct) - pflag = &(cast(TypeStruct)tb).att; - else if (tb.ty == Tclass) - pflag = &(cast(TypeClass)tb).att; - else - return false; - - AliasThisRec flag = cast(AliasThisRec)(*pflag & AliasThisRec.typeMask); - if (flag == AliasThisRec.fwdref) - { - Type att = aliasthisOf(); - flag = att && att.implicitConvTo(this) ? AliasThisRec.yes : AliasThisRec.no; - } - *pflag = cast(AliasThisRec)(flag | (*pflag & ~AliasThisRec.typeMask)); - return flag == AliasThisRec.yes; - } - Type makeConst() { //printf("Type::makeConst() %p, %s\n", this, toChars()); @@ -1451,129 +1353,6 @@ extern (C++) abstract class Type : ASTNode return 0; } - Type substWildTo(uint mod) - { - //printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod); - Type t; - - if (Type tn = nextOf()) - { - // substitution has no effect on function pointer type. - if (ty == Tpointer && tn.ty == Tfunction) - { - t = this; - goto L1; - } - - t = tn.substWildTo(mod); - if (t == tn) - t = this; - else - { - if (ty == Tpointer) - t = t.pointerTo(); - else if (ty == Tarray) - t = t.arrayOf(); - else if (ty == Tsarray) - t = new TypeSArray(t, (cast(TypeSArray)this).dim.syntaxCopy()); - else if (ty == Taarray) - { - t = new TypeAArray(t, (cast(TypeAArray)this).index.syntaxCopy()); - } - else if (ty == Tdelegate) - { - t = new TypeDelegate(t.isTypeFunction()); - } - else - assert(0); - - t = t.merge(); - } - } - else - t = this; - - L1: - if (isWild()) - { - if (mod == MODFlags.immutable_) - { - t = t.immutableOf(); - } - else if (mod == MODFlags.wildconst) - { - t = t.wildConstOf(); - } - else if (mod == MODFlags.wild) - { - if (isWildConst()) - t = t.wildConstOf(); - else - t = t.wildOf(); - } - else if (mod == MODFlags.const_) - { - t = t.constOf(); - } - else - { - if (isWildConst()) - t = t.constOf(); - else - t = t.mutableOf(); - } - } - if (isConst()) - t = t.addMod(MODFlags.const_); - if (isShared()) - t = t.addMod(MODFlags.shared_); - - //printf("-Type::substWildTo t = %s\n", t.toChars()); - return t; - } - - final Type unqualify(uint m) - { - Type t = this.mutableOf().unSharedOf(); - - Type tn = ty == Tenum ? null : nextOf(); - if (tn && tn.ty != Tfunction) - { - Type utn = tn.unqualify(m); - if (utn != tn) - { - if (ty == Tpointer) - t = utn.pointerTo(); - else if (ty == Tarray) - t = utn.arrayOf(); - else if (ty == Tsarray) - t = new TypeSArray(utn, (cast(TypeSArray)this).dim); - else if (ty == Taarray) - { - t = new TypeAArray(utn, (cast(TypeAArray)this).index); - } - else - assert(0); - - t = t.merge(); - } - } - t = t.addMod(mod & ~m); - return t; - } - - /************************** - * Return type with the top level of it being mutable. - */ - inout(Type) toHeadMutable() inout - { - if (!mod) - return this; - Type unqualThis = cast(Type) this; - // `mutableOf` needs a mutable `this` only for caching - return cast(inout(Type)) unqualThis.mutableOf(); - } - inout(ClassDeclaration) isClassHandle() inout { return null; @@ -3396,55 +3175,6 @@ extern (C++) final class TypeFunction : TypeNext return linkage == LINK.d && parameterList.varargs == VarArg.variadic; } - override Type substWildTo(uint) - { - if (!iswild && !(mod & MODFlags.wild)) - return this; - - // Substitude inout qualifier of function type to mutable or immutable - // would break type system. Instead substitude inout to the most weak - // qualifer - const. - uint m = MODFlags.const_; - - assert(next); - Type tret = next.substWildTo(m); - Parameters* params = parameterList.parameters; - if (mod & MODFlags.wild) - params = parameterList.parameters.copy(); - for (size_t i = 0; i < params.length; i++) - { - Parameter p = (*params)[i]; - Type t = p.type.substWildTo(m); - if (t == p.type) - continue; - if (params == parameterList.parameters) - params = parameterList.parameters.copy(); - (*params)[i] = new Parameter(p.loc, p.storageClass, t, null, null, null); - } - if (next == tret && params == parameterList.parameters) - return this; - - // Similar to TypeFunction::syntaxCopy; - auto t = new TypeFunction(ParameterList(params, parameterList.varargs), tret, linkage); - t.mod = ((mod & MODFlags.wild) ? (mod & ~MODFlags.wild) | MODFlags.const_ : mod); - t.isnothrow = isnothrow; - t.isnogc = isnogc; - t.purity = purity; - t.isproperty = isproperty; - t.isref = isref; - t.isreturn = isreturn; - t.isreturnscope = isreturnscope; - t.isScopeQual = isScopeQual; - t.isreturninferred = isreturninferred; - t.isscopeinferred = isscopeinferred; - t.isInOutParam = false; - t.isInOutQual = false; - t.trust = trust; - t.fargs = fargs; - t.isctor = isctor; - return t.merge(); - } - extern(D) static const(char)* getMatchError(A...)(const(char)* format, A args) { if (global.gag && !global.params.v.showGaggedErrors) @@ -4316,7 +4046,7 @@ extern (C++) final class TypeStruct : Type MATCH m; if (!(ty == to.ty && sym == (cast(TypeStruct)to).sym) && sym.aliasthis && !(att & AliasThisRec.tracing)) { - if (auto ato = aliasthisOf()) + if (auto ato = aliasthisOf(this)) { att = cast(AliasThisRec)(att | AliasThisRec.tracing); m = ato.implicitConvTo(to); @@ -4353,7 +4083,7 @@ extern (C++) final class TypeStruct : Type if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing)) { - if (auto ato = aliasthisOf()) + if (auto ato = aliasthisOf(this)) { att = cast(AliasThisRec)(att | AliasThisRec.tracing); wm = ato.deduceWild(t, isRef); @@ -4364,11 +4094,6 @@ extern (C++) final class TypeStruct : Type return wm; } - override inout(Type) toHeadMutable() inout - { - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -4595,7 +4320,7 @@ extern (C++) final class TypeClass : Type MATCH m; if (sym.aliasthis && !(att & AliasThisRec.tracing)) { - if (auto ato = aliasthisOf()) + if (auto ato = aliasthisOf(this)) { att = cast(AliasThisRec)(att | AliasThisRec.tracing); m = ato.implicitConvTo(to); @@ -4644,7 +4369,7 @@ extern (C++) final class TypeClass : Type if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing)) { - if (auto ato = aliasthisOf()) + if (auto ato = aliasthisOf(this)) { att = cast(AliasThisRec)(att | AliasThisRec.tracing); wm = ato.deduceWild(t, isRef); @@ -4655,11 +4380,6 @@ extern (C++) final class TypeClass : Type return wm; } - override inout(Type) toHeadMutable() inout - { - return this; - } - override bool isZeroInit(const ref Loc loc) { return true; @@ -5852,36 +5572,3 @@ TypeIdentifier getException() tid.addIdent(Id.Exception); return tid; } - -/************************************** - * Check and set 'att' if 't' is a recursive 'alias this' type - * - * The goal is to prevent endless loops when there is a cycle in the alias this chain. - * Since there is no multiple `alias this`, the chain either ends in a leaf, - * or it loops back on itself as some point. - * - * Example: S0 -> (S1 -> S2 -> S3 -> S1) - * - * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried. - * `S1` is a recursive alias this type, but since `att` is initialized to `null`, - * this still returns `false`, but `att1` is set to `S1`. - * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again, - * we notice `att == t`, so we're back at the start of the loop, and this returns `true`. - * - * Params: - * att = type reference used to detect recursion. Should be initialized to `null`. - * t = type of 'alias this' rewrite to attempt - * - * Returns: - * `false` if the rewrite is safe, `true` if it would loop back around - */ -bool isRecursiveAliasThis(ref Type att, Type t) -{ - //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars()); - auto tb = t.toBasetype(); - if (att && tb.equivalent(att)) - return true; - else if (!att && tb.checkAliasThisRec()) - att = tb; - return false; -} diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index 57f4ec6..2f8bfa6 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -257,7 +257,6 @@ public: Type *arrayOf(); Type *sarrayOf(dinteger_t dim); bool hasDeprecatedAliasThis(); - Type *aliasthisOf(); virtual Type *makeConst(); virtual Type *makeImmutable(); virtual Type *makeShared(); @@ -271,11 +270,7 @@ public: virtual MATCH implicitConvTo(Type *to); virtual MATCH constConv(Type *to); virtual unsigned char deduceWild(Type *t, bool isRef); - virtual Type *substWildTo(unsigned mod); - Type *unqualify(unsigned m); - - virtual Type *toHeadMutable(); virtual ClassDeclaration *isClassHandle(); virtual structalign_t alignment(); virtual Expression *defaultInitLiteral(const Loc &loc); @@ -580,7 +575,6 @@ public: bool hasLazyParameters(); bool isDstyleVariadic() const; - Type *substWildTo(unsigned mod) override; MATCH constConv(Type *to) override; bool isnothrow() const; @@ -751,7 +745,6 @@ public: MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; unsigned char deduceWild(Type *t, bool isRef) override; - Type *toHeadMutable() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -804,7 +797,6 @@ public: MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; unsigned char deduceWild(Type *t, bool isRef) override; - Type *toHeadMutable() override; bool isZeroInit(const Loc &loc) override; bool isscope() override; bool isBoolean() override; @@ -892,6 +884,8 @@ namespace dmd Type *pointerTo(Type *type); Type *referenceTo(Type *type); Type *merge2(Type *type); + Type *sarrayOf(Type *type, dinteger_t dim); + Type *arrayOf(Type *type); Type *constOf(Type *type); Type *immutableOf(Type *type); Type *mutableOf(Type *type); @@ -902,7 +896,11 @@ namespace dmd Type *wildConstOf(Type *type); Type *sharedWildOf(Type *type); Type *sharedWildConstOf(Type *type); + Type *unqualify(Type *type, unsigned m); + Type *toHeadMutable(Type *type); + Type *aliasthisOf(Type *type); Type *castMod(Type *type, MOD mod); Type *addMod(Type *type, MOD mod); Type *addStorageClass(Type *type, StorageClass stc); + Type *substWildTo(Type *type, unsigned mod); } diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index dd6b117..2c89a58 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -1349,7 +1349,7 @@ Expression optimize(Expression e, int result, bool keepLvalue = false) if (b++ == global.recursionLimit) { error(e.loc, "infinite loop while optimizing expression"); - fatal(); + return ErrorExp.get(); } auto ex = ret; diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index 8b57f7f..1e5fb47 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -26,7 +26,7 @@ import dmd.identifier; import dmd.mtype; import dmd.target; import dmd.tokens; -import dmd.typesem : hasPointers; +import dmd.typesem : hasPointers, arrayOf; import dmd.func : setUnsafe, setUnsafePreview; /************************************************************* diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 61272ea..ad87ea0 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1687,7 +1687,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc) if (!ClassDeclaration.object) { .error(Loc.initial, "missing or corrupt object.d"); - fatal(); + return error(); } __gshared FuncDeclaration feq = null; @@ -6229,6 +6229,29 @@ Type referenceTo(Type type) return type.rto; } +// Make corresponding static array type without semantic +Type sarrayOf(Type type, dinteger_t dim) +{ + assert(type.deco); + Type t = new TypeSArray(type, new IntegerExp(Loc.initial, dim, Type.tsize_t)); + // according to TypeSArray.semantic() + t = t.addMod(type.mod); + t = t.merge(); + return t; +} + +Type arrayOf(Type type) +{ + if (type.ty == Terror) + return type; + if (!type.arrayof) + { + Type t = new TypeDArray(type); + type.arrayof = t.merge(); + } + return type.arrayof; +} + /******************************** * Convert to 'const'. */ @@ -6478,6 +6501,104 @@ Type sharedWildConstOf(Type type) return t; } +Type unqualify(Type type, uint m) +{ + Type t = type.mutableOf().unSharedOf(); + + Type tn = type.ty == Tenum ? null : type.nextOf(); + if (tn && tn.ty != Tfunction) + { + Type utn = tn.unqualify(m); + if (utn != tn) + { + if (type.ty == Tpointer) + t = utn.pointerTo(); + else if (type.ty == Tarray) + t = utn.arrayOf(); + else if (type.ty == Tsarray) + t = new TypeSArray(utn, (cast(TypeSArray)type).dim); + else if (type.ty == Taarray) + { + t = new TypeAArray(utn, (cast(TypeAArray)type).index); + } + else + assert(0); + + t = t.merge(); + } + } + t = t.addMod(type.mod & ~m); + return t; +} + +/************************** + * Return type with the top level of it being mutable. + * + * Params: + * t = type for which the top level mutable version is being returned + * + * Returns: + * type version with mutable top level + */ +Type toHeadMutable(const Type t) +{ + Type unqualType = cast(Type) t; + if (t.isTypeStruct() || t.isTypeClass()) + return unqualType; + + if (!t.mod) + return unqualType; + return unqualType.mutableOf(); +} + +Type aliasthisOf(Type type) +{ + auto ad = isAggregate(type); + if (!ad || !ad.aliasthis) + return null; + + auto s = ad.aliasthis.sym; + if (s.isAliasDeclaration()) + s = s.toAlias(); + + if (s.isTupleDeclaration()) + return null; + + if (auto vd = s.isVarDeclaration()) + { + auto t = vd.type; + if (vd.needThis()) + t = t.addMod(type.mod); + return t; + } + Dsymbol callable = s.isFuncDeclaration(); + callable = callable ? callable : s.isTemplateDeclaration(); + if (callable) + { + auto fd = resolveFuncCall(Loc.initial, null, callable, null, type, ArgumentList(), FuncResolveFlag.quiet); + if (!fd || fd.errors || !functionSemantic(fd)) + return Type.terror; + + auto t = fd.type.nextOf(); + if (!t) // https://issues.dlang.org/show_bug.cgi?id=14185 + return Type.terror; + t = t.substWildTo(type.mod == 0 ? MODFlags.mutable : type.mod); + return t; + } + if (auto d = s.isDeclaration()) + { + assert(d.type); + return d.type; + } + if (auto ed = s.isEnumDeclaration()) + { + return ed.type; + } + + //printf("%s\n", s.kind()); + return null; +} + /************************************ * Apply MODxxxx bits to existing type. */ @@ -6528,6 +6649,137 @@ Type castMod(Type type, MOD mod) return t; } +Type substWildTo(Type type, uint mod) +{ + auto tf = type.isTypeFunction(); + if (!tf) + { + //printf("+Type.substWildTo this = %s, mod = x%x\n", toChars(), mod); + Type t; + + if (Type tn = type.nextOf()) + { + // substitution has no effect on function pointer type. + if (type.ty == Tpointer && tn.ty == Tfunction) + { + t = type; + goto L1; + } + + t = tn.substWildTo(mod); + if (t == tn) + t = type; + else + { + if (type.ty == Tpointer) + t = t.pointerTo(); + else if (type.ty == Tarray) + t = t.arrayOf(); + else if (type.ty == Tsarray) + t = new TypeSArray(t, (cast(TypeSArray)type).dim.syntaxCopy()); + else if (type.ty == Taarray) + { + t = new TypeAArray(t, (cast(TypeAArray)type).index.syntaxCopy()); + } + else if (type.ty == Tdelegate) + { + t = new TypeDelegate(t.isTypeFunction()); + } + else + assert(0); + + t = t.merge(); + } + } + else + t = type; + + L1: + if (type.isWild()) + { + if (mod == MODFlags.immutable_) + { + t = t.immutableOf(); + } + else if (mod == MODFlags.wildconst) + { + t = t.wildConstOf(); + } + else if (mod == MODFlags.wild) + { + if (type.isWildConst()) + t = t.wildConstOf(); + else + t = t.wildOf(); + } + else if (mod == MODFlags.const_) + { + t = t.constOf(); + } + else + { + if (type.isWildConst()) + t = t.constOf(); + else + t = t.mutableOf(); + } + } + if (type.isConst()) + t = t.addMod(MODFlags.const_); + if (type.isShared()) + t = t.addMod(MODFlags.shared_); + + //printf("-Type.substWildTo t = %s\n", t.toChars()); + return t; + } + + if (!tf.iswild && !(tf.mod & MODFlags.wild)) + return tf; + + // Substitude inout qualifier of function type to mutable or immutable + // would break type system. Instead substitude inout to the most weak + // qualifer - const. + uint m = MODFlags.const_; + + assert(tf.next); + Type tret = tf.next.substWildTo(m); + Parameters* params = tf.parameterList.parameters; + if (tf.mod & MODFlags.wild) + params = tf.parameterList.parameters.copy(); + for (size_t i = 0; i < params.length; i++) + { + Parameter p = (*params)[i]; + Type t = p.type.substWildTo(m); + if (t == p.type) + continue; + if (params == tf.parameterList.parameters) + params = tf.parameterList.parameters.copy(); + (*params)[i] = new Parameter(p.loc, p.storageClass, t, null, null, null); + } + if (tf.next == tret && params == tf.parameterList.parameters) + return tf; + + // Similar to TypeFunction.syntaxCopy; + auto t = new TypeFunction(ParameterList(params, tf.parameterList.varargs), tret, tf.linkage); + t.mod = ((tf.mod & MODFlags.wild) ? (tf.mod & ~MODFlags.wild) | MODFlags.const_ : tf.mod); + t.isnothrow = tf.isnothrow; + t.isnogc = tf.isnogc; + t.purity = tf.purity; + t.isproperty = tf.isproperty; + t.isref = tf.isref; + t.isreturn = tf.isreturn; + t.isreturnscope = tf.isreturnscope; + t.isScopeQual = tf.isScopeQual; + t.isreturninferred = tf.isreturninferred; + t.isscopeinferred = tf.isscopeinferred; + t.isInOutParam = false; + t.isInOutQual = false; + t.trust = tf.trust; + t.fargs = tf.fargs; + t.isctor = tf.isctor; + return t.merge(); +} + /************************************ * Add MODxxxx bits to existing type. * We're adding, not replacing, so adding const to @@ -6633,6 +6885,69 @@ Type addMod(Type type, MOD mod) return t; } +/** + * Check whether this type has endless `alias this` recursion. + * + * Params: + * t = type to check whether it has a recursive alias this + * Returns: + * `true` if `t` has an `alias this` that can be implicitly + * converted back to `t` itself. + */ +private bool checkAliasThisRec(Type t) +{ + Type tb = t.toBasetype(); + AliasThisRec* pflag; + if (tb.ty == Tstruct) + pflag = &(cast(TypeStruct)tb).att; + else if (tb.ty == Tclass) + pflag = &(cast(TypeClass)tb).att; + else + return false; + + AliasThisRec flag = cast(AliasThisRec)(*pflag & AliasThisRec.typeMask); + if (flag == AliasThisRec.fwdref) + { + Type att = aliasthisOf(t); + flag = att && att.implicitConvTo(t) ? AliasThisRec.yes : AliasThisRec.no; + } + *pflag = cast(AliasThisRec)(flag | (*pflag & ~AliasThisRec.typeMask)); + return flag == AliasThisRec.yes; +} + +/************************************** + * Check and set 'att' if 't' is a recursive 'alias this' type + * + * The goal is to prevent endless loops when there is a cycle in the alias this chain. + * Since there is no multiple `alias this`, the chain either ends in a leaf, + * or it loops back on itself as some point. + * + * Example: S0 -> (S1 -> S2 -> S3 -> S1) + * + * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried. + * `S1` is a recursive alias this type, but since `att` is initialized to `null`, + * this still returns `false`, but `att1` is set to `S1`. + * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again, + * we notice `att == t`, so we're back at the start of the loop, and this returns `true`. + * + * Params: + * att = type reference used to detect recursion. Should be initialized to `null`. + * t = type of 'alias this' rewrite to attempt + * + * Returns: + * `false` if the rewrite is safe, `true` if it would loop back around + */ +bool isRecursiveAliasThis(ref Type att, Type t) +{ + //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars()); + auto tb = t.toBasetype(); + if (att && tb.equivalent(att)) + return true; + else if (!att && tb.checkAliasThisRec()) + att = tb; + return false; +} + /******************************* Private *****************************************/ private: diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 7fbabbe..d055e0b 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -464,7 +464,7 @@ public: else { /* Use _adEq2() to compare each element. */ - Type *t1array = t1elem->arrayOf (); + Type *t1array = dmd::arrayOf (t1elem); tree result = build_libcall (LIBCALL_ADEQ2, e->type, 3, d_array_convert (e->e1), d_array_convert (e->e2), @@ -2172,7 +2172,8 @@ public: { /* Generate a slice for non-zero initialized aggregates, otherwise create an empty array. */ - gcc_assert (e->type == dmd::constOf (Type::tvoid->arrayOf ())); + gcc_assert (e->type->isConst () + && e->type->nextOf ()->ty == TY::Tvoid); tree type = build_ctype (e->type); tree length = size_int (sd->dsym->structsize); @@ -2571,7 +2572,7 @@ public: /* Implicitly convert void[n] to ubyte[n]. */ if (tb->ty == TY::Tsarray && tb->nextOf ()->toBasetype ()->ty == TY::Tvoid) - tb = Type::tuns8->sarrayOf (tb->isTypeSArray ()->dim->toUInteger ()); + tb = dmd::sarrayOf (Type::tuns8, tb->isTypeSArray ()->dim->toUInteger ()); gcc_assert (tb->ty == TY::Tarray || tb->ty == TY::Tsarray || tb->ty == TY::Tpointer); @@ -2685,7 +2686,7 @@ public: /* Allocate space on the memory managed heap. */ tree mem = build_libcall (LIBCALL_ARRAYLITERALTX, dmd::pointerTo (etype), 2, - build_typeinfo (e, etype->arrayOf ()), + build_typeinfo (e, dmd::arrayOf (etype)), size_int (e->elements->length)); mem = d_save_expr (mem); @@ -2732,20 +2733,20 @@ public: /* Build an expression that assigns all expressions in KEYS to a constructor. */ - tree akeys = build_array_from_exprs (ta->index->sarrayOf (e->keys->length), - e->keys, this->constp_); + Type *tkarray = dmd::sarrayOf (ta->index, e->keys->length); + tree akeys = build_array_from_exprs (tkarray, e->keys, this->constp_); tree init = stabilize_expr (&akeys); /* Do the same with all expressions in VALUES. */ - tree avals = build_array_from_exprs (ta->next->sarrayOf (e->values->length), - e->values, this->constp_); + Type *tvarray = dmd::sarrayOf (ta->next, e->values->length); + tree avals = build_array_from_exprs (tvarray, e->values, this->constp_); init = compound_expr (init, stabilize_expr (&avals)); /* Generate: _d_assocarrayliteralTX (ti, keys, vals); */ - tree keys = d_array_value (build_ctype (ta->index->arrayOf ()), + tree keys = d_array_value (build_ctype (dmd::arrayOf (ta->index)), size_int (e->keys->length), build_address (akeys)); - tree vals = d_array_value (build_ctype (ta->next->arrayOf ()), + tree vals = d_array_value (build_ctype (dmd::arrayOf (ta->next)), size_int (e->values->length), build_address (avals)); diff --git a/gcc/d/intrinsics.cc b/gcc/d/intrinsics.cc index 8bbcdc1..c895c1a 100644 --- a/gcc/d/intrinsics.cc +++ b/gcc/d/intrinsics.cc @@ -274,7 +274,7 @@ build_shuffle_mask_type (tree type) gcc_assert (t != NULL); unsigned HOST_WIDE_INT nunits = TYPE_VECTOR_SUBPARTS (type).to_constant (); - return build_ctype (TypeVector::create (t->sarrayOf (nunits))); + return build_ctype (TypeVector::create (dmd::sarrayOf (t, nunits))); } /* Checks if call to intrinsic FUNCTION in CALLEXP matches the internal @@ -414,7 +414,7 @@ maybe_warn_intrinsic_mismatch (tree function, tree callexp) break; Type *inner = build_frontend_type (TREE_TYPE (vec0)); - Type *vector = TypeVector::create (inner->sarrayOf (nunits)); + Type *vector = TypeVector::create (dmd::sarrayOf (inner, nunits)); return warn_mismatched_argument (callexp, 1, build_ctype (vector), true); } @@ -479,7 +479,7 @@ maybe_warn_intrinsic_mismatch (tree function, tree callexp) break; Type *inner = build_frontend_type (TREE_TYPE (arg)); - Type *vector = TypeVector::create (inner->sarrayOf (nunits)); + Type *vector = TypeVector::create (dmd::sarrayOf (inner, nunits)); return warn_mismatched_argument (callexp, 0, build_ctype (vector), true); } diff --git a/gcc/d/runtime.cc b/gcc/d/runtime.cc index e5988c7..8a64c52 100644 --- a/gcc/d/runtime.cc +++ b/gcc/d/runtime.cc @@ -158,31 +158,31 @@ get_libcall_type (d_libcall_type type) break; case LCT_ARRAY_VOID: - libcall_types[type] = Type::tvoid->arrayOf (); + libcall_types[type] = dmd::arrayOf (Type::tvoid); break; case LCT_ARRAY_SIZE_T: - libcall_types[type] = Type::tsize_t->arrayOf (); + libcall_types[type] = dmd::arrayOf (Type::tsize_t); break; case LCT_ARRAY_BYTE: - libcall_types[type] = Type::tint8->arrayOf (); + libcall_types[type] = dmd::arrayOf (Type::tint8); break; case LCT_ARRAY_STRING: - libcall_types[type] = Type::tstring->arrayOf (); + libcall_types[type] = dmd::arrayOf (Type::tstring); break; case LCT_ARRAY_WSTRING: - libcall_types[type] = Type::twstring->arrayOf (); + libcall_types[type] = dmd::arrayOf (Type::twstring); break; case LCT_ARRAY_DSTRING: - libcall_types[type] = Type::tdstring->arrayOf (); + libcall_types[type] = dmd::arrayOf (Type::tdstring); break; case LCT_ARRAYARRAY_BYTE: - libcall_types[type] = Type::tint8->arrayOf ()->arrayOf (); + libcall_types[type] = dmd::arrayOf (Type::tint8); break; case LCT_POINTER_ASSOCARRAY: @@ -190,15 +190,15 @@ get_libcall_type (d_libcall_type type) break; case LCT_POINTER_VOIDPTR: - libcall_types[type] = Type::tvoidptr->arrayOf (); + libcall_types[type] = dmd::arrayOf (Type::tvoidptr); break; case LCT_ARRAYPTR_VOID: - libcall_types[type] = dmd::pointerTo (Type::tvoid->arrayOf ()); + libcall_types[type] = dmd::pointerTo (dmd::arrayOf (Type::tvoid)); break; case LCT_ARRAYPTR_BYTE: - libcall_types[type] = dmd::pointerTo (Type::tint8->arrayOf ()); + libcall_types[type] = dmd::pointerTo (dmd::arrayOf (Type::tint8)); break; case LCT_IMMUTABLE_CHARPTR: diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc index 794737b..cadcbe8 100644 --- a/gcc/d/typeinfo.cc +++ b/gcc/d/typeinfo.cc @@ -415,7 +415,7 @@ class TypeInfoVisitor : public Visitor tree decl = this->internal_reference (value); TREE_READONLY (decl) = 1; - value = d_array_value (build_ctype (Type::tchar->arrayOf ()), + value = d_array_value (build_ctype (dmd::arrayOf (Type::tchar)), size_int (len), build_address (decl)); this->layout_field (value); } @@ -1137,7 +1137,7 @@ public: this->layout_base (Type::typeinfotypelist); /* TypeInfo[] elements; */ - Type *satype = Type::tvoidptr->sarrayOf (ti->arguments->length); + Type *satype = dmd::sarrayOf (Type::tvoidptr, ti->arguments->length); vec<constructor_elt, va_gc> *elms = NULL; for (size_t i = 0; i < ti->arguments->length; i++) { diff --git a/gcc/testsuite/gdc.test/compilable/issue24399.d b/gcc/testsuite/gdc.test/compilable/issue24399.d new file mode 100644 index 0000000..ae3e744 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/issue24399.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -main +// LINK: +template rt_options() +{ + __gshared string[] rt_options = []; + string[] rt_options_tls = []; +} + +alias _ = rt_options!(); diff --git a/gcc/testsuite/gdc.test/compilable/issue24409.d b/gcc/testsuite/gdc.test/compilable/issue24409.d new file mode 100644 index 0000000..5d298df --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/issue24409.d @@ -0,0 +1,17 @@ +static struct S +{ + union + { + int i; + long l; + } +} + +int f() +{ + S* r = new S(); + r.i = 5; + return r.i; +} + +enum X = f(); diff --git a/gcc/testsuite/gdc.test/runnable/issue24401.d b/gcc/testsuite/gdc.test/runnable/issue24401.d new file mode 100644 index 0000000..109d543 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/issue24401.d @@ -0,0 +1,6 @@ +// PERMUTE_ARGS: +// https://issues.dlang.org/show_bug.cgi?id=24401 +int main() +{ + return (() @trusted => 0)(); +} diff --git a/gcc/testsuite/gdc.test/runnable/test24371.d b/gcc/testsuite/gdc.test/runnable/test24371.d new file mode 100644 index 0000000..885f9b8 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test24371.d @@ -0,0 +1,15 @@ +// https://issues.dlang.org/show_bug.cgi?id=24371 + +void main() +{ + assert("b" ~ "c" == "bc"); + assert(["a"] ~ "b" == ["a", "b"]); + assert(["a"] ~ ("b" ~ "c") == ["a", "bc"]); + + auto strArr = ["a"]; + assert(strArr ~ ("b" ~ "c") == ["a", "bc"]); + auto str = "c"; + assert(["a"] ~ ("b" ~ str) == ["a", "bc"]); + + assert(strArr ~ ("b" ~ str) == ["a", "bc"]); +} diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test7925.d b/gcc/testsuite/gdc.test/runnable_cxx/test7925.d index f05aac9..2d0b023 100644 --- a/gcc/testsuite/gdc.test/runnable_cxx/test7925.d +++ b/gcc/testsuite/gdc.test/runnable_cxx/test7925.d @@ -1,12 +1,5 @@ // EXTRA_CPP_SOURCES: cpp7925.cpp -/* -Exclude -O/-inline due to a codegen bug on OSX: -https://issues.dlang.org/show_bug.cgi?id=22556 - -PERMUTE_ARGS(osx): -release -g -*/ - import core.vararg; extern(C++) class C1 |