d: Merge upstream dmd, druntime 643b1261bb, phobos 1c98326e7
D front-end changes: - Suggested preview switches now give gdc flags (PR109681). - `new S[10]' is now lowered to `_d_newarrayT!S(10)'. D runtime changes: - Runtime compiler library functions `_d_newarrayU', `_d_newarrayT', `_d_newarrayiT' have been converted to templates. Phobos changes: - Add new `std.traits.Unshared' template. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 643b1261bb. * d-attribs.cc (build_attributes): Update for new front-end interface. * d-lang.cc (d_post_options): Likewise. * decl.cc (layout_class_initializer): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 643b1261bb. * libdruntime/Makefile.am (DRUNTIME_DSOURCES_FREEBSD): Add core/sys/freebsd/ifaddrs.d, core/sys/freebsd/net/if_dl.d, core/sys/freebsd/sys/socket.d, core/sys/freebsd/sys/types.d. (DRUNTIME_DSOURCES_LINUX): Add core/sys/linux/linux/if_arp.d, core/sys/linux/linux/if_packet.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 1c98326e7.
This commit is contained in:
parent
8a4cde6319
commit
04802ed3b9
63 changed files with 1594 additions and 786 deletions
|
@ -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;
|
||||
OutBuffer buf;
|
||||
|
||||
// Allocate temporary array comp[]
|
||||
alias T = const(char)[];
|
||||
auto compptr = cast(T*)Mem.check(malloc(complength * T.sizeof));
|
||||
auto comp = compptr[0 .. complength];
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
|
22
gcc/d/dmd/typinf.h
Normal file
22
gcc/d/dmd/typinf.h
Normal file
|
@ -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;
|
||||
|
|
42
gcc/testsuite/gdc.test/fail_compilation/b23686.d
Normal file
42
gcc/testsuite/gdc.test/fail_compilation/b23686.d
Normal file
|
@ -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
|
||||
---
|
||||
*/
|
||||
|
|
20
gcc/testsuite/gdc.test/fail_compilation/fail24208.d
Normal file
20
gcc/testsuite/gdc.test/fail_compilation/fail24208.d
Normal file
|
@ -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);
|
||||
}
|
30
gcc/testsuite/gdc.test/fail_compilation/fail24212.d
Normal file
30
gcc/testsuite/gdc.test/fail_compilation/fail24212.d
Normal file
|
@ -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);
|
||||
}
|
17
gcc/testsuite/gdc.test/fail_compilation/fail24213.d
Normal file
17
gcc/testsuite/gdc.test/fail_compilation/fail24213.d
Normal file
|
@ -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);
|
||||
}
|
32
gcc/testsuite/gdc.test/fail_compilation/ice23865.d
Normal file
32
gcc/testsuite/gdc.test/fail_compilation/ice23865.d
Normal file
|
@ -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;
|
||||
}
|
14
gcc/testsuite/gdc.test/fail_compilation/ice24188.d
Normal file
14
gcc/testsuite/gdc.test/fail_compilation/ice24188.d
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
|
28
gcc/testsuite/gdc.test/fail_compilation/test24157.d
Normal file
28
gcc/testsuite/gdc.test/fail_compilation/test24157.d
Normal file
|
@ -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)
|
||||
|
|
136
libphobos/libdruntime/core/sys/linux/linux/if_arp.d
Normal file
136
libphobos/libdruntime/core/sys/linux/linux/if_arp.d
Normal file
|
@ -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;
|
||||
}
|
315
libphobos/libdruntime/core/sys/linux/linux/if_packet.d
Normal file
315
libphobos/libdruntime/core/sys/linux/linux/if_packet.d
Normal file
|
@ -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)
|
||||
{
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue