@@ -351,7 +351,7 @@ build_attributes (Expressions *eattrs)
/* Get the result of the attribute if it hasn't already been folded. */
if (attr->op == EXP::call)
- attr = attr->ctfeInterpret ();
+ attr = ctfeInterpret (attr);
if (attr->op != EXP::structLiteral)
{
@@ -936,7 +936,6 @@ d_post_options (const char ** fn)
fields with params. */
global.compileEnv.previewIn = global.params.previewIn;
global.compileEnv.ddocOutput = global.params.ddoc.doOutput;
- global.compileEnv.shortenedMethods = global.params.shortenedMethods;
if (warn_return_type == -1)
warn_return_type = 0;
@@ -2377,7 +2377,7 @@ layout_class_initializer (ClassDeclaration *cd)
NewExp *ne = NewExp::create (cd->loc, NULL, cd->type, NULL);
ne->type = cd->type;
- Expression *e = ne->ctfeInterpret ();
+ Expression *e = ctfeInterpret (ne);
gcc_assert (e->op == EXP::classReference);
return build_class_instance (e->isClassReferenceExp ());
@@ -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.
@@ -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;
+}
@@ -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
@@ -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;
@@ -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:
@@ -328,6 +328,7 @@ final class CParser(AST) : Parser!AST
case TOK._Atomic:
case TOK.__attribute__:
+ case TOK.__declspec:
Ldeclaration:
{
@@ -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)
{
@@ -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];
@@ -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;
@@ -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)
{
@@ -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;
@@ -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.
@@ -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;
@@ -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;
@@ -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)
{
@@ -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:
}
}
@@ -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)
@@ -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); }
};
@@ -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.
@@ -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;
@@ -274,7 +274,6 @@ struct CompileEnv
DString timestamp;
d_bool previewIn;
d_bool ddocOutput;
- d_bool shortenedMethods;
};
struct Global
@@ -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;
}
@@ -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;
@@ -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
}
@@ -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
@@ -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;
@@ -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;
@@ -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());
@@ -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
@@ -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();
}
@@ -12,6 +12,7 @@
module dmd.staticcond;
import dmd.arraytypes;
+import dmd.dinterpret;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
@@ -12,6 +12,7 @@
module dmd.templateparamsem;
import dmd.arraytypes;
+import dmd.dinterpret;
import dmd.dsymbol;
import dmd.dscope;
import dmd.dtemplate;
@@ -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;
@@ -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)
@@ -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)
{
new file mode 100644
@@ -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);
@@ -86,3 +86,16 @@ int testu()
}
static assert(testu() == 1);
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=24193
+
+union U24193 {
+ struct S {
+ int aa,bb;
+ }
+ S ss;
+ int tt:8;
+}
+
+static assert(U24193.sizeof == 8);
@@ -1,12 +1,12 @@
-// REQUIRED_ARGS:
+// REQUIRED_ARGS: -dw
// PERMUTE_ARGS:
class C
{
void bug()
{
- autoref!(true, C)(this); // 'auto ref' becomes ref parameter
- autoref!(false, Object)(super); // 'auto ref' becomes non-ref parameter
+ autoref(this); // 'auto ref' becomes non-ref parameter
+ autoref(super); // 'auto ref' becomes non-ref parameter
}
}
-void autoref(bool result, T)(auto ref T t) { static assert(__traits(isRef, t) == result); }
+void autoref(T)(auto ref T t) { static assert(__traits(isRef, t) == false); }
@@ -20,9 +20,21 @@ string fun2(string x = "x", string y, string z = "z")
static assert(fun2(y: "y") == "xyz");
-// The assumption that first parameter having a default implies all parameters have a default is no longer valid,
-// so this struct constructor shouldn't be mistaken for a default constructor.
-struct SD { this(int x = 1, int y) { } }
+struct SD
+{
+ int x;
+ int y;
+
+ // The assumption that first parameter having a default implies all parameters have a default is no longer valid,
+ // so this struct constructor shouldn't be mistaken for a default constructor.
+ this(int x = 10, int y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+}
+
+static assert(SD(y: 20) == SD(10, 20));
// UFCS
static assert("x".fun("y", w: "w") == "xyZw");
@@ -1,5 +1,5 @@
void foo()() { }
-class bar { }
+void bar(int) { }
alias bug = foo;
alias bug = bar;
new file mode 100644
@@ -0,0 +1,42 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/b23686.d(107): Error: undefined identifier `eFN1`, did you mean template `eFN0()()`?
+fail_compilation/b23686.d(107): Error: `mixin(_error_)` does not give a valid type
+fail_compilation/b23686.d(115): while looking for match for `eload!(int, 1)`
+fail_compilation/b23686.d(121): Error: undefined identifier `FNwtf`
+fail_compilation/b23686.d(121): Error: `mixin(_error_)` does not give a valid type
+fail_compilation/b23686.d(126): while looking for match for `load!"wtf"`
+---
+*/
+module b23686;
+
+#line 100
+
+//-------------------
+
+void eFN0()()
+{
+}
+
+void eload(I, I name, alias T = mixin("eFN" ~ name.stringof))()
+{
+ T!()();
+}
+
+void test2()
+{
+ eload!(int,0)();
+ eload!(int,1)();
+}
+
+//-------------------
+
+void FNfoo() {}
+void load(string name, alias T = mixin("FN" ~ name))() {}
+
+void test1()
+{
+ load!"foo"();
+ load!"wtf"();
+}
@@ -1,13 +1,13 @@
/*
TEST_OUTPUT:
---
+fail_compilation/diag4596.d(15): Error: `this` is not an lvalue and cannot be modified
+fail_compilation/diag4596.d(16): Error: conditional expression `1 ? this : this` is not a modifiable lvalue
fail_compilation/diag4596.d(18): Error: `super` is not an lvalue and cannot be modified
fail_compilation/diag4596.d(19): Error: conditional expression `1 ? super : super` is not a modifiable lvalue
---
*/
-
-
class NoGo4596
{
void fun()
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail13116.d(14): Error: returning `this` escapes a reference to parameter `this`
+fail_compilation/fail13116.d(14): Error: `this` is not an lvalue and cannot be modified
fail_compilation/fail13116.d(23): Error: `super` is not an lvalue and cannot be modified
---
*/
new file mode 100644
@@ -0,0 +1,20 @@
+/+
+REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail24208.d(19): Error: reference to local variable `n` assigned to non-scope parameter `p` calling `escape`
+fail_compilation/fail24208.d(15): which is not `scope` because of `escaped = p`
+---
++/
+void test() @safe
+{
+ int* escaped;
+
+ void escape(int* p) @safe
+ {
+ escaped = p;
+ }
+
+ int n;
+ escape(&n);
+}
new file mode 100644
@@ -0,0 +1,30 @@
+/+
+REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail24212.d(29): Error: reference to local variable `n` assigned to non-scope parameter `p` calling `fun`
+---
++/
+class Base
+{
+ @safe pure nothrow
+ void fun(int* p) {}
+}
+
+void test() @safe
+{
+ int* escaped;
+
+ class Escaper : Base
+ {
+ @safe pure nothrow
+ override void fun(int* p)
+ {
+ escaped = p;
+ }
+ }
+
+ int n;
+ Base base = new Escaper;
+ base.fun(&n);
+}
new file mode 100644
@@ -0,0 +1,17 @@
+/+
+REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail24213.d(16): Error: reference to local variable `n` assigned to non-scope parameter `p`
+---
++/
+alias Dg = void delegate(int* p) @safe pure nothrow;
+
+void main() @safe
+{
+ int* escaped;
+
+ int n;
+ Dg dg = delegate void (int* p) { escaped = p; };
+ dg(&n);
+}
new file mode 100644
@@ -0,0 +1,32 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice23865.d(64): Error: alias `ice23865.AssignableRange.back` conflicts with alias `ice23865.AssignableRange.back` at fail_compilation/ice23865.d(58)
+---
+*/
+module ice23865;
+
+#line 50
+
+class AssignableRange
+{
+ int element;
+ int front()
+ {
+ return element;
+ }
+ alias back = front;
+
+ void front(int newValue)
+ {
+ element = newValue;
+ }
+ alias back = element;
+}
+
+void test()
+{
+ AssignableRange a = new AssignableRange();
+
+ a.back;
+}
new file mode 100644
@@ -0,0 +1,14 @@
+/*
+REQUIRED_ARGS: fail_compilation/ice24188_a/ice24188_c.d
+TEST_OUTPUT:
+---
+fail_compilation/ice24188.d(9): Error: module `ice24188_c` from file fail_compilation/ice24188_a/ice24188_c.d must be imported with 'import ice24188_c;'
+---
+*/
+auto b() {
+ import fail_compilation.ice24188_a.ice24188_c : D;
+
+ struct A {
+ D e;
+ }
+}
new file mode 100644
@@ -3,6 +3,7 @@
TEST_OUTPUT:
---
fail_compilation/imports/test18480a.d(2): Error: `alias TestTemplate = TestTemplate;` cannot alias itself, use a qualified name to create an overload set
+fail_compilation/imports/test18480a.d(2): Error: alias `test18480a.TestTemplate` conflicts with alias `test18480a.TestTemplate` at fail_compilation/imports/test18480a.d(1)
---
https://issues.dlang.org/show_bug.cgi?id=18480
*/
new file mode 100644
@@ -0,0 +1,28 @@
+// https://issues.dlang.org/show_bug.cgi?id=24157
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test24157.d(23): Error: `p.self()` is not an lvalue and cannot be modified
+fail_compilation/test24157.d(27): Error: `p.unshared()` is not an lvalue and cannot be modified
+---
+*/
+
+class Promise {
+ auto ref self() {
+ return this;
+ }
+
+ auto ref unshared() shared {
+ return cast() this;
+ }
+}
+
+
+void testThis(Promise p) {
+ auto ptr = &p.self(); // must not return a ref to the Promise class ref
+}
+
+void testCastThis(shared Promise p) {
+ auto ptr = &p.unshared(); // ditto
+}
@@ -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.
@@ -261,7 +261,8 @@ DRUNTIME_DSOURCES_ELF = core/sys/elf/package.d
DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \
core/sys/freebsd/dlfcn.d core/sys/freebsd/err.d \
- core/sys/freebsd/execinfo.d core/sys/freebsd/netinet/in_.d \
+ core/sys/freebsd/execinfo.d core/sys/freebsd/ifaddrs.d \
+ core/sys/freebsd/net/if_dl.d core/sys/freebsd/netinet/in_.d \
core/sys/freebsd/pthread_np.d core/sys/freebsd/stdlib.d \
core/sys/freebsd/string.d core/sys/freebsd/sys/_bitset.d \
core/sys/freebsd/sys/_cpuset.d core/sys/freebsd/sys/cdefs.d \
@@ -269,7 +270,8 @@ DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \
core/sys/freebsd/sys/elf64.d core/sys/freebsd/sys/elf_common.d \
core/sys/freebsd/sys/event.d core/sys/freebsd/sys/link_elf.d \
core/sys/freebsd/sys/mman.d core/sys/freebsd/sys/mount.d \
- core/sys/freebsd/sys/sysctl.d core/sys/freebsd/time.d \
+ core/sys/freebsd/sys/socket.d core/sys/freebsd/sys/sysctl.d \
+ core/sys/freebsd/sys/types.d core/sys/freebsd/time.d \
core/sys/freebsd/unistd.d
DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
@@ -278,6 +280,7 @@ DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
core/sys/linux/fcntl.d core/sys/linux/fs.d core/sys/linux/ifaddrs.d \
core/sys/linux/input.d core/sys/linux/input_event_codes.d \
core/sys/linux/io_uring.d core/sys/linux/link.d \
+ core/sys/linux/linux/if_arp.d core/sys/linux/linux/if_packet.d \
core/sys/linux/netinet/in_.d core/sys/linux/netinet/tcp.d \
core/sys/linux/perf_event.d core/sys/linux/sched.d \
core/sys/linux/stdio.d core/sys/linux/string.d \
@@ -327,6 +327,7 @@ am__objects_11 = core/sys/bionic/err.lo core/sys/bionic/fcntl.lo \
@DRUNTIME_OS_ANDROID_TRUE@am__objects_12 = $(am__objects_11)
am__objects_13 = core/sys/freebsd/config.lo core/sys/freebsd/dlfcn.lo \
core/sys/freebsd/err.lo core/sys/freebsd/execinfo.lo \
+ core/sys/freebsd/ifaddrs.lo core/sys/freebsd/net/if_dl.lo \
core/sys/freebsd/netinet/in_.lo core/sys/freebsd/pthread_np.lo \
core/sys/freebsd/stdlib.lo core/sys/freebsd/string.lo \
core/sys/freebsd/sys/_bitset.lo \
@@ -336,7 +337,8 @@ am__objects_13 = core/sys/freebsd/config.lo core/sys/freebsd/dlfcn.lo \
core/sys/freebsd/sys/elf_common.lo \
core/sys/freebsd/sys/event.lo core/sys/freebsd/sys/link_elf.lo \
core/sys/freebsd/sys/mman.lo core/sys/freebsd/sys/mount.lo \
- core/sys/freebsd/sys/sysctl.lo core/sys/freebsd/time.lo \
+ core/sys/freebsd/sys/socket.lo core/sys/freebsd/sys/sysctl.lo \
+ core/sys/freebsd/sys/types.lo core/sys/freebsd/time.lo \
core/sys/freebsd/unistd.lo
@DRUNTIME_OS_FREEBSD_TRUE@am__objects_14 = $(am__objects_13)
am__objects_15 = core/sys/netbsd/dlfcn.lo core/sys/netbsd/err.lo \
@@ -366,6 +368,8 @@ am__objects_19 = core/sys/linux/config.lo core/sys/linux/dlfcn.lo \
core/sys/linux/fs.lo core/sys/linux/ifaddrs.lo \
core/sys/linux/input.lo core/sys/linux/input_event_codes.lo \
core/sys/linux/io_uring.lo core/sys/linux/link.lo \
+ core/sys/linux/linux/if_arp.lo \
+ core/sys/linux/linux/if_packet.lo \
core/sys/linux/netinet/in_.lo core/sys/linux/netinet/tcp.lo \
core/sys/linux/perf_event.lo core/sys/linux/sched.lo \
core/sys/linux/stdio.lo core/sys/linux/string.lo \
@@ -931,7 +935,8 @@ DRUNTIME_DSOURCES_DRAGONFLYBSD = core/sys/dragonflybsd/dlfcn.d \
DRUNTIME_DSOURCES_ELF = core/sys/elf/package.d
DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \
core/sys/freebsd/dlfcn.d core/sys/freebsd/err.d \
- core/sys/freebsd/execinfo.d core/sys/freebsd/netinet/in_.d \
+ core/sys/freebsd/execinfo.d core/sys/freebsd/ifaddrs.d \
+ core/sys/freebsd/net/if_dl.d core/sys/freebsd/netinet/in_.d \
core/sys/freebsd/pthread_np.d core/sys/freebsd/stdlib.d \
core/sys/freebsd/string.d core/sys/freebsd/sys/_bitset.d \
core/sys/freebsd/sys/_cpuset.d core/sys/freebsd/sys/cdefs.d \
@@ -939,7 +944,8 @@ DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \
core/sys/freebsd/sys/elf64.d core/sys/freebsd/sys/elf_common.d \
core/sys/freebsd/sys/event.d core/sys/freebsd/sys/link_elf.d \
core/sys/freebsd/sys/mman.d core/sys/freebsd/sys/mount.d \
- core/sys/freebsd/sys/sysctl.d core/sys/freebsd/time.d \
+ core/sys/freebsd/sys/socket.d core/sys/freebsd/sys/sysctl.d \
+ core/sys/freebsd/sys/types.d core/sys/freebsd/time.d \
core/sys/freebsd/unistd.d
DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
@@ -948,6 +954,7 @@ DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
core/sys/linux/fcntl.d core/sys/linux/fs.d core/sys/linux/ifaddrs.d \
core/sys/linux/input.d core/sys/linux/input_event_codes.d \
core/sys/linux/io_uring.d core/sys/linux/link.d \
+ core/sys/linux/linux/if_arp.d core/sys/linux/linux/if_packet.d \
core/sys/linux/netinet/in_.d core/sys/linux/netinet/tcp.d \
core/sys/linux/perf_event.d core/sys/linux/sched.d \
core/sys/linux/stdio.d core/sys/linux/string.d \
@@ -1593,6 +1600,11 @@ core/sys/freebsd/config.lo: core/sys/freebsd/$(am__dirstamp)
core/sys/freebsd/dlfcn.lo: core/sys/freebsd/$(am__dirstamp)
core/sys/freebsd/err.lo: core/sys/freebsd/$(am__dirstamp)
core/sys/freebsd/execinfo.lo: core/sys/freebsd/$(am__dirstamp)
+core/sys/freebsd/ifaddrs.lo: core/sys/freebsd/$(am__dirstamp)
+core/sys/freebsd/net/$(am__dirstamp):
+ @$(MKDIR_P) core/sys/freebsd/net
+ @: > core/sys/freebsd/net/$(am__dirstamp)
+core/sys/freebsd/net/if_dl.lo: core/sys/freebsd/net/$(am__dirstamp)
core/sys/freebsd/netinet/$(am__dirstamp):
@$(MKDIR_P) core/sys/freebsd/netinet
@: > core/sys/freebsd/netinet/$(am__dirstamp)
@@ -1617,7 +1629,9 @@ core/sys/freebsd/sys/link_elf.lo: \
core/sys/freebsd/sys/$(am__dirstamp)
core/sys/freebsd/sys/mman.lo: core/sys/freebsd/sys/$(am__dirstamp)
core/sys/freebsd/sys/mount.lo: core/sys/freebsd/sys/$(am__dirstamp)
+core/sys/freebsd/sys/socket.lo: core/sys/freebsd/sys/$(am__dirstamp)
core/sys/freebsd/sys/sysctl.lo: core/sys/freebsd/sys/$(am__dirstamp)
+core/sys/freebsd/sys/types.lo: core/sys/freebsd/sys/$(am__dirstamp)
core/sys/freebsd/time.lo: core/sys/freebsd/$(am__dirstamp)
core/sys/freebsd/unistd.lo: core/sys/freebsd/$(am__dirstamp)
core/sys/netbsd/$(am__dirstamp):
@@ -1685,6 +1699,12 @@ core/sys/linux/input.lo: core/sys/linux/$(am__dirstamp)
core/sys/linux/input_event_codes.lo: core/sys/linux/$(am__dirstamp)
core/sys/linux/io_uring.lo: core/sys/linux/$(am__dirstamp)
core/sys/linux/link.lo: core/sys/linux/$(am__dirstamp)
+core/sys/linux/linux/$(am__dirstamp):
+ @$(MKDIR_P) core/sys/linux/linux
+ @: > core/sys/linux/linux/$(am__dirstamp)
+core/sys/linux/linux/if_arp.lo: core/sys/linux/linux/$(am__dirstamp)
+core/sys/linux/linux/if_packet.lo: \
+ core/sys/linux/linux/$(am__dirstamp)
core/sys/linux/netinet/$(am__dirstamp):
@$(MKDIR_P) core/sys/linux/netinet
@: > core/sys/linux/netinet/$(am__dirstamp)
@@ -2055,12 +2075,16 @@ mostlyclean-compile:
-rm -f core/sys/elf/*.lo
-rm -f core/sys/freebsd/*.$(OBJEXT)
-rm -f core/sys/freebsd/*.lo
+ -rm -f core/sys/freebsd/net/*.$(OBJEXT)
+ -rm -f core/sys/freebsd/net/*.lo
-rm -f core/sys/freebsd/netinet/*.$(OBJEXT)
-rm -f core/sys/freebsd/netinet/*.lo
-rm -f core/sys/freebsd/sys/*.$(OBJEXT)
-rm -f core/sys/freebsd/sys/*.lo
-rm -f core/sys/linux/*.$(OBJEXT)
-rm -f core/sys/linux/*.lo
+ -rm -f core/sys/linux/linux/*.$(OBJEXT)
+ -rm -f core/sys/linux/linux/*.lo
-rm -f core/sys/linux/netinet/*.$(OBJEXT)
-rm -f core/sys/linux/netinet/*.lo
-rm -f core/sys/linux/sys/*.$(OBJEXT)
@@ -2231,9 +2255,11 @@ clean-libtool:
-rm -rf core/sys/dragonflybsd/sys/.libs core/sys/dragonflybsd/sys/_libs
-rm -rf core/sys/elf/.libs core/sys/elf/_libs
-rm -rf core/sys/freebsd/.libs core/sys/freebsd/_libs
+ -rm -rf core/sys/freebsd/net/.libs core/sys/freebsd/net/_libs
-rm -rf core/sys/freebsd/netinet/.libs core/sys/freebsd/netinet/_libs
-rm -rf core/sys/freebsd/sys/.libs core/sys/freebsd/sys/_libs
-rm -rf core/sys/linux/.libs core/sys/linux/_libs
+ -rm -rf core/sys/linux/linux/.libs core/sys/linux/linux/_libs
-rm -rf core/sys/linux/netinet/.libs core/sys/linux/netinet/_libs
-rm -rf core/sys/linux/sys/.libs core/sys/linux/sys/_libs
-rm -rf core/sys/netbsd/.libs core/sys/netbsd/_libs
@@ -2394,9 +2420,11 @@ distclean-generic:
-rm -f core/sys/dragonflybsd/sys/$(am__dirstamp)
-rm -f core/sys/elf/$(am__dirstamp)
-rm -f core/sys/freebsd/$(am__dirstamp)
+ -rm -f core/sys/freebsd/net/$(am__dirstamp)
-rm -f core/sys/freebsd/netinet/$(am__dirstamp)
-rm -f core/sys/freebsd/sys/$(am__dirstamp)
-rm -f core/sys/linux/$(am__dirstamp)
+ -rm -f core/sys/linux/linux/$(am__dirstamp)
-rm -f core/sys/linux/netinet/$(am__dirstamp)
-rm -f core/sys/linux/sys/$(am__dirstamp)
-rm -f core/sys/netbsd/$(am__dirstamp)
new file mode 100644
@@ -0,0 +1,136 @@
+//Written in the D programming language
+
+/++
+ D header file for Linux's linux/if_arp.h.
+
+ Copyright: Copyright 2023
+ License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
+ Authors: $(HTTP jmdavisprog.com, Jonathan M Davis)
+ +/
+module core.sys.linux.linux.if_arp;
+
+version (linux):
+extern(C):
+@nogc:
+nothrow:
+
+import core.sys.posix.net.if_ : IF_NAMESIZE;
+import core.sys.posix.sys.socket : sockaddr;
+
+enum : ushort
+{
+ ARPHRD_NETROM = 0,
+ ARPHRD_ETHER = 1,
+ ARPHRD_EETHER = 2,
+ ARPHRD_AX25 = 3,
+ ARPHRD_PRONET = 4,
+ ARPHRD_CHAOS = 5,
+ ARPHRD_IEEE802 = 6,
+ ARPHRD_ARCNET = 7,
+ ARPHRD_APPLETLK = 8,
+ ARPHRD_DLCI =15,
+ ARPHRD_ATM =19,
+ ARPHRD_METRICOM = 23,
+ ARPHRD_IEEE1394 = 24,
+ ARPHRD_EUI64 = 27,
+ ARPHRD_INFINIBAND = 32,
+
+ ARPHRD_SLIP = 256,
+ ARPHRD_CSLIP = 257,
+ ARPHRD_SLIP6 = 258,
+ ARPHRD_CSLIP6 = 259,
+ ARPHRD_RSRVD = 260,
+ ARPHRD_ADAPT = 264,
+ ARPHRD_ROSE = 270,
+ ARPHRD_X25 = 271,
+ ARPHRD_HWX25 = 272,
+ ARPHRD_CAN = 280,
+ ARPHRD_MCTP = 290,
+ ARPHRD_PPP = 512,
+ ARPHRD_CISCO = 513,
+ ARPHRD_HDLC = ARPHRD_CISCO,
+ ARPHRD_LAPB = 516,
+ ARPHRD_DDCMP = 517,
+ ARPHRD_RAWHDLC = 518,
+ ARPHRD_RAWIP = 519,
+
+ ARPHRD_TUNNEL = 768,
+ ARPHRD_TUNNEL6 = 769,
+ ARPHRD_FRAD = 770,
+ ARPHRD_SKIP = 771,
+ ARPHRD_LOOPBACK = 772,
+ ARPHRD_LOCALTLK = 773,
+ ARPHRD_FDDI = 774,
+ ARPHRD_BIF = 775,
+ ARPHRD_SIT = 776,
+ ARPHRD_IPDDP = 777,
+ ARPHRD_IPGRE = 778,
+ ARPHRD_PIMREG = 779,
+ ARPHRD_HIPPI = 780,
+ ARPHRD_ASH = 781,
+ ARPHRD_ECONET = 782,
+ ARPHRD_IRDA = 783,
+
+ ARPHRD_FCPP = 784,
+ ARPHRD_FCAL = 785,
+ ARPHRD_FCPL = 786,
+ ARPHRD_FCFABRIC = 787,
+
+ ARPHRD_IEEE802_TR = 800,
+ ARPHRD_IEEE80211 = 801,
+ ARPHRD_IEEE80211_PRISM = 802,
+ ARPHRD_IEEE80211_RADIOTAP = 803,
+ ARPHRD_IEEE802154 = 804,
+ ARPHRD_IEEE802154_MONITOR = 805,
+
+ ARPHRD_PHONET = 820,
+ ARPHRD_PHONET_PIPE = 821,
+ ARPHRD_CAIF = 822,
+ ARPHRD_IP6GRE = 823,
+ ARPHRD_NETLINK = 824,
+ ARPHRD_6LOWPAN = 825,
+ ARPHRD_VSOCKMON = 826,
+
+ ARPHRD_VOID = 0xFFFF,
+ ARPHRD_NONE = 0xFFFE,
+}
+
+enum : ushort
+{
+ ARPOP_REQUEST = 1,
+ ARPOP_REPLY = 2,
+ ARPOP_RREQUEST = 3,
+ ARPOP_RREPLY = 4,
+ ARPOP_InREQUEST = 8,
+ ARPOP_InREPLY = 9,
+ ARPOP_NAK = 10,
+}
+
+struct arpreq
+{
+ sockaddr arp_pa;
+ sockaddr arp_ha;
+ int arp_flags;
+ sockaddr arp_netmask;
+ char[IF_NAMESIZE] arp_dev;
+}
+
+enum
+{
+ ATF_COM = 0x02,
+ ATF_PERM = 0x04,
+ ATF_PUBL = 0x08,
+ ATF_USETRAILERS = 0x10,
+ ATF_NETMASK = 0x20,
+
+ ATF_DONTPUB = 0x40,
+}
+
+struct arphdr
+{
+ ushort ar_hrd;
+ ushort ar_pro;
+ ubyte ar_hln;
+ ubyte ar_pln;
+ ushort ar_op;
+}
new file mode 100644
@@ -0,0 +1,315 @@
+//Written in the D programming language
+
+/++
+ D header file for Linux's linux/if_packet.h.
+
+ Copyright: Copyright 2023
+ License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
+ Authors: $(HTTP jmdavisprog.com, Jonathan M Davis)
+ +/
+module core.sys.linux.linux.if_packet;
+
+version (linux):
+extern(C):
+@nogc:
+nothrow:
+
+import core.stdc.config : c_ulong;
+import core.sys.posix.sys.socket : sa_family_t;
+
+struct sockaddr_pkt
+{
+ sa_family_t spkt_family;
+ ubyte[14] spkt_device;
+ ushort spkt_protocol;
+}
+
+struct sockaddr_ll
+{
+ sa_family_t sll_family;
+ ushort sll_protocol;
+ int sll_ifindex;
+ ushort sll_hatype;
+ ubyte sll_pkttype;
+ ubyte sll_halen;
+ ubyte[8] sll_addr;
+}
+
+enum : ubyte
+{
+ PACKET_HOST = 0,
+ PACKET_BROADCAST = 1,
+ PACKET_MULTICAST = 2,
+ PACKET_OTHERHOST = 3,
+ PACKET_OUTGOING = 4,
+ PACKET_LOOPBACK = 5,
+ PACKET_USER = 6,
+ PACKET_KERNEL = 7,
+}
+
+enum
+{
+ PACKET_ADD_MEMBERSHIP = 1,
+ PACKET_DROP_MEMBERSHIP = 2,
+ PACKET_RECV_OUTPUT = 3,
+
+ PACKET_RX_RING = 5,
+ PACKET_STATISTICS = 6,
+ PACKET_COPY_THRESH = 7,
+ PACKET_AUXDATA = 8,
+ PACKET_ORIGDEV = 9,
+ PACKET_VERSION = 10,
+ PACKET_HDRLEN = 11,
+ PACKET_RESERVE = 12,
+ PACKET_TX_RING = 13,
+ PACKET_LOSS = 14,
+ PACKET_VNET_HDR = 15,
+ PACKET_TX_TIMESTAMP = 16,
+ PACKET_TIMESTAMP = 17,
+ PACKET_FANOUT = 18,
+ PACKET_TX_HAS_OFF = 19,
+ PACKET_QDISC_BYPASS = 20,
+ PACKET_ROLLOVER_STATS = 21,
+ PACKET_FANOUT_DATA = 22,
+ PACKET_IGNORE_OUTGOING = 23,
+ PACKET_VNET_HDR_SZ = 24,
+
+ PACKET_FANOUT_HASH = 0,
+ PACKET_FANOUT_LB = 1,
+ PACKET_FANOUT_CPU = 2,
+ PACKET_FANOUT_ROLLOVER = 3,
+ PACKET_FANOUT_RND = 4,
+ PACKET_FANOUT_QM = 5,
+ PACKET_FANOUT_CBPF = 6,
+ PACKET_FANOUT_EBPF = 7,
+
+ PACKET_FANOUT_FLAG_ROLLOVER = 0x1000,
+ PACKET_FANOUT_FLAG_UNIQUEID = 0x2000,
+ PACKET_FANOUT_FLAG_IGNORE_OUTGOING = 0x4000,
+ PACKET_FANOUT_FLAG_DEFRAG = 0x8000,
+}
+
+struct tpacket_stats
+{
+ uint tp_packets;
+ uint tp_drops;
+}
+
+struct tpacket_stats_v3
+{
+ uint tp_packets;
+ uint tp_drops;
+ uint tp_freeze_q_cnt;
+}
+
+struct tpacket_rollover_stats
+{
+ align(8):
+ ulong tp_all;
+ ulong tp_huge;
+ ulong tp_failed;
+}
+
+union tpacket_stats_u
+{
+ tpacket_stats stats1;
+ tpacket_stats_v3 stats3;
+}
+
+struct tpacket_auxdata
+{
+ uint tp_status;
+ uint tp_len;
+ uint tp_snaplen;
+ ushort tp_mac;
+ ushort tp_net;
+ ushort tp_vlan_tci;
+ ushort tp_vlan_tpid;
+}
+
+enum : uint
+{
+ TP_STATUS_KERNEL = 0,
+ TP_STATUS_USER = 1 << 0,
+ TP_STATUS_COPY = 1 << 1,
+ TP_STATUS_LOSING = 1 << 2,
+ TP_STATUS_CSUMNOTREADY = 1 << 3,
+ TP_STATUS_VLAN_VALID = 1 << 4,
+ TP_STATUS_BLK_TMO = 1 << 5,
+ TP_STATUS_VLAN_TPID_VALID = 1 << 6,
+ TP_STATUS_CSUM_VALID = 1 << 7,
+ TP_STATUS_GSO_TCP = 1 << 8,
+}
+
+enum : uint
+{
+ TP_STATUS_AVAILABLE = 0,
+ TP_STATUS_SEND_REQUEST = 1 << 0,
+ TP_STATUS_SENDING = 1 << 1,
+ TP_STATUS_WRONG_FORMAT = 1 << 2,
+}
+
+enum : uint
+{
+ TP_STATUS_TS_SOFTWARE = 1 << 29,
+ TP_STATUS_TS_RAW_HARDWARE = 1U << 31,
+}
+
+enum uint TP_FT_REQ_FILL_RXHASH = 0x1;
+
+struct tpacket_hdr
+{
+ c_ulong tp_status;
+ uint tp_len;
+ uint tp_snaplen;
+ ushort tp_mac;
+ ushort tp_net;
+ uint tp_sec;
+ uint tp_usec;
+}
+
+enum TPACKET_ALIGNMENT = 16;
+size_t TPACKET_ALIGN(size_t x) { return (x + TPACKET_ALIGNMENT - 1) &~ (TPACKET_ALIGNMENT - 1); }
+enum TPACKET_HDRLEN = TPACKET_ALIGN(tpacket_hdr.sizeof) + sockaddr_ll.sizeof;
+
+struct tpacket2_hdr
+{
+ uint tp_status;
+ uint tp_len;
+ uint tp_snaplen;
+ ushort tp_mac;
+ ushort tp_net;
+ uint tp_sec;
+ uint tp_nsec;
+ ushort tp_vlan_tci;
+ ushort tp_vlan_tpid;
+ ubyte[4] tp_padding;
+}
+
+struct tpacket_hdr_variant1
+{
+ uint tp_rxhash;
+ uint tp_vlan_tci;
+ ushort tp_vlan_tpid;
+ ushort tp_padding;
+}
+
+struct tpacket3_hdr
+{
+ uint tp_next_offset;
+ uint tp_sec;
+ uint tp_nsec;
+ uint tp_snaplen;
+ uint tp_len;
+ uint tp_status;
+ ushort tp_mac;
+ ushort tp_net;
+
+ union
+ {
+ tpacket_hdr_variant1 hv1;
+ }
+
+ ubyte[8] tp_padding;
+}
+
+struct tpacket_bd_ts
+{
+ uint ts_sec;
+
+ union
+ {
+ uint ts_usec;
+ uint ts_nsec;
+ }
+}
+
+struct tpacket_hdr_v1
+{
+ uint block_status;
+ uint num_pkts;
+ uint offset_to_first_pkt;
+ uint blk_len;
+ align(8) ulong seq_num;
+ tpacket_bd_ts ts_first_pkt;
+ tpacket_bd_ts ts_last_pkt;
+}
+
+union tpacket_bd_header_u
+{
+ tpacket_hdr_v1 bh1;
+}
+
+struct tpacket_block_desc
+{
+ uint version_;
+ uint offset_to_priv;
+ tpacket_bd_header_u hdr;
+}
+
+enum TPACKET2_HDRLEN = TPACKET_ALIGN(tpacket2_hdr.sizeof) + sockaddr_ll.sizeof;
+enum TPACKET3_HDRLEN = TPACKET_ALIGN(tpacket3_hdr.sizeof) + sockaddr_ll.sizeof;
+
+enum tpacket_versions
+{
+ TPACKET_V1,
+ TPACKET_V2,
+ TPACKET_V3
+}
+
+struct tpacket_req
+{
+ uint tp_block_size;
+ uint tp_block_nr;
+ uint tp_frame_size;
+ uint tp_frame_nr;
+}
+
+struct tpacket_req3
+{
+ uint tp_block_size;
+ uint tp_block_nr;
+ uint tp_frame_size;
+ uint tp_frame_nr;
+ uint tp_retire_blk_tov;
+ uint tp_sizeof_priv;
+ uint tp_feature_req_word;
+}
+
+union tpacket_req_u
+{
+ tpacket_req req;
+ tpacket_req3 req3;
+}
+
+struct packet_mreq
+{
+ int mr_ifindex;
+ ushort mr_type;
+ ushort mr_alen;
+ ubyte[8] mr_address;
+}
+
+struct fanout_args
+{
+ version(LittleEndian)
+ {
+ ushort id;
+ ushort type_flags;
+ }
+ else
+ {
+ ushort type_flags;
+ ushort id;
+ }
+
+ uint max_num_members;
+}
+
+enum
+{
+ PACKET_MR_MULTICAST = 0,
+ PACKET_MR_PROMISC = 1,
+ PACKET_MR_ALLMULTI = 2,
+ PACKET_MR_UNICAST = 3,
+}
@@ -1,4 +1,4 @@
-2458e8f82e3004197d8a66239a6b72e17264bb26
+1c98326e787e504d9045004e593273ec99b13121
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
@@ -418,8 +418,8 @@ Bugs: Changes to `ref` and `out` arguments are not propagated to the
*/
struct Task(alias fun, Args...)
{
- AbstractTask base = {runTask : &impl};
- alias base this;
+ private AbstractTask base = {runTask : &impl};
+ private alias base this;
private @property AbstractTask* basePtr()
{
@@ -165,21 +165,24 @@ See_Also:
Params:
R = type to be tested
- E = the type of the elements of the range if not `void`
+ E = if present, the elements of the range must be
+ $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible)
+ to this type
Returns:
`true` if R is an input range (possibly with element type `E`), `false` if not
*/
-enum bool isInputRange(R, E = void) =
+enum bool isInputRange(R) =
is(typeof(R.init) == R)
&& is(typeof((R r) { return r.empty; } (R.init)) == bool)
&& (is(typeof((return ref R r) => r.front)) || is(typeof(ref (return ref R r) => r.front)))
&& !is(typeof((R r) { return r.front; } (R.init)) == void)
- && is(typeof((R r) => r.popFront))
- && (is(E == void) ||
- is(ElementType!R == E) ||
- is(const(ElementType!R) == E) ||
- (is(const(ElementType!R) == immutable E) && is(const(E) == E)));
+ && is(typeof((R r) => r.popFront));
+
+/// ditto
+enum bool isInputRange(R, E) =
+ .isInputRange!R && isQualifierConvertible!(ElementType!R, E);
+
///
@safe unittest
{
@@ -132,6 +132,7 @@
* $(LREF PointerTarget)
* $(LREF Signed)
* $(LREF Unconst)
+ * $(LREF Unshared)
* $(LREF Unqual)
* $(LREF Unsigned)
* $(LREF ValueType)
@@ -7848,6 +7849,46 @@ else
static assert(is(Unconst!ImmIntArr == immutable(int)[]));
}
+/++
+ Removes `shared` qualifier, if any, from type `T`.
+
+ Note that while `immutable` is implicitly `shared`, it is unaffected by
+ Unshared. Only explict `shared` is removed.
+ +/
+template Unshared(T)
+{
+ static if (is(T == shared U, U))
+ alias Unshared = U;
+ else
+ alias Unshared = T;
+}
+
+///
+@safe unittest
+{
+ static assert(is(Unshared!int == int));
+ static assert(is(Unshared!(const int) == const int));
+ static assert(is(Unshared!(immutable int) == immutable int));
+
+ static assert(is(Unshared!(shared int) == int));
+ static assert(is(Unshared!(shared(const int)) == const int));
+
+ static assert(is(Unshared!(shared(int[])) == shared(int)[]));
+}
+
+@safe unittest
+{
+ static assert(is(Unshared!( int) == int));
+ static assert(is(Unshared!( const int) == const int));
+ static assert(is(Unshared!( inout int) == inout int));
+ static assert(is(Unshared!( inout const int) == inout const int));
+ static assert(is(Unshared!(shared int) == int));
+ static assert(is(Unshared!(shared const int) == const int));
+ static assert(is(Unshared!(shared inout int) == inout int));
+ static assert(is(Unshared!(shared inout const int) == inout const int));
+ static assert(is(Unshared!( immutable int) == immutable int));
+}
+
version (StdDdoc)
{
/**