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:
Iain Buclaw 2023-11-02 13:24:07 +01:00
parent 8a4cde6319
commit 04802ed3b9
63 changed files with 1594 additions and 786 deletions

View file

@ -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)
{

View file

@ -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;

View file

@ -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 ());

View file

@ -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.

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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:

View file

@ -328,6 +328,7 @@ final class CParser(AST) : Parser!AST
case TOK._Atomic:
case TOK.__attribute__:
case TOK.__declspec:
Ldeclaration:
{

View file

@ -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)
{

View file

@ -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];

View file

@ -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;

View file

@ -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)
{

View file

@ -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;

View file

@ -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.

View file

@ -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;

View file

@ -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;

View file

@ -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)
{

View file

@ -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:
}
}

View file

@ -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)

View file

@ -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); }
};

View file

@ -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.

View file

@ -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;

View file

@ -274,7 +274,6 @@ struct CompileEnv
DString timestamp;
d_bool previewIn;
d_bool ddocOutput;
d_bool shortenedMethods;
};
struct Global

View file

@ -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;
}

View file

@ -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;

View file

@ -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
}

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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());

View file

@ -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

View file

@ -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();
}

View file

@ -12,6 +12,7 @@
module dmd.staticcond;
import dmd.arraytypes;
import dmd.dinterpret;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;

View file

@ -12,6 +12,7 @@
module dmd.templateparamsem;
import dmd.arraytypes;
import dmd.dinterpret;
import dmd.dsymbol;
import dmd.dscope;
import dmd.dtemplate;

View file

@ -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;

View file

@ -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)

View file

@ -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
View 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);

View file

@ -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);

View file

@ -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); }

View file

@ -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");

View file

@ -1,5 +1,5 @@
void foo()() { }
class bar { }
void bar(int) { }
alias bug = foo;
alias bug = bar;

View 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"();
}

View file

@ -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()

View file

@ -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
---
*/

View 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);
}

View 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);
}

View 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);
}

View 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;
}

View 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;
}
}

View file

@ -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
*/

View 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
}

View file

@ -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.

View file

@ -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 \

View file

@ -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)

View 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;
}

View 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,
}

View file

@ -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.

View file

@ -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()
{

View file

@ -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
{

View file

@ -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)
{
/**