aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2023-11-02 13:24:07 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2023-11-02 14:54:13 +0100
commit04802ed3b94bdc3083547ac08bca71764a004d01 (patch)
tree2d492f8013b9bdb4af409c973fdd3990ab34dd31 /gcc/d/dmd
parent8a4cde6319b40802a842a8fe71267524dd8af828 (diff)
downloadgcc-04802ed3b94bdc3083547ac08bca71764a004d01.zip
gcc-04802ed3b94bdc3083547ac08bca71764a004d01.tar.gz
gcc-04802ed3b94bdc3083547ac08bca71764a004d01.tar.bz2
d: Merge upstream dmd, druntime 643b1261bb, phobos 1c98326e7
D front-end changes: - Suggested preview switches now give gdc flags (PR109681). - `new S[10]' is now lowered to `_d_newarrayT!S(10)'. D runtime changes: - Runtime compiler library functions `_d_newarrayU', `_d_newarrayT', `_d_newarrayiT' have been converted to templates. Phobos changes: - Add new `std.traits.Unshared' template. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 643b1261bb. * d-attribs.cc (build_attributes): Update for new front-end interface. * d-lang.cc (d_post_options): Likewise. * decl.cc (layout_class_initializer): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 643b1261bb. * libdruntime/Makefile.am (DRUNTIME_DSOURCES_FREEBSD): Add core/sys/freebsd/ifaddrs.d, core/sys/freebsd/net/if_dl.d, core/sys/freebsd/sys/socket.d, core/sys/freebsd/sys/types.d. (DRUNTIME_DSOURCES_LINUX): Add core/sys/linux/linux/if_arp.d, core/sys/linux/linux/if_packet.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 1c98326e7.
Diffstat (limited to 'gcc/d/dmd')
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/aggregate.d184
-rw-r--r--gcc/d/dmd/attrib.d6
-rw-r--r--gcc/d/dmd/cond.d1
-rw-r--r--gcc/d/dmd/constfold.d24
-rw-r--r--gcc/d/dmd/cparse.d1
-rw-r--r--gcc/d/dmd/dcast.d3
-rw-r--r--gcc/d/dmd/dclass.d2
-rw-r--r--gcc/d/dmd/declaration.d50
-rw-r--r--gcc/d/dmd/dinterpret.d3
-rw-r--r--gcc/d/dmd/dmangle.d1
-rw-r--r--gcc/d/dmd/doc.d2
-rw-r--r--gcc/d/dmd/dstruct.d2
-rw-r--r--gcc/d/dmd/dsymbol.d74
-rw-r--r--gcc/d/dmd/dsymbolsem.d11
-rw-r--r--gcc/d/dmd/dtemplate.d15
-rw-r--r--gcc/d/dmd/expression.d546
-rw-r--r--gcc/d/dmd/expression.h20
-rw-r--r--gcc/d/dmd/expressionsem.d511
-rw-r--r--gcc/d/dmd/func.d1
-rw-r--r--gcc/d/dmd/globals.h1
-rw-r--r--gcc/d/dmd/gluelayer.d5
-rw-r--r--gcc/d/dmd/initsem.d1
-rw-r--r--gcc/d/dmd/lexer.d1
-rw-r--r--gcc/d/dmd/mtype.d25
-rw-r--r--gcc/d/dmd/mtype.h2
-rw-r--r--gcc/d/dmd/optimize.d1
-rw-r--r--gcc/d/dmd/parse.d22
-rw-r--r--gcc/d/dmd/semantic3.d7
-rw-r--r--gcc/d/dmd/statementsem.d5
-rw-r--r--gcc/d/dmd/staticcond.d1
-rw-r--r--gcc/d/dmd/templateparamsem.d1
-rw-r--r--gcc/d/dmd/traits.d1
-rw-r--r--gcc/d/dmd/typesem.d2
-rw-r--r--gcc/d/dmd/typinf.d30
-rw-r--r--gcc/d/dmd/typinf.h22
36 files changed, 830 insertions, 756 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 2a0baf0..235db4b 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-e48bc0987dfec35bc76a3015ee3e85906ce86dfd
+643b1261bba0757d97efa3ff1f63e461271eb000
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/aggregate.d b/gcc/d/dmd/aggregate.d
index d9b48b5..d42ef951 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -501,90 +501,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
return !errors;
}
- /****************************
- * Do byte or word alignment as necessary.
- * Align sizes of 0, as we may not know array sizes yet.
- * Params:
- * alignment = struct alignment that is in effect
- * memalignsize = natural alignment of field
- * poffset = pointer to offset to be aligned
- */
- extern (D) static void alignmember(structalign_t alignment, uint memalignsize, uint* poffset) pure nothrow @safe
- {
- //debug printf("alignment = %u %d, size = %u, offset = %u\n", alignment.get(), alignment.isPack(), memalignsize, *poffset);
- uint alignvalue;
-
- if (alignment.isDefault())
- {
- // Alignment in Target::fieldalignsize must match what the
- // corresponding C compiler's default alignment behavior is.
- alignvalue = memalignsize;
- }
- else if (alignment.isPack()) // #pragma pack semantics
- {
- alignvalue = alignment.get();
- if (memalignsize < alignvalue)
- alignvalue = memalignsize; // align to min(memalignsize, alignment)
- }
- else if (alignment.get() > 1)
- {
- // Align on alignment boundary, which must be a positive power of 2
- alignvalue = alignment.get();
- }
- else
- return;
-
- assert(alignvalue > 0 && !(alignvalue & (alignvalue - 1)));
- *poffset = (*poffset + alignvalue - 1) & ~(alignvalue - 1);
- }
-
- /****************************************
- * Place a field (mem) into an aggregate (agg), which can be a struct, union or class
- * Params:
- * nextoffset = location just past the end of the previous field in the aggregate.
- * Updated to be just past the end of this field to be placed, i.e. the future nextoffset
- * memsize = size of field
- * memalignsize = natural alignment of field
- * alignment = alignment in effect for this field
- * paggsize = size of aggregate (updated)
- * paggalignsize = alignment of aggregate (updated)
- * isunion = the aggregate is a union
- * Returns:
- * aligned offset to place field at
- *
- */
- extern (D) static uint placeField(uint* nextoffset, uint memsize, uint memalignsize,
- structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion)
- {
- uint ofs = *nextoffset;
-
- const uint actualAlignment =
- alignment.isDefault() || alignment.isPack() && memalignsize < alignment.get()
- ? memalignsize : alignment.get();
-
- // Ensure no overflow
- bool overflow;
- const sz = addu(memsize, actualAlignment, overflow);
- addu(ofs, sz, overflow);
- if (overflow) assert(0);
-
- // Skip no-op for noreturn without custom aligment
- if (memalignsize != 0 || !alignment.isDefault())
- alignmember(alignment, memalignsize, &ofs);
-
- uint memoffset = ofs;
- ofs += memsize;
- if (ofs > *paggsize)
- *paggsize = ofs;
- if (!isunion)
- *nextoffset = ofs;
-
- if (*paggalignsize < actualAlignment)
- *paggalignsize = actualAlignment;
-
- return memoffset;
- }
-
override final Type getType()
{
/* Apply storage classes to forward references. (Issue 22254)
@@ -844,3 +760,103 @@ int apply(Dsymbol symbol, int function(Dsymbol, void*) fp, void* ctx)
return fp(symbol, ctx);
}
+
+/****************************
+ * Do byte or word alignment as necessary.
+ * Align sizes of 0, as we may not know array sizes yet.
+ * Params:
+ * alignment = struct alignment that is in effect
+ * memalignsize = natural alignment of field
+ * offset = offset to be aligned
+ * Returns:
+ * aligned offset
+ */
+public uint alignmember(structalign_t alignment, uint memalignsize, uint offset) pure nothrow @safe
+{
+ //debug printf("alignment = %u %d, size = %u, offset = %u\n", alignment.get(), alignment.isPack(), memalignsize, offset);
+ uint alignvalue;
+
+ if (alignment.isDefault())
+ {
+ // Alignment in Target::fieldalignsize must match what the
+ // corresponding C compiler's default alignment behavior is.
+ alignvalue = memalignsize;
+ }
+ else if (alignment.isPack()) // #pragma pack semantics
+ {
+ alignvalue = alignment.get();
+ if (memalignsize < alignvalue)
+ alignvalue = memalignsize; // align to min(memalignsize, alignment)
+ }
+ else if (alignment.get() > 1)
+ {
+ // Align on alignment boundary, which must be a positive power of 2
+ alignvalue = alignment.get();
+ }
+ else
+ return offset;
+
+ assert(alignvalue && !(alignvalue & (alignvalue - 1))); // non-zero and power of 2
+ return (offset + alignvalue - 1) & ~(alignvalue - 1);
+}
+
+/****************************************
+ * Place a field (mem) into an aggregate (agg), which can be a struct, union or class
+ * Params:
+ * nextoffset = location just past the end of the previous field in the aggregate.
+ * Updated to be just past the end of this field to be placed, i.e. the future nextoffset
+ * memsize = size of field
+ * memalignsize = natural alignment of field
+ * alignment = alignment in effect for this field
+ * aggsize = size of aggregate (updated)
+ * aggalignsize = alignment of aggregate (updated)
+ * isunion = the aggregate is a union
+ * Returns:
+ * aligned offset to place field at
+ *
+ */
+public uint placeField(ref uint nextoffset, uint memsize, uint memalignsize,
+ structalign_t alignment, ref uint aggsize, ref uint aggalignsize, bool isunion) @safe pure nothrow
+{
+ static if (0)
+ {
+ printf("placeField() nextoffset: %u\n", nextoffset);
+ printf(": memsize: %u\n", memsize);
+ printf(": memalignsize: %u\n", memalignsize);
+ printf(": alignment: %u\n", alignment.get());
+ printf(": aggsize: %u\n", aggsize);
+ printf(": aggalignsize: %u\n", aggalignsize);
+ printf(": isunion: %d\n", isunion);
+ }
+
+ uint ofs = nextoffset;
+
+ const uint actualAlignment =
+ alignment.isDefault() || alignment.isPack() && memalignsize < alignment.get()
+ ? memalignsize : alignment.get();
+
+ // Ensure no overflow for (memsize + actualAlignment + ofs)
+ bool overflow;
+ const sz = addu(memsize, actualAlignment, overflow);
+ addu(ofs, sz, overflow);
+ if (overflow) assert(0);
+
+ // Skip no-op for noreturn without custom aligment
+ if (memalignsize != 0 || !alignment.isDefault())
+ ofs = alignmember(alignment, memalignsize, ofs);
+
+ uint memoffset = ofs;
+ ofs += memsize;
+ if (ofs > aggsize)
+ aggsize = ofs;
+ if (!isunion)
+ {
+ nextoffset = ofs;
+ //printf(" revised nextoffset: %u\n", ofs);
+ }
+
+ if (aggalignsize < actualAlignment)
+ aggalignsize = actualAlignment;
+
+ return memoffset;
+}
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index 7b5def1..49fc308 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -839,10 +839,10 @@ extern (C++) final class AnonDeclaration : AttribDeclaration
/* Given the anon 'member's size and alignment,
* go ahead and place it.
*/
- anonoffset = AggregateDeclaration.placeField(
- &fieldState.offset,
+ anonoffset = placeField(
+ fieldState.offset,
anonstructsize, anonalignsize, alignment,
- &ad.structsize, &ad.alignsize,
+ ad.structsize, ad.alignsize,
isunion);
// Add to the anon fields the base offset of this anonymous aggregate
diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d
index 9fa8a25..a8d0994 100644
--- a/gcc/d/dmd/cond.d
+++ b/gcc/d/dmd/cond.d
@@ -18,6 +18,7 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
import dmd.dcast;
+import dmd.dinterpret;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index ef408cb..fc3fd3b 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -20,6 +20,7 @@ import core.stdc.stdio;
import dmd.arraytypes;
import dmd.astenums;
import dmd.ctfeexpr;
+import dmd.dcast;
import dmd.declaration;
import dmd.dstruct;
import dmd.errors;
@@ -48,29 +49,6 @@ private Expression expType(Type type, Expression e)
return e;
}
-/************************************
- * Returns:
- * true if e is a constant
- */
-int isConst(Expression e) @safe
-{
- //printf("Expression::isConst(): %s\n", e.toChars());
- switch (e.op)
- {
- case EXP.int64:
- case EXP.float64:
- case EXP.complex80:
- return 1;
- case EXP.null_:
- return 0;
- case EXP.symbolOffset:
- return 2;
- default:
- return 0;
- }
- assert(0);
-}
-
/**********************************
* Initialize a EXP.cantExpression Expression.
* Params:
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index 0b738cd..b8e8052 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -328,6 +328,7 @@ final class CParser(AST) : Parser!AST
case TOK._Atomic:
case TOK.__attribute__:
+ case TOK.__declspec:
Ldeclaration:
{
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index e4d5805..f769473 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -20,6 +20,7 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.dclass;
import dmd.declaration;
+import dmd.dinterpret;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
@@ -232,7 +233,7 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t)
* Returns:
* The `MATCH` level between `e.type` and `t`.
*/
-MATCH implicitConvTo(Expression e, Type t)
+extern(C++) MATCH implicitConvTo(Expression e, Type t)
{
MATCH visit(Expression e)
{
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index 09a4f4e..bae942c 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -613,7 +613,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
if (!b.sym.alignsize)
b.sym.alignsize = target.ptrsize;
- alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, &offset);
+ offset = alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, offset);
assert(bi < vtblInterfaces.length);
BaseClass* bv = (*vtblInterfaces)[bi];
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index d634e7f..76a31f4 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -818,6 +818,11 @@ extern (C++) final class AliasDeclaration : Declaration
return this._import && this.equals(s);
}
+ // https://issues.dlang.org/show_bug.cgi?id=23865
+ // only insert if the symbol can be part of a set
+ const s1 = s.toAlias();
+ const isInsertCandidate = s1.isFuncDeclaration() || s1.isOverDeclaration() || s1.isTemplateDeclaration();
+
/* When s is added in member scope by static if, mixin("code") or others,
* aliassym is determined already. See the case in: test/compilable/test61.d
*/
@@ -832,7 +837,8 @@ extern (C++) final class AliasDeclaration : Declaration
fa.visibility = visibility;
fa.parent = parent;
aliassym = fa;
- return aliassym.overloadInsert(s);
+ if (isInsertCandidate)
+ return aliassym.overloadInsert(s);
}
if (auto td = sa.isTemplateDeclaration())
{
@@ -840,7 +846,8 @@ extern (C++) final class AliasDeclaration : Declaration
od.visibility = visibility;
od.parent = parent;
aliassym = od;
- return aliassym.overloadInsert(s);
+ if (isInsertCandidate)
+ return aliassym.overloadInsert(s);
}
if (auto od = sa.isOverDeclaration())
{
@@ -851,7 +858,8 @@ extern (C++) final class AliasDeclaration : Declaration
od.parent = parent;
aliassym = od;
}
- return od.overloadInsert(s);
+ if (isInsertCandidate)
+ return od.overloadInsert(s);
}
if (auto os = sa.isOverloadSet())
{
@@ -877,8 +885,11 @@ extern (C++) final class AliasDeclaration : Declaration
os.parent = parent;
aliassym = os;
}
- os.push(s);
- return true;
+ if (isInsertCandidate)
+ {
+ os.push(s);
+ return true;
+ }
}
return false;
}
@@ -1287,10 +1298,10 @@ extern (C++) class VarDeclaration : Declaration
assert(sz != SIZE_INVALID && sz < uint.max);
uint memsize = cast(uint)sz; // size of member
uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
- offset = AggregateDeclaration.placeField(
- &fieldState.offset,
+ offset = placeField(
+ fieldState.offset,
memsize, memalignsize, alignment,
- &ad.structsize, &ad.alignsize,
+ ad.structsize, ad.alignsize,
isunion);
//printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
@@ -1813,11 +1824,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars());
void print(const ref FieldState fieldState)
{
- printf("FieldState.offset = %d bytes\n", fieldState.offset);
- printf(" .fieldOffset = %d bytes\n", fieldState.fieldOffset);
- printf(" .bitOffset = %d bits\n", fieldState.bitOffset);
- printf(" .fieldSize = %d bytes\n", fieldState.fieldSize);
- printf(" .inFlight = %d\n", fieldState.inFlight);
+ fieldState.print();
printf(" fieldWidth = %d bits\n", fieldWidth);
}
print(fieldState);
@@ -1866,11 +1873,11 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
alignsize = memsize; // not memalignsize
uint dummy;
- offset = AggregateDeclaration.placeField(
- &fieldState.offset,
+ offset = placeField(
+ fieldState.offset,
memsize, alignsize, alignment,
- &ad.structsize,
- (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? &dummy : &ad.alignsize,
+ ad.structsize,
+ (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize,
isunion);
fieldState.inFlight = true;
@@ -1989,7 +1996,14 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
auto size = (pastField + 7) / 8;
fieldState.fieldSize = size;
//printf(" offset: %d, size: %d\n", offset, size);
- ad.structsize = offset + size;
+ if (isunion)
+ {
+ const newstructsize = offset + size;
+ if (newstructsize > ad.structsize)
+ ad.structsize = newstructsize;
+ }
+ else
+ ad.structsize = offset + size;
}
else
fieldState.fieldSize = memsize;
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index cbd9740..90352e3 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -22,6 +22,7 @@ import dmd.attrib;
import dmd.builtin;
import dmd.constfold;
import dmd.ctfeexpr;
+import dmd.dcast;
import dmd.dclass;
import dmd.declaration;
import dmd.dstruct;
@@ -59,7 +60,7 @@ import dmd.visitor;
* functions and may invoke a function that contains `ErrorStatement` in its body.
* If that, the "CTFE failed because of previous errors" error is raised.
*/
-public Expression ctfeInterpret(Expression e)
+extern(C++) public Expression ctfeInterpret(Expression e)
{
switch (e.op)
{
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d
index 8fdb1ae..c58b585 100644
--- a/gcc/d/dmd/dmangle.d
+++ b/gcc/d/dmd/dmangle.d
@@ -139,6 +139,7 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.dclass;
import dmd.declaration;
+import dmd.dinterpret;
import dmd.dmodule;
import dmd.dsymbol;
import dmd.dtemplate;
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index b1a4c2f..5488d5a 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -438,7 +438,7 @@ void gendocfile(Module m, const char[] ddoctext, const char* datetime, ErrorSink
if (!loc.filename)
loc.filename = srcfilename.ptr;
- size_t commentlen = strlen(cast(char*)m.comment);
+ size_t commentlen = m.comment ? strlen(cast(char*)m.comment) : 0;
Dsymbols a;
// https://issues.dlang.org/show_bug.cgi?id=9764
// Don't push m in a, to prevent emphasize ddoc file name.
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 5171e1f..f77a263 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -357,7 +357,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
sizeok = Sizeok.done;
- //printf("-StructDeclaration::finalizeSize() %s, fields.length = %d, structsize = %d\n", toChars(), fields.length, structsize);
+ //printf("-StructDeclaration::finalizeSize() %s, fields.length = %d, structsize = %d\n", toChars(), cast(int)fields.length, cast(int)structsize);
if (errors)
return;
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 579a542..914213c 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -56,6 +56,8 @@ import dmd.staticassert;
import dmd.tokens;
import dmd.visitor;
+import dmd.common.outbuffer;
+
/***************************************
* Calls dg(Dsymbol *sym) for each Dsymbol.
* If dg returns !=0, stops and returns that value else returns 0.
@@ -236,6 +238,15 @@ struct FieldState
uint bitOffset; /// bit offset for field
bool inFlight; /// bit field is in flight
+
+ void print() const
+ {
+ printf("FieldState.offset = %d bytes\n", offset);
+ printf(" .fieldOffset = %d bytes\n", fieldOffset);
+ printf(" .bitOffset = %d bits\n", bitOffset);
+ printf(" .fieldSize = %d bytes\n", fieldSize);
+ printf(" .inFlight = %d\n", inFlight);
+ }
}
// 99.9% of Dsymbols don't have attributes (at least in druntime and Phobos),
@@ -684,7 +695,7 @@ extern (C++) class Dsymbol : ASTNode
const(char)* toPrettyChars(bool QualifyTypes = false)
{
if (prettystring && !QualifyTypes)
- return prettystring;
+ return prettystring; // value cached for speed
//printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
if (!parent)
@@ -695,42 +706,22 @@ extern (C++) class Dsymbol : ASTNode
return s;
}
- // Computer number of components
- size_t complength = 0;
- for (Dsymbol p = this; p; p = p.parent)
- ++complength;
-
- // Allocate temporary array comp[]
- alias T = const(char)[];
- auto compptr = cast(T*)Mem.check(malloc(complength * T.sizeof));
- auto comp = compptr[0 .. complength];
+ OutBuffer buf;
- // Fill in comp[] and compute length of final result
- size_t length = 0;
- int i;
- for (Dsymbol p = this; p; p = p.parent)
+ void addQualifiers(Dsymbol p)
{
+ if (p.parent)
+ {
+ addQualifiers(p.parent);
+ buf.writeByte('.');
+ }
const s = QualifyTypes ? p.toPrettyCharsHelper() : p.toChars();
- const len = strlen(s);
- comp[i] = s[0 .. len];
- ++i;
- length += len + 1;
+ buf.writestring(s);
}
- auto s = cast(char*)mem.xmalloc_noscan(length);
- auto q = s + length - 1;
- *q = 0;
- foreach (j; 0 .. complength)
- {
- const t = comp[j].ptr;
- const len = comp[j].length;
- q -= len;
- memcpy(q, t, len);
- if (q == s)
- break;
- *--q = '.';
- }
- free(comp.ptr);
+ addQualifiers(this);
+ auto s = buf.extractSlice(true).ptr;
+
if (!QualifyTypes)
prettystring = s;
return s;
@@ -1734,8 +1725,8 @@ public:
Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null);
parameters.push(p);
Type tret = null;
- tfgetmembers = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
- tfgetmembers = cast(TypeFunction)tfgetmembers.dsymbolSemantic(Loc.initial, &sc);
+ TypeFunction tf = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
+ tfgetmembers = tf.dsymbolSemantic(Loc.initial, &sc).isTypeFunction();
}
if (fdx)
fdx = fdx.overloadExactMatch(tfgetmembers);
@@ -1863,11 +1854,11 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol
Expression eold = null;
for (Expression e = withstate.exp; e && e != eold; e = resolveAliasThis(_scope, e, true))
{
- if (e.op == EXP.scope_)
+ if (auto se = e.isScopeExp())
{
- s = (cast(ScopeExp)e).sds;
+ s = se.sds;
}
- else if (e.op == EXP.type)
+ else if (e.isTypeExp())
{
s = e.type.toDsymbol(null);
}
@@ -2041,11 +2032,11 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
if (TemplateDeclaration td = s.isTemplateDeclaration())
{
dinteger_t dim = 0;
- if (exp.op == EXP.array)
+ if (auto ae = exp.isArrayExp())
{
- dim = (cast(ArrayExp)exp).currentDimension;
+ dim = ae.currentDimension;
}
- else if (exp.op == EXP.slice)
+ else if (exp.isSliceExp())
{
dim = 0; // slices are currently always one-dimensional
}
@@ -2066,7 +2057,8 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
* Note that it's impossible to have both template & function opDollar,
* because both take no arguments.
*/
- if (exp.op == EXP.array && (cast(ArrayExp)exp).arguments.length != 1)
+ auto ae = exp.isArrayExp();
+ if (ae && ae.arguments.length != 1)
{
error(exp.loc, "`%s` only defines opDollar for one dimension", ad.toChars());
return null;
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 8309e4a..397c5e5 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -1320,7 +1320,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
return;
if (!(global.params.bitfields || sc.flags & SCOPE.Cfile))
- .error(dsym.loc, "%s `%s` use -preview=bitfields for bitfield support", dsym.kind, dsym.toPrettyChars);
+ {
+ version (IN_GCC)
+ .error(dsym.loc, "%s `%s` use `-fpreview=bitfields` for bitfield support", dsym.kind, dsym.toPrettyChars);
+ else
+ .error(dsym.loc, "%s `%s` use -preview=bitfields for bitfield support", dsym.kind, dsym.toPrettyChars);
+ }
if (!dsym.parent.isStructDeclaration() && !dsym.parent.isClassDeclaration())
{
@@ -1390,7 +1395,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// if parser errors occur when loading a module
// we should just stop compilation
if (imp.load(sc))
+ {
+ for (size_t i = 0; i < imp.aliasdecls.length; i++)
+ imp.aliasdecls[i].type = Type.terror;
return;
+ }
if (imp.mod)
{
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 5dca6df..883f4ac 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -49,6 +49,7 @@ import dmd.attrib;
import dmd.dcast;
import dmd.dclass;
import dmd.declaration;
+import dmd.dinterpret;
import dmd.dmangle;
import dmd.dmodule;
import dmd.dscope;
@@ -5725,13 +5726,19 @@ extern (C++) final class TemplateAliasParameter : TemplateParameter
override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
{
RootObject da = defaultAlias;
- Type ta = isType(defaultAlias);
- if (ta)
+ if (auto ta = isType(defaultAlias))
{
- if (ta.ty == Tinstance)
+ switch (ta.ty)
{
- // If the default arg is a template, instantiate for each type
+ // If the default arg is a template, instantiate for each type
+ case Tinstance :
+ // same if the default arg is a mixin, traits, typeof
+ // since the content might rely on a previous parameter
+ // (https://issues.dlang.org/show_bug.cgi?id=23686)
+ case Tmixin, Ttypeof, Ttraits :
da = ta.syntaxCopy();
+ break;
+ default:
}
}
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 32ded3b..87611f4 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -24,24 +24,18 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
import dmd.gluelayer;
-import dmd.constfold;
import dmd.ctfeexpr;
import dmd.ctorflow;
-import dmd.dcast;
import dmd.dclass;
import dmd.declaration;
-import dmd.delegatize;
import dmd.dimport;
-import dmd.dinterpret;
import dmd.dmodule;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
-import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.errors;
import dmd.errorsink;
-import dmd.escape;
import dmd.expressionsem;
import dmd.func;
import dmd.globals;
@@ -49,11 +43,8 @@ import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.init;
-import dmd.inline;
import dmd.location;
import dmd.mtype;
-import dmd.nspace;
-import dmd.objc;
import dmd.opover;
import dmd.optimize;
import dmd.root.complex;
@@ -66,10 +57,8 @@ import dmd.rootobject;
import dmd.root.string;
import dmd.root.utf;
import dmd.safe;
-import dmd.sideeffect;
import dmd.target;
import dmd.tokens;
-import dmd.typesem;
import dmd.visitor;
enum LOGSEMANTIC = false;
@@ -745,21 +734,6 @@ extern (C++) abstract class Expression : ASTNode
return toLvalue(sc, e);
}
- extern (D) final Expression implicitCastTo(Scope* sc, Type t)
- {
- return .implicitCastTo(this, sc, t);
- }
-
- final MATCH implicitConvTo(Type t)
- {
- return .implicitConvTo(this, t);
- }
-
- extern (D) final Expression castTo(Scope* sc, Type t)
- {
- return .castTo(this, sc, t);
- }
-
/****************************************
* Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
*/
@@ -1304,16 +1278,6 @@ extern (C++) abstract class Expression : ASTNode
return true;
}
- /************************************************
- * Destructors are attached to VarDeclarations.
- * Hence, if expression returns a temp that needs a destructor,
- * make sure and create a VarDeclaration for that temp.
- */
- Expression addDtorHook(Scope* sc)
- {
- return this;
- }
-
/******************************
* Take address of expression.
*/
@@ -1349,16 +1313,23 @@ extern (C++) abstract class Expression : ASTNode
return Expression_optimize(this, result, keepLvalue);
}
- // Entry point for CTFE.
- // A compile-time result is required. Give an error if not possible
- final Expression ctfeInterpret()
- {
- return .ctfeInterpret(this);
- }
-
final int isConst()
{
- return .isConst(this);
+ //printf("Expression::isConst(): %s\n", e.toChars());
+ switch (op)
+ {
+ case EXP.int64:
+ case EXP.float64:
+ case EXP.complex80:
+ return 1;
+ case EXP.null_:
+ return 0;
+ case EXP.symbolOffset:
+ return 2;
+ default:
+ return 0;
+ }
+ assert(0);
}
/******
@@ -2110,13 +2081,19 @@ extern (C++) class ThisExp : Expression
return typeof(return)(true);
}
- override bool isLvalue()
+ override final bool isLvalue()
{
- return true;
+ // Class `this` should be an rvalue; struct `this` should be an lvalue.
+ return type.toBasetype().ty != Tclass;
}
- override Expression toLvalue(Scope* sc, Expression e)
+ override final Expression toLvalue(Scope* sc, Expression e)
{
+ if (type.toBasetype().ty == Tclass)
+ {
+ // Class `this` is an rvalue; struct `this` is an lvalue.
+ return Expression.toLvalue(sc, e);
+ }
return this;
}
@@ -2136,18 +2113,6 @@ extern (C++) final class SuperExp : ThisExp
super(loc, EXP.super_);
}
- override bool isLvalue()
- {
- // Class `super` should be an rvalue
- return false;
- }
-
- override Expression toLvalue(Scope* sc, Expression e)
- {
- // Class `super` is an rvalue
- return Expression.toLvalue(sc, e);
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -2187,12 +2152,13 @@ extern (C++) final class NullExp : Expression
override StringExp toStringExp()
{
- if (implicitConvTo(Type.tstring))
+ if (this.type.implicitConvTo(Type.tstring))
{
auto se = new StringExp(loc, (cast(char*)mem.xcalloc(1, 1))[0 .. 0]);
se.type = Type.tstring;
return se;
}
+
return null;
}
@@ -2417,23 +2383,6 @@ extern (C++) final class StringExp : Expression
return this;
}
- /****************************************
- * Convert string to char[].
- */
- StringExp toUTF8(Scope* sc)
- {
- if (sz != 1)
- {
- // Convert to UTF-8 string
- committed = false;
- Expression e = castTo(sc, Type.tchar.arrayOf());
- e = e.optimize(WANTvalue);
- auto se = e.isStringExp();
- assert(se.sz == 1);
- return se;
- }
- return this;
- }
/**
* Compare two `StringExp` by length, then value
@@ -3101,34 +3050,6 @@ extern (C++) final class StructLiteralExp : Expression
return -1;
}
- override Expression addDtorHook(Scope* sc)
- {
- /* If struct requires a destructor, rewrite as:
- * (S tmp = S()),tmp
- * so that the destructor can be hung on tmp.
- */
- if (sd.dtor && sc.func)
- {
- /* Make an identifier for the temporary of the form:
- * __sl%s%d, where %s is the struct name
- */
- char[10] buf = void;
- const prefix = "__sl";
- const ident = sd.ident.toString;
- const fullLen = prefix.length + ident.length;
- const len = fullLen < buf.length ? fullLen : buf.length;
- buf[0 .. prefix.length] = prefix;
- buf[prefix.length .. len] = ident[0 .. len - prefix.length];
-
- auto tmp = copyToTemp(0, buf[0 .. len], this);
- Expression ae = new DeclarationExp(loc, tmp);
- Expression e = new CommaExp(loc, ae, new VarExp(loc, tmp));
- e = e.expressionSemantic(sc);
- return e;
- }
- return this;
- }
-
override Expression toLvalue(Scope* sc, Expression e)
{
if (sc.flags & SCOPE.Cfile)
@@ -3658,173 +3579,6 @@ extern (C++) final class FuncExp : Expression
return new FuncExp(loc, fd);
}
- extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, ErrorSink eSink)
- {
- MATCH cannotInfer()
- {
- eSink.error(loc, "cannot infer parameter types from `%s`", to.toChars());
- return MATCH.nomatch;
- }
-
- //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
- if (presult)
- *presult = null;
-
- TypeFunction tof = null;
- if (to.ty == Tdelegate)
- {
- if (tok == TOK.function_)
- {
- eSink.error(loc, "cannot match function literal to delegate type `%s`", to.toChars());
- return MATCH.nomatch;
- }
- tof = cast(TypeFunction)to.nextOf();
- }
- else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
- {
- if (tok == TOK.delegate_)
- {
- eSink.error(loc, "cannot match delegate literal to function pointer type `%s`", to.toChars());
- return MATCH.nomatch;
- }
- }
-
- if (td)
- {
- if (!tof)
- {
- return cannotInfer();
- }
-
- // Parameter types inference from 'tof'
- assert(td._scope);
- TypeFunction tf = fd.type.isTypeFunction();
- //printf("\ttof = %s\n", tof.toChars());
- //printf("\ttf = %s\n", tf.toChars());
- const dim = tf.parameterList.length;
-
- if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
- return cannotInfer();
-
- auto tiargs = new Objects();
- tiargs.reserve(td.parameters.length);
-
- foreach (tp; *td.parameters)
- {
- size_t u = 0;
- foreach (i, p; tf.parameterList)
- {
- if (auto ti = p.type.isTypeIdentifier())
- if (ti && ti.ident == tp.ident)
- break;
-
- ++u;
- }
- assert(u < dim);
- Parameter pto = tof.parameterList[u];
- Type t = pto.type;
- if (t.ty == Terror)
- return cannotInfer();
- tf.parameterList[u].storageClass = tof.parameterList[u].storageClass;
- tiargs.push(t);
- }
-
- // Set target of return type inference
- if (!tf.next && tof.next)
- fd.treq = to;
-
- auto ti = new TemplateInstance(loc, td, tiargs);
- Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
-
- // Reset inference target for the later re-semantic
- fd.treq = null;
-
- if (ex.op == EXP.error)
- return MATCH.nomatch;
- if (auto ef = ex.isFuncExp())
- return ef.matchType(to, sc, presult, eSink);
- else
- return cannotInfer();
- }
-
- if (!tof || !tof.next)
- return MATCH.nomatch;
-
- assert(type && type != Type.tvoid);
- if (fd.type.ty == Terror)
- return MATCH.nomatch;
- auto tfx = fd.type.isTypeFunction();
- bool convertMatch = (type.ty != to.ty);
-
- if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
- {
- /* If return type is inferred and covariant return,
- * tweak return statements to required return type.
- *
- * interface I {}
- * class C : Object, I{}
- *
- * I delegate() dg = delegate() { return new class C(); }
- */
- convertMatch = true;
-
- auto tfy = new TypeFunction(tfx.parameterList, tof.next,
- tfx.linkage, STC.undefined_);
- tfy.mod = tfx.mod;
- tfy.trust = tfx.trust;
- tfy.isnothrow = tfx.isnothrow;
- tfy.isnogc = tfx.isnogc;
- tfy.purity = tfx.purity;
- tfy.isproperty = tfx.isproperty;
- tfy.isref = tfx.isref;
- tfy.isInOutParam = tfx.isInOutParam;
- tfy.isInOutQual = tfx.isInOutQual;
- tfy.deco = tfy.merge().deco;
-
- tfx = tfy;
- }
- Type tx;
- if (tok == TOK.delegate_ ||
- tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
- {
- // Allow conversion from implicit function pointer to delegate
- tx = new TypeDelegate(tfx);
- tx.deco = tx.merge().deco;
- }
- else
- {
- assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors);
- tx = tfx.pointerTo();
- }
- //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
-
- MATCH m = tx.implicitConvTo(to);
- if (m > MATCH.nomatch)
- {
- // MATCH.exact: exact type match
- // MATCH.constant: covairiant type match (eg. attributes difference)
- // MATCH.convert: context conversion
- m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
-
- if (presult)
- {
- (*presult) = cast(FuncExp)copy();
- (*presult).type = to;
-
- // https://issues.dlang.org/show_bug.cgi?id=12508
- // Tweak function body for covariant returns.
- (*presult).fd.modifyReturns(sc, tof.next);
- }
- }
- else if (!cast(ErrorSinkNull)eSink)
- {
- auto ts = toAutoQualChars(tx, to);
- eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
- toChars(), ts[0], ts[1]);
- }
- return m;
- }
-
override const(char)* toChars() const
{
return fd.toChars();
@@ -4133,153 +3887,6 @@ extern (C++) abstract class BinExp : Expression
return ErrorExp.get();
}
- extern (D) final Expression checkOpAssignTypes(Scope* sc)
- {
- // At that point t1 and t2 are the merged types. type is the original type of the lhs.
- Type t1 = e1.type;
- Type t2 = e2.type;
-
- // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
- // See https://issues.dlang.org/show_bug.cgi?id=3841.
- // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
- if (op == EXP.addAssign || op == EXP.minAssign ||
- op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
- op == EXP.powAssign)
- {
- if ((type.isintegral() && t2.isfloating()))
- {
- warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
- }
- }
-
- // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
- if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign)
- {
- // Any multiplication by an imaginary or complex number yields a complex result.
- // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
- const(char)* opstr = EXPtoString(op).ptr;
- if (t1.isreal() && t2.iscomplex())
- {
- error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
- return ErrorExp.get();
- }
- else if (t1.isimaginary() && t2.iscomplex())
- {
- error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
- return ErrorExp.get();
- }
- else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
- {
- error(loc, "`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
- return ErrorExp.get();
- }
- }
-
- // generate an error if this is a nonsensical += or -=, eg real += imaginary
- if (op == EXP.addAssign || op == EXP.minAssign)
- {
- // Addition or subtraction of a real and an imaginary is a complex result.
- // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
- if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
- {
- error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
- return ErrorExp.get();
- }
- if (type.isreal() || type.isimaginary())
- {
- assert(global.errors || t2.isfloating());
- e2 = e2.castTo(sc, t1);
- }
- }
- if (op == EXP.mulAssign)
- {
- if (t2.isfloating())
- {
- if (t1.isreal())
- {
- if (t2.isimaginary() || t2.iscomplex())
- {
- e2 = e2.castTo(sc, t1);
- }
- }
- else if (t1.isimaginary())
- {
- if (t2.isimaginary() || t2.iscomplex())
- {
- switch (t1.ty)
- {
- case Timaginary32:
- t2 = Type.tfloat32;
- break;
-
- case Timaginary64:
- t2 = Type.tfloat64;
- break;
-
- case Timaginary80:
- t2 = Type.tfloat80;
- break;
-
- default:
- assert(0);
- }
- e2 = e2.castTo(sc, t2);
- }
- }
- }
- }
- else if (op == EXP.divAssign)
- {
- if (t2.isimaginary())
- {
- if (t1.isreal())
- {
- // x/iv = i(-x/v)
- // Therefore, the result is 0
- e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
- e2.type = t1;
- Expression e = new AssignExp(loc, e1, e2);
- e.type = t1;
- return e;
- }
- else if (t1.isimaginary())
- {
- Type t3;
- switch (t1.ty)
- {
- case Timaginary32:
- t3 = Type.tfloat32;
- break;
-
- case Timaginary64:
- t3 = Type.tfloat64;
- break;
-
- case Timaginary80:
- t3 = Type.tfloat80;
- break;
-
- default:
- assert(0);
- }
- e2 = e2.castTo(sc, t3);
- Expression e = new AssignExp(loc, e1, e2);
- e.type = t1;
- return e;
- }
- }
- }
- else if (op == EXP.modAssign)
- {
- if (t2.iscomplex())
- {
- error(loc, "cannot perform modulo complex arithmetic");
- return ErrorExp.get();
- }
- }
- return this;
- }
-
extern (D) final bool checkIntegralBin()
{
bool r1 = e1.checkIntegral();
@@ -4294,13 +3901,6 @@ extern (C++) abstract class BinExp : Expression
return (r1 || r2);
}
- extern (D) final bool checkSharedAccessBin(Scope* sc)
- {
- const r1 = e1.checkSharedAccess(sc);
- const r2 = e2.checkSharedAccess(sc);
- return (r1 || r2);
- }
-
/*********************
* Mark the operands as will never be dereferenced,
* which is useful info for @safe checks.
@@ -4315,54 +3915,6 @@ extern (C++) abstract class BinExp : Expression
}
- extern (D) final Expression reorderSettingAAElem(Scope* sc)
- {
- BinExp be = this;
-
- auto ie = be.e1.isIndexExp();
- if (!ie)
- return be;
- if (ie.e1.type.toBasetype().ty != Taarray)
- return be;
-
- /* Fix evaluation order of setting AA element
- * https://issues.dlang.org/show_bug.cgi?id=3825
- * Rewrite:
- * aa[k1][k2][k3] op= val;
- * as:
- * auto ref __aatmp = aa;
- * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
- * auto ref __aaval = val;
- * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
- */
-
- Expression e0;
- while (1)
- {
- Expression de;
- ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
- e0 = Expression.combine(de, e0);
-
- auto ie1 = ie.e1.isIndexExp();
- if (!ie1 ||
- ie1.e1.type.toBasetype().ty != Taarray)
- {
- break;
- }
- ie = ie1;
- }
- assert(ie.e1.type.toBasetype().ty == Taarray);
-
- Expression de;
- ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
- e0 = Expression.combine(de, e0);
-
- be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
-
- //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
- return Expression.combine(e0, be);
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -4941,38 +4493,6 @@ extern (C++) final class CallExp : UnaExp
return Expression.toLvalue(sc, e);
}
- override Expression addDtorHook(Scope* sc)
- {
- /* Only need to add dtor hook if it's a type that needs destruction.
- * Use same logic as VarDeclaration::callScopeDtor()
- */
-
- if (auto tf = e1.type.isTypeFunction())
- {
- if (tf.isref)
- return this;
- }
-
- Type tv = type.baseElemOf();
- if (auto ts = tv.isTypeStruct())
- {
- StructDeclaration sd = ts.sym;
- if (sd.dtor)
- {
- /* Type needs destruction, so declare a tmp
- * which the back end will recognize and call dtor on
- */
- auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), this);
- auto de = new DeclarationExp(loc, tmp);
- auto ve = new VarExp(loc, tmp);
- Expression e = new CommaExp(loc, de, ve);
- e = e.expressionSemantic(sc);
- return e;
- }
- }
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -5248,13 +4768,6 @@ extern (C++) final class CastExp : UnaExp
return Expression.toLvalue(sc, e);
}
- override Expression addDtorHook(Scope* sc)
- {
- if (to.toBasetype().ty == Tvoid) // look past the cast(void)
- e1 = e1.addDtorHook(sc);
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -5522,12 +5035,6 @@ extern (C++) final class CommaExp : BinExp
return e2.toBool();
}
- override Expression addDtorHook(Scope* sc)
- {
- e2 = e2.addDtorHook(sc);
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -6785,7 +6292,6 @@ extern (C++) final class ObjcClassReferenceExp : Expression
{
super(loc, EXP.objcClassReference);
this.classDeclaration = classDeclaration;
- type = objc.getRuntimeMetaclass(classDeclaration).getType();
}
override void accept(Visitor v)
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index cfd5198..f7f6b0b 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -45,7 +45,12 @@ typedef union tree_node Symbol;
struct Symbol; // back end symbol
#endif
+// Entry point for CTFE.
+// A compile-time result is required. Give an error if not possible
+Expression *ctfeInterpret(Expression *e);
void expandTuples(Expressions *exps, Identifiers *names = nullptr);
+StringExp *toUTF8(StringExp *se, Scope *sc);
+MATCH implicitConvTo(Expression *e, Type *t);
typedef unsigned char OwnedBy;
enum
@@ -96,19 +101,14 @@ public:
virtual bool isLvalue();
virtual Expression *toLvalue(Scope *sc, Expression *e);
virtual Expression *modifiableLvalue(Scope *sc, Expression *e);
- MATCH implicitConvTo(Type *t);
virtual Expression *resolveLoc(const Loc &loc, Scope *sc);
virtual bool checkType();
virtual bool checkValue();
- virtual Expression *addDtorHook(Scope *sc);
Expression *addressOf();
Expression *deref();
Expression *optimize(int result, bool keepLvalue = false);
- // Entry point for CTFE.
- // A compile-time result is required. Give an error if not possible
- Expression *ctfeInterpret();
int isConst();
virtual bool isIdentical(const Expression *e) const;
virtual Optional<bool> toBool();
@@ -331,8 +331,8 @@ public:
ThisExp *syntaxCopy() override;
Optional<bool> toBool() override;
- bool isLvalue() override;
- Expression *toLvalue(Scope *sc, Expression *e) override;
+ bool isLvalue() override final;
+ Expression *toLvalue(Scope *sc, Expression *e) override final;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -340,8 +340,6 @@ public:
class SuperExp final : public ThisExp
{
public:
- bool isLvalue() override;
- Expression* toLvalue(Scope* sc, Expression* e) final override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -370,7 +368,6 @@ public:
bool equals(const RootObject * const o) const override;
char32_t getCodeUnit(d_size_t i) const;
StringExp *toStringExp() override;
- StringExp *toUTF8(Scope *sc);
Optional<bool> toBool() override;
bool isLvalue() override;
Expression *toLvalue(Scope *sc, Expression *e) override;
@@ -472,7 +469,6 @@ public:
static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
bool equals(const RootObject * const o) const override;
StructLiteralExp *syntaxCopy() override;
- Expression *addDtorHook(Scope *sc) override;
Expression *toLvalue(Scope *sc, Expression *e) override;
void accept(Visitor *v) override { v->visit(this); }
@@ -826,7 +822,6 @@ public:
CallExp *syntaxCopy() override;
bool isLvalue() override;
Expression *toLvalue(Scope *sc, Expression *e) override;
- Expression *addDtorHook(Scope *sc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -1005,7 +1000,6 @@ public:
Expression *toLvalue(Scope *sc, Expression *e) override;
Expression *modifiableLvalue(Scope *sc, Expression *e) override;
Optional<bool> toBool() override;
- Expression *addDtorHook(Scope *sc) override;
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index ac8e571..1ddb2b1 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -41,6 +41,7 @@ import dmd.dstruct;
import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.errors;
+import dmd.errorsink;
import dmd.escape;
import dmd.expression;
import dmd.file_manager;
@@ -59,6 +60,7 @@ import dmd.location;
import dmd.mtype;
import dmd.mustuse;
import dmd.nspace;
+import dmd.objc;
import dmd.opover;
import dmd.optimize;
import dmd.parse;
@@ -231,6 +233,226 @@ StringExp semanticString(Scope *sc, Expression exp, const char* s)
return se;
}
+/****************************************
+ * Convert string to char[].
+ */
+StringExp toUTF8(StringExp se, Scope* sc)
+{
+ if (se.sz != 1)
+ {
+ // Convert to UTF-8 string
+ se.committed = false;
+ Expression e = castTo(se, sc, Type.tchar.arrayOf());
+ e = e.optimize(WANTvalue);
+ auto result = e.isStringExp();
+ assert(result.sz == 1);
+ return result;
+ }
+ return se;
+}
+
+private Expression reorderSettingAAElem(BinExp exp, Scope* sc)
+{
+ BinExp be = exp;
+
+ auto ie = be.e1.isIndexExp();
+ if (!ie)
+ return be;
+ if (ie.e1.type.toBasetype().ty != Taarray)
+ return be;
+
+ /* Fix evaluation order of setting AA element
+ * https://issues.dlang.org/show_bug.cgi?id=3825
+ * Rewrite:
+ * aa[k1][k2][k3] op= val;
+ * as:
+ * auto ref __aatmp = aa;
+ * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
+ * auto ref __aaval = val;
+ * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
+ */
+
+ Expression e0;
+ while (1)
+ {
+ Expression de;
+ ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
+ e0 = Expression.combine(de, e0);
+
+ auto ie1 = ie.e1.isIndexExp();
+ if (!ie1 ||
+ ie1.e1.type.toBasetype().ty != Taarray)
+ {
+ break;
+ }
+ ie = ie1;
+ }
+ assert(ie.e1.type.toBasetype().ty == Taarray);
+
+ Expression de;
+ ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
+ e0 = Expression.combine(de, e0);
+
+ be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
+
+ //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
+ return Expression.combine(e0, be);
+}
+
+
+private Expression checkOpAssignTypes(BinExp binExp, Scope* sc)
+{
+ auto e1 = binExp.e1;
+ auto e2 = binExp.e2;
+ auto op = binExp.op;
+ auto type = binExp.type;
+ auto loc = binExp.loc;
+
+ // At that point t1 and t2 are the merged types. type is the original type of the lhs.
+ Type t1 = e1.type;
+ Type t2 = e2.type;
+
+ // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
+ // See https://issues.dlang.org/show_bug.cgi?id=3841.
+ // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
+ if (op == EXP.addAssign || op == EXP.minAssign ||
+ op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
+ op == EXP.powAssign)
+ {
+ if ((type.isintegral() && t2.isfloating()))
+ {
+ warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
+ }
+ }
+
+ // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
+ if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign)
+ {
+ // Any multiplication by an imaginary or complex number yields a complex result.
+ // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
+ const(char)* opstr = EXPtoString(op).ptr;
+ if (t1.isreal() && t2.iscomplex())
+ {
+ error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
+ return ErrorExp.get();
+ }
+ else if (t1.isimaginary() && t2.iscomplex())
+ {
+ error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
+ return ErrorExp.get();
+ }
+ else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
+ {
+ error(loc, "`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
+ return ErrorExp.get();
+ }
+ }
+
+ // generate an error if this is a nonsensical += or -=, eg real += imaginary
+ if (op == EXP.addAssign || op == EXP.minAssign)
+ {
+ // Addition or subtraction of a real and an imaginary is a complex result.
+ // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
+ if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
+ {
+ error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
+ return ErrorExp.get();
+ }
+ if (type.isreal() || type.isimaginary())
+ {
+ assert(global.errors || t2.isfloating());
+ e2 = e2.castTo(sc, t1);
+ }
+ }
+ if (op == EXP.mulAssign)
+ {
+ if (t2.isfloating())
+ {
+ if (t1.isreal())
+ {
+ if (t2.isimaginary() || t2.iscomplex())
+ {
+ e2 = e2.castTo(sc, t1);
+ }
+ }
+ else if (t1.isimaginary())
+ {
+ if (t2.isimaginary() || t2.iscomplex())
+ {
+ switch (t1.ty)
+ {
+ case Timaginary32:
+ t2 = Type.tfloat32;
+ break;
+
+ case Timaginary64:
+ t2 = Type.tfloat64;
+ break;
+
+ case Timaginary80:
+ t2 = Type.tfloat80;
+ break;
+
+ default:
+ assert(0);
+ }
+ e2 = e2.castTo(sc, t2);
+ }
+ }
+ }
+ }
+ else if (op == EXP.divAssign)
+ {
+ if (t2.isimaginary())
+ {
+ if (t1.isreal())
+ {
+ // x/iv = i(-x/v)
+ // Therefore, the result is 0
+ e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
+ e2.type = t1;
+ Expression e = new AssignExp(loc, e1, e2);
+ e.type = t1;
+ return e;
+ }
+ else if (t1.isimaginary())
+ {
+ Type t3;
+ switch (t1.ty)
+ {
+ case Timaginary32:
+ t3 = Type.tfloat32;
+ break;
+
+ case Timaginary64:
+ t3 = Type.tfloat64;
+ break;
+
+ case Timaginary80:
+ t3 = Type.tfloat80;
+ break;
+
+ default:
+ assert(0);
+ }
+ e2 = e2.castTo(sc, t3);
+ Expression e = new AssignExp(loc, e1, e2);
+ e.type = t1;
+ return e;
+ }
+ }
+ }
+ else if (op == EXP.modAssign)
+ {
+ if (t2.iscomplex())
+ {
+ error(loc, "cannot perform modulo complex arithmetic");
+ return ErrorExp.get();
+ }
+ }
+ return binExp;
+}
+
private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
{
Expression e0;
@@ -1364,7 +1586,10 @@ L1:
var.isFuncDeclaration && var.isFuncDeclaration.isStatic &&
var.isFuncDeclaration.objc.selector)
{
- return new ObjcClassReferenceExp(e1.loc, ad.isClassDeclaration());
+ auto cls = ad.isClassDeclaration();
+ auto classObj = new ObjcClassReferenceExp(e1.loc, cls);
+ classObj.type = objc.getRuntimeMetaclass(cls).getType();
+ return classObj;
}
/* Access of a member which is a template parameter in dual-scope scenario
@@ -2471,7 +2696,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
//printf("type: %s\n", arg.type.toChars());
//printf("param: %s\n", p.toChars());
- const pStc = tf.parameterStorageClass(tthis, p);
+ const indirect = (fd is null) || (fd.isVirtual() && !fd.isFinal());
+ const pStc = tf.parameterStorageClass(tthis, p, fd ? &fd.outerVars : null, indirect);
if (firstArg && (pStc & STC.return_))
{
@@ -5176,7 +5402,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else
assert(0);
- e = new CallExp(exp.loc, e, exp.arguments);
+ e = new CallExp(exp.loc, e, exp.arguments, exp.names);
e = e.expressionSemantic(sc);
result = e;
return;
@@ -13890,6 +14116,186 @@ Lerr:
return errorExp();
}
+MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink eSink)
+{
+ auto loc = funcExp.loc;
+ auto tok = funcExp.tok;
+ auto td = funcExp.td;
+ auto fd = funcExp.fd;
+ auto type = funcExp.type;
+
+ MATCH cannotInfer()
+ {
+ eSink.error(loc, "cannot infer parameter types from `%s`", to.toChars());
+ return MATCH.nomatch;
+ }
+
+ //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
+ if (presult)
+ *presult = null;
+
+ TypeFunction tof = null;
+ if (to.ty == Tdelegate)
+ {
+ if (tok == TOK.function_)
+ {
+ eSink.error(loc, "cannot match function literal to delegate type `%s`", to.toChars());
+ return MATCH.nomatch;
+ }
+ tof = cast(TypeFunction)to.nextOf();
+ }
+ else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
+ {
+ if (tok == TOK.delegate_)
+ {
+ eSink.error(loc, "cannot match delegate literal to function pointer type `%s`", to.toChars());
+ return MATCH.nomatch;
+ }
+ }
+
+ if (td)
+ {
+ if (!tof)
+ {
+ return cannotInfer();
+ }
+
+ // Parameter types inference from 'tof'
+ assert(td._scope);
+ TypeFunction tf = fd.type.isTypeFunction();
+ //printf("\ttof = %s\n", tof.toChars());
+ //printf("\ttf = %s\n", tf.toChars());
+ const dim = tf.parameterList.length;
+
+ if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
+ return cannotInfer();
+
+ auto tiargs = new Objects();
+ tiargs.reserve(td.parameters.length);
+
+ foreach (tp; *td.parameters)
+ {
+ size_t u = 0;
+ foreach (i, p; tf.parameterList)
+ {
+ if (auto ti = p.type.isTypeIdentifier())
+ if (ti && ti.ident == tp.ident)
+ break;
+
+ ++u;
+ }
+ assert(u < dim);
+ Parameter pto = tof.parameterList[u];
+ Type t = pto.type;
+ if (t.ty == Terror)
+ return cannotInfer();
+ tf.parameterList[u].storageClass = tof.parameterList[u].storageClass;
+ tiargs.push(t);
+ }
+
+ // Set target of return type inference
+ if (!tf.next && tof.next)
+ fd.treq = to;
+
+ auto ti = new TemplateInstance(loc, td, tiargs);
+ Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
+
+ // Reset inference target for the later re-semantic
+ fd.treq = null;
+
+ if (ex.op == EXP.error)
+ return MATCH.nomatch;
+ if (auto ef = ex.isFuncExp())
+ return ef.matchType(to, sc, presult, eSink);
+ else
+ return cannotInfer();
+ }
+
+ if (!tof || !tof.next)
+ return MATCH.nomatch;
+
+ assert(type && type != Type.tvoid);
+ if (fd.type.ty == Terror)
+ return MATCH.nomatch;
+ auto tfx = fd.type.isTypeFunction();
+ bool convertMatch = (type.ty != to.ty);
+
+ if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
+ {
+ /* If return type is inferred and covariant return,
+ * tweak return statements to required return type.
+ *
+ * interface I {}
+ * class C : Object, I{}
+ *
+ * I delegate() dg = delegate() { return new class C(); }
+ */
+ convertMatch = true;
+
+ auto tfy = new TypeFunction(tfx.parameterList, tof.next,
+ tfx.linkage, STC.undefined_);
+ tfy.mod = tfx.mod;
+ tfy.trust = tfx.trust;
+ tfy.isnothrow = tfx.isnothrow;
+ tfy.isnogc = tfx.isnogc;
+ tfy.purity = tfx.purity;
+ tfy.isproperty = tfx.isproperty;
+ tfy.isref = tfx.isref;
+ tfy.isInOutParam = tfx.isInOutParam;
+ tfy.isInOutQual = tfx.isInOutQual;
+ tfy.deco = tfy.merge().deco;
+
+ tfx = tfy;
+ }
+ Type tx;
+ if (tok == TOK.delegate_ ||
+ tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
+ {
+ // Allow conversion from implicit function pointer to delegate
+ tx = new TypeDelegate(tfx);
+ tx.deco = tx.merge().deco;
+ }
+ else
+ {
+ assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors);
+ tx = tfx.pointerTo();
+ }
+ //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
+
+ MATCH m = tx.implicitConvTo(to);
+ if (m > MATCH.nomatch)
+ {
+ // MATCH.exact: exact type match
+ // MATCH.constant: covairiant type match (eg. attributes difference)
+ // MATCH.convert: context conversion
+ m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
+
+ if (presult)
+ {
+ (*presult) = cast(FuncExp)funcExp.copy();
+ (*presult).type = to;
+
+ // https://issues.dlang.org/show_bug.cgi?id=12508
+ // Tweak function body for covariant returns.
+ (*presult).fd.modifyReturns(sc, tof.next);
+ }
+ }
+ else if (!cast(ErrorSinkNull)eSink)
+ {
+ auto ts = toAutoQualChars(tx, to);
+ eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
+ funcExp.toChars(), ts[0], ts[1]);
+ }
+ return m;
+}
+
+private bool checkSharedAccessBin(BinExp binExp, Scope* sc)
+{
+ const r1 = binExp.e1.checkSharedAccess(sc);
+ const r2 = binExp.e2.checkSharedAccess(sc);
+ return (r1 || r2);
+}
+
/***************************************
* If expression is shared, check that we can access it.
* Give error message if not.
@@ -14060,7 +14466,106 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
return check(e, returnRef);
}
+/************************************************
+ * Destructors are attached to VarDeclarations.
+ * Hence, if expression returns a temp that needs a destructor,
+ * make sure and create a VarDeclaration for that temp.
+ */
+Expression addDtorHook(Expression e, Scope* sc)
+{
+ Expression visit(Expression exp)
+ {
+ return exp;
+ }
+
+ Expression visitStructLiteral(StructLiteralExp exp)
+ {
+ auto sd = exp.sd;
+ /* If struct requires a destructor, rewrite as:
+ * (S tmp = S()),tmp
+ * so that the destructor can be hung on tmp.
+ */
+ if (sd.dtor && sc.func)
+ {
+ /* Make an identifier for the temporary of the form:
+ * __sl%s%d, where %s is the struct name
+ */
+ char[10] buf = void;
+ const prefix = "__sl";
+ const ident = sd.ident.toString;
+ const fullLen = prefix.length + ident.length;
+ const len = fullLen < buf.length ? fullLen : buf.length;
+ buf[0 .. prefix.length] = prefix;
+ buf[prefix.length .. len] = ident[0 .. len - prefix.length];
+
+ auto tmp = copyToTemp(0, buf[0 .. len], exp);
+ Expression ae = new DeclarationExp(exp.loc, tmp);
+ Expression e = new CommaExp(exp.loc, ae, new VarExp(exp.loc, tmp));
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ return exp;
+ }
+
+ Expression visitCall(CallExp exp)
+ {
+ auto e1 = exp.e1;
+ auto type = exp.type;
+ /* Only need to add dtor hook if it's a type that needs destruction.
+ * Use same logic as VarDeclaration::callScopeDtor()
+ */
+
+ if (auto tf = e1.type.isTypeFunction())
+ {
+ if (tf.isref)
+ return exp;
+ }
+ Type tv = type.baseElemOf();
+ if (auto ts = tv.isTypeStruct())
+ {
+ StructDeclaration sd = ts.sym;
+ if (sd.dtor)
+ {
+ /* Type needs destruction, so declare a tmp
+ * which the back end will recognize and call dtor on
+ */
+ auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), exp);
+ auto de = new DeclarationExp(exp.loc, tmp);
+ auto ve = new VarExp(exp.loc, tmp);
+ Expression e = new CommaExp(exp.loc, de, ve);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+ }
+
+ return exp;
+ }
+
+ Expression visitCast(CastExp exp)
+ {
+ if (exp.to.toBasetype().ty == Tvoid) // look past the cast(void)
+ exp.e1 = exp.e1.addDtorHook(sc);
+ return exp;
+ }
+
+ Expression visitComma(CommaExp exp)
+ {
+ exp.e2 = exp.e2.addDtorHook(sc);
+ return exp;
+ }
+
+ switch(e.op)
+ {
+ default: return visit(e);
+
+ case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp());
+ case EXP.call: return visitCall(e.isCallExp());
+ case EXP.cast_: return visitCast(e.isCastExp());
+ case EXP.comma: return visitComma(e.isCommaExp());
+ }
+}
/****************************************************
* Determine if `exp`, which gets its address taken, can do so safely.
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 99848d8..edf113e 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -25,6 +25,7 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.blockexit;
import dmd.gluelayer;
+import dmd.dcast;
import dmd.dclass;
import dmd.declaration;
import dmd.delegatize;
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index 5c21be1..4284f85 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -274,7 +274,6 @@ struct CompileEnv
DString timestamp;
d_bool previewIn;
d_bool ddocOutput;
- d_bool shortenedMethods;
};
struct Global
diff --git a/gcc/d/dmd/gluelayer.d b/gcc/d/dmd/gluelayer.d
index 1793700..756c0e5 100644
--- a/gcc/d/dmd/gluelayer.d
+++ b/gcc/d/dmd/gluelayer.d
@@ -39,9 +39,6 @@ version (NoBackend)
return null;
}
- // toir
- void toObjFile(Dsymbol ds, bool multiobj) {}
-
extern(C++) abstract class ObjcGlue
{
static void initialize() {}
@@ -59,7 +56,6 @@ else version (IN_GCC)
extern (C++)
{
Statement asmSemantic(AsmStatement s, Scope* sc);
- void toObjFile(Dsymbol ds, bool multiobj);
}
// stubs
@@ -76,5 +72,4 @@ else
public import dmd.backend.code_x86 : code;
public import dmd.iasm : asmSemantic;
public import dmd.objc_glue : ObjcGlue;
- public import dmd.toobj : toObjFile;
}
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index 28c7c2b..632c0d0 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -20,6 +20,7 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.dcast;
import dmd.declaration;
+import dmd.dinterpret;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index 882f2ea..a1214b2 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -50,7 +50,6 @@ struct CompileEnv
bool previewIn; /// `in` means `[ref] scope const`, accepts rvalues
bool ddocOutput; /// collect embedded documentation comments
- bool shortenedMethods = true; /// allow => in normal function declarations
bool masm; /// use MASM inline asm syntax
}
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 6af140f..8860f14 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -24,6 +24,7 @@ import dmd.astenums;
import dmd.ast_node;
import dmd.gluelayer;
import dmd.dclass;
+import dmd.dcast;
import dmd.declaration;
import dmd.denum;
import dmd.dmangle;
@@ -4404,10 +4405,13 @@ extern (C++) final class TypeFunction : TypeNext
* Params:
* tthis = type of `this` parameter, null if none
* p = parameter to this function
+ * outerVars = context variables p could escape into, if any
+ * indirect = is this for an indirect or virtual function call?
* Returns:
* storage class with STC.scope_ or STC.return_ OR'd in
*/
- StorageClass parameterStorageClass(Type tthis, Parameter p)
+ StorageClass parameterStorageClass(Type tthis, Parameter p, VarDeclarations* outerVars = null,
+ bool indirect = false)
{
//printf("parameterStorageClass(p: %s)\n", p.toChars());
auto stc = p.storageClass;
@@ -4441,6 +4445,15 @@ extern (C++) final class TypeFunction : TypeNext
// See if p can escape via any of the other parameters
if (purity == PURE.weak)
{
+ /*
+ * Indirect calls may escape p through a nested context
+ * See:
+ * https://issues.dlang.org/show_bug.cgi?id=24212
+ * https://issues.dlang.org/show_bug.cgi?id=24213
+ */
+ if (indirect)
+ return stc;
+
// Check escaping through parameters
foreach (i, fparam; parameterList)
{
@@ -4478,6 +4491,16 @@ extern (C++) final class TypeFunction : TypeNext
return stc;
}
}
+
+ // Check escaping through nested context
+ if (outerVars && this.isMutable())
+ {
+ foreach (VarDeclaration v; *outerVars)
+ {
+ if (v.hasPointers())
+ return stc;
+ }
+ }
}
// Check escaping through return value
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index e72d918..675e944 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -610,7 +610,7 @@ public:
void purityLevel();
bool hasLazyParameters();
bool isDstyleVariadic() const;
- StorageClass parameterStorageClass(Parameter *p);
+ StorageClass parameterStorageClass(Type* tthis, Parameter *p, VarDeclarations* outerVars = nullptr, bool indirect = false);
Type *addStorageClass(StorageClass stc) override;
Type *substWildTo(unsigned mod) override;
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index d108cff..0065b01 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -16,6 +16,7 @@ import core.stdc.stdio;
import dmd.astenums;
import dmd.constfold;
import dmd.ctfeexpr;
+import dmd.dcast;
import dmd.dclass;
import dmd.declaration;
import dmd.dsymbol;
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 9a13d5c..51e522d 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -1223,11 +1223,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
else if (added & STC.ref_)
{
- // accept for legacy compatibility
- //deprecation("using `in ref` is deprecated, use `-preview=in` and `in` instead");
+ // accept using `in ref` for legacy compatibility
}
else
- error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead");
+ {
+ version (IN_GCC)
+ error("attribute `scope` cannot be applied with `in`, use `-fpreview=in` instead");
+ else
+ error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead");
+ }
return orig;
}
@@ -1244,11 +1248,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
else if (orig & STC.ref_)
{
- // accept for legacy compatibility
- //deprecation("using `in ref` is deprecated, use `-preview=in` and `in` instead");
+ // accept using `in ref` for legacy compatibility
}
else
- error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`");
+ {
+ version (IN_GCC)
+ error("attribute `in` cannot be added after `scope`: remove `scope` and use `-fpreview=in`");
+ else
+ error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`");
+ }
return orig;
}
@@ -5203,8 +5211,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.goesTo:
if (requireDo)
error("missing `do { ... }` after `in` or `out`");
- if (!compileEnv.shortenedMethods)
- error("=> shortened method not enabled, compile with compiler switch `-preview=shortenedMethods`");
const returnloc = token.loc;
nextToken();
f.fbody = new AST.ReturnStatement(returnloc, parseExpression());
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index 2f1839c..0b0ca91 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -412,7 +412,12 @@ private extern(C++) final class Semantic3Visitor : Visitor
if (!global.params.useTypeInfo || !Type.dtypeinfo || !Type.typeinfotypelist)
{
if (!global.params.useTypeInfo)
- .error(funcdecl.loc, "%s `%s` D-style variadic functions cannot be used with -betterC", funcdecl.kind, funcdecl.toPrettyChars);
+ {
+ version (IN_GCC)
+ .error(funcdecl.loc, "%s `%s` D-style variadic functions cannot be used with `-fno-rtti`", funcdecl.kind, funcdecl.toPrettyChars);
+ else
+ .error(funcdecl.loc, "%s `%s` D-style variadic functions cannot be used with -betterC", funcdecl.kind, funcdecl.toPrettyChars);
+ }
else if (!Type.typeinfotypelist)
.error(funcdecl.loc, "%s `%s` `object.TypeInfo_Tuple` could not be found, but is implicitly used in D-style variadic functions", funcdecl.kind, funcdecl.toPrettyChars);
else
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index 962ef62..d43d915 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -3483,7 +3483,10 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
// https://issues.dlang.org/show_bug.cgi?id=23159
if (!global.params.useExceptions)
{
- error(oss.loc, "`%s` cannot be used with -betterC", Token.toChars(oss.tok));
+ version (IN_GCC)
+ error(oss.loc, "`%s` cannot be used with `-fno-exceptions`", Token.toChars(oss.tok));
+ else
+ error(oss.loc, "`%s` cannot be used with -betterC", Token.toChars(oss.tok));
return setError();
}
diff --git a/gcc/d/dmd/staticcond.d b/gcc/d/dmd/staticcond.d
index 45e7773..923f1a9 100644
--- a/gcc/d/dmd/staticcond.d
+++ b/gcc/d/dmd/staticcond.d
@@ -12,6 +12,7 @@
module dmd.staticcond;
import dmd.arraytypes;
+import dmd.dinterpret;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
diff --git a/gcc/d/dmd/templateparamsem.d b/gcc/d/dmd/templateparamsem.d
index de40c1f..7762363 100644
--- a/gcc/d/dmd/templateparamsem.d
+++ b/gcc/d/dmd/templateparamsem.d
@@ -12,6 +12,7 @@
module dmd.templateparamsem;
import dmd.arraytypes;
+import dmd.dinterpret;
import dmd.dsymbol;
import dmd.dscope;
import dmd.dtemplate;
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index 254900e..ca2af79 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -24,6 +24,7 @@ import dmd.canthrow;
import dmd.dclass;
import dmd.declaration;
import dmd.dimport;
+import dmd.dinterpret;
import dmd.dmangle;
import dmd.dmodule;
import dmd.dscope;
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index fe54e29..bbe11f6 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -27,6 +27,7 @@ import dmd.dclass;
import dmd.declaration;
import dmd.denum;
import dmd.dimport;
+import dmd.dinterpret;
import dmd.dmangle;
import dmd.dmodule;
import dmd.dscope;
@@ -4305,6 +4306,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
&& d.isFuncDeclaration().objc.selector)
{
auto classRef = new ObjcClassReferenceExp(e.loc, mt.sym);
+ classRef.type = objc.getRuntimeMetaclass(mt.sym).getType();
return new DotVarExp(e.loc, classRef, d).expressionSemantic(sc);
}
else if (d.needThis() && sc.intypeof != 1)
diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d
index 6e05695..485ca3f 100644
--- a/gcc/d/dmd/typinf.d
+++ b/gcc/d/dmd/typinf.d
@@ -4,7 +4,7 @@
* Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typeinf.d, _typeinf.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typinf.d, _typinf.d)
* Documentation: https://dlang.org/phobos/dmd_typinf.html
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typinf.d
*/
@@ -20,10 +20,8 @@ import dmd.dstruct;
import dmd.errors;
import dmd.expression;
import dmd.globals;
-import dmd.gluelayer;
import dmd.location;
import dmd.mtype;
-import dmd.visitor;
import core.stdc.stdio;
/****************************************************
@@ -34,9 +32,10 @@ import core.stdc.stdio;
* loc = the location for reporting line numbers in errors
* torig = the type to generate the `TypeInfo` object for
* sc = the scope
- * genObjCode = if true, object code will be generated for the obtained TypeInfo
+ * Returns:
+ * true if `TypeInfo` was generated and needs compiling to object file
*/
-extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc, bool genObjCode = true)
+extern (C++) bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
{
// printf("genTypeInfo() %s\n", torig.toChars());
@@ -67,6 +66,7 @@ extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope
}
Type t = torig.merge2(); // do this since not all Type's are merge'd
+ bool needsCodegen = false;
if (!t.vtinfo)
{
if (t.isShared()) // does both 'shared' and 'shared const'
@@ -84,25 +84,13 @@ extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope
// ClassInfos are generated as part of ClassDeclaration codegen
const isUnqualifiedClassInfo = (t.ty == Tclass && !t.mod);
- // generate a COMDAT for other TypeInfos not available as builtins in
- // druntime
- if (!isUnqualifiedClassInfo && !builtinTypeInfo(t) && genObjCode)
- {
- if (sc) // if in semantic() pass
- {
- // Find module that will go all the way to an object file
- Module m = sc._module.importedFrom;
- m.members.push(t.vtinfo);
- }
- else // if in obj generation pass
- {
- toObjFile(t.vtinfo, global.params.multiobj);
- }
- }
+ if (!isUnqualifiedClassInfo && !builtinTypeInfo(t))
+ needsCodegen = true;
}
if (!torig.vtinfo)
torig.vtinfo = t.vtinfo; // Types aren't merged, but we can share the vtinfo's
assert(torig.vtinfo);
+ return needsCodegen;
}
/****************************************************
@@ -158,7 +146,7 @@ private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
* true if any part of type t is speculative.
* if t is null, returns false.
*/
-bool isSpeculativeType(Type t)
+extern (C++) bool isSpeculativeType(Type t)
{
static bool visitVector(TypeVector t)
{
diff --git a/gcc/d/dmd/typinf.h b/gcc/d/dmd/typinf.h
new file mode 100644
index 0000000..76f623a
--- /dev/null
+++ b/gcc/d/dmd/typinf.h
@@ -0,0 +1,22 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * https://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * https://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/typinf.h
+ */
+
+#pragma once
+
+#include "globals.h"
+
+class Expression;
+class Type;
+struct Scope;
+
+bool genTypeInfo(Expression *e, const Loc &loc, Type *torig, Scope *sc);
+Type *getTypeInfoType(const Loc &loc, Type *t, Scope *sc, bool genObjCode = true);
+bool isSpeculativeType(Type *t);
+bool builtinTypeInfo(Type *t);