aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2024-03-03 20:28:58 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2024-03-03 23:42:56 +0100
commitbbfbaa792b50ebd75b383be25f50c92f30243256 (patch)
tree745acbaba5cd3643e8e3ed9797a4ca258d2ae1d8 /gcc
parent24975a9195743e8eb4ca213f35b9221d4eeb6b59 (diff)
downloadgcc-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')
-rw-r--r--gcc/d/d-builtins.cc6
-rw-r--r--gcc/d/d-codegen.cc2
-rw-r--r--gcc/d/d-convert.cc4
-rw-r--r--gcc/d/decl.cc2
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/VERSION2
-rw-r--r--gcc/d/dmd/constfold.d2
-rw-r--r--gcc/d/dmd/cparse.d8
-rw-r--r--gcc/d/dmd/cxxfrontend.d36
-rw-r--r--gcc/d/dmd/denum.d1
-rw-r--r--gcc/d/dmd/dinterpret.d4
-rw-r--r--gcc/d/dmd/dmodule.d16
-rw-r--r--gcc/d/dmd/expressionsem.d14
-rw-r--r--gcc/d/dmd/func.d176
-rw-r--r--gcc/d/dmd/funcsem.d168
-rw-r--r--gcc/d/dmd/location.d10
-rw-r--r--gcc/d/dmd/mtype.d321
-rw-r--r--gcc/d/dmd/mtype.h14
-rw-r--r--gcc/d/dmd/optimize.d2
-rw-r--r--gcc/d/dmd/safe.d2
-rw-r--r--gcc/d/dmd/typesem.d317
-rw-r--r--gcc/d/expr.cc21
-rw-r--r--gcc/d/intrinsics.cc6
-rw-r--r--gcc/d/runtime.cc20
-rw-r--r--gcc/d/typeinfo.cc4
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue24399.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue24409.d17
-rw-r--r--gcc/testsuite/gdc.test/runnable/issue24401.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/test24371.d15
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/test7925.d7
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