695 changes: 593 additions & 102 deletions gcc/d/dmd/cppmangle.d

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions gcc/d/dmd/ddoc/default_ddoc_theme.ddoc
Original file line number Diff line number Diff line change
Expand Up @@ -735,3 +735,8 @@ DDOC_CONSTRAINT = $(DDOC_CONSTRAINT) if ($0)
DDOC_OVERLOAD_SEPARATOR = $0
DDOC_TEMPLATE_PARAM_LIST = $0
DDOC_TEMPLATE_PARAM = $0
DDOC_LINK_AUTODETECT = $(LINK $0)
DDOC_AUTO_PSYMBOL = $(DDOC_PSYMBOL $0)
DDOC_AUTO_KEYWORD = $(DDOC_KEYWORD $0)
DDOC_AUTO_PARAM = $(DDOC_PARAM $0)
DDOC_AUTO_PSYMBOL_SUPPRESS = $0
6 changes: 6 additions & 0 deletions gcc/d/dmd/dstruct.d
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,12 @@ extern (C++) class StructDeclaration : AggregateDeclaration
{
if (vd._init)
{
if (vd._init.isVoidInitializer())
/* Treat as 0 for the purposes of putting the initializer
* in the BSS segment, or doing a mass set to 0
*/
continue;

// Zero size fields are zero initialized
if (vd.type.size(vd.loc) == 0)
continue;
Expand Down
3 changes: 3 additions & 0 deletions gcc/d/dmd/errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

#pragma once

#include <stdarg.h>
#include <stddef.h>

struct Loc;

bool isConsoleColorSupported();
Expand Down
47 changes: 26 additions & 21 deletions gcc/d/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -2189,12 +2189,16 @@ private Module loadStdMath()
auto a = new Identifiers();
a.push(Id.std);
auto s = new Import(Loc.initial, a, Id.math, null, false);
// Module.load will call fatal() if there's no std.math available.
// Gag the error here, pushing the error handling to the caller.
uint errors = global.startGagging();
s.load(null);
if (s.mod)
{
s.mod.importAll(null);
s.mod.dsymbolSemantic(null);
}
global.endGagging(errors);
impStdMath = s;
}
return impStdMath.mod;
Expand Down Expand Up @@ -2353,19 +2357,29 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor

if (hasThis(sc))
{
AggregateDeclaration ad = sc.getStructClassScope();
if (ad && ad.aliasthis)
for (AggregateDeclaration ad = sc.getStructClassScope(); ad;)
{
Expression e;
e = new ThisExp(exp.loc);
e = new DotIdExp(exp.loc, e, ad.aliasthis.ident);
e = new DotIdExp(exp.loc, e, exp.ident);
e = e.trySemantic(sc);
if (e)
if (ad.aliasthis)
{
result = e;
return;
Expression e;
e = new ThisExp(exp.loc);
e = new DotIdExp(exp.loc, e, ad.aliasthis.ident);
e = new DotIdExp(exp.loc, e, exp.ident);
e = e.trySemantic(sc);
if (e)
{
result = e;
return;
}
}

auto cd = ad.isClassDeclaration();
if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
{
ad = cd.baseClass;
continue;
}
break;
}
}

Expand Down Expand Up @@ -9464,17 +9478,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Module mmath = loadStdMath();
if (!mmath)
{
//error("requires std.math for ^^ operators");
//fatal();
// Leave handling of PowExp to the backend, or throw
// an error gracefully if no backend support exists.
if (Expression ex = typeCombine(exp, sc))
{
result = ex;
return;
}
result = exp;
return;
e.error("`%s` requires `std.math` for `^^` operators", e.toChars());
return setError();
}
e = new ScopeExp(exp.loc, mmath);

Expand Down
11 changes: 10 additions & 1 deletion gcc/d/dmd/func.d
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,17 @@ public:
{
DtorExpStatement des;
if (fd.nrvo_can && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
fd.nrvo_var == des.var && global.params.useExceptions && ClassDeclaration.throwable)
fd.nrvo_var == des.var)
{
if (!(global.params.useExceptions && ClassDeclaration.throwable))
{
/* Don't need to call destructor at all, since it is nrvo
*/
replaceCurrent(s._body);
s._body.accept(this);
return;
}

/* Normally local variable dtors are called regardless exceptions.
* But for nrvo_var, its dtor should be called only when exception is thrown.
*
Expand Down
96 changes: 49 additions & 47 deletions gcc/d/dmd/init.d
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ extern (C++) class Initializer : RootObject
this.kind = kind;
}

abstract Initializer syntaxCopy();

override final const(char)* toChars()
{
OutBuffer buf;
Expand Down Expand Up @@ -115,11 +113,6 @@ extern (C++) final class VoidInitializer : Initializer
super(loc, InitKind.void_);
}

override Initializer syntaxCopy()
{
return new VoidInitializer(loc);
}

override void accept(Visitor v)
{
v.visit(this);
Expand All @@ -135,11 +128,6 @@ extern (C++) final class ErrorInitializer : Initializer
super(Loc.initial, InitKind.error);
}

override Initializer syntaxCopy()
{
return this;
}

override void accept(Visitor v)
{
v.visit(this);
Expand All @@ -158,20 +146,6 @@ extern (C++) final class StructInitializer : Initializer
super(loc, InitKind.struct_);
}

override Initializer syntaxCopy()
{
auto ai = new StructInitializer(loc);
assert(field.dim == value.dim);
ai.field.setDim(field.dim);
ai.value.setDim(value.dim);
for (size_t i = 0; i < field.dim; i++)
{
ai.field[i] = field[i];
ai.value[i] = value[i].syntaxCopy();
}
return ai;
}

void addInit(Identifier field, Initializer value)
{
//printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value);
Expand Down Expand Up @@ -200,21 +174,6 @@ extern (C++) final class ArrayInitializer : Initializer
super(loc, InitKind.array);
}

override Initializer syntaxCopy()
{
//printf("ArrayInitializer::syntaxCopy()\n");
auto ai = new ArrayInitializer(loc);
assert(index.dim == value.dim);
ai.index.setDim(index.dim);
ai.value.setDim(value.dim);
for (size_t i = 0; i < ai.value.dim; i++)
{
ai.index[i] = index[i] ? index[i].syntaxCopy() : null;
ai.value[i] = value[i].syntaxCopy();
}
return ai;
}

void addInit(Expression index, Initializer value)
{
this.index.push(index);
Expand Down Expand Up @@ -243,20 +202,15 @@ extern (C++) final class ArrayInitializer : Initializer
*/
extern (C++) final class ExpInitializer : Initializer
{
Expression exp;
bool expandTuples;
Expression exp;

extern (D) this(const ref Loc loc, Expression exp)
{
super(loc, InitKind.exp);
this.exp = exp;
}

override Initializer syntaxCopy()
{
return new ExpInitializer(loc, exp.syntaxCopy());
}

override void accept(Visitor v)
{
v.visit(this);
Expand Down Expand Up @@ -336,3 +290,51 @@ version (all)
return false;
}
}


/****************************************
* Copy the AST for Initializer.
* Params:
* inx = Initializer AST to copy
* Returns:
* the copy
*/
Initializer syntaxCopy(Initializer inx)
{
static Initializer copyStruct(StructInitializer vi)
{
auto si = new StructInitializer(vi.loc);
assert(vi.field.dim == vi.value.dim);
si.field.setDim(vi.field.dim);
si.value.setDim(vi.value.dim);
foreach (const i; 0 .. vi.field.dim)
{
si.field[i] = vi.field[i];
si.value[i] = vi.value[i].syntaxCopy();
}
return si;
}

static Initializer copyArray(ArrayInitializer vi)
{
auto ai = new ArrayInitializer(vi.loc);
assert(vi.index.dim == vi.value.dim);
ai.index.setDim(vi.index.dim);
ai.value.setDim(vi.value.dim);
foreach (const i; 0 .. vi.value.dim)
{
ai.index[i] = vi.index[i] ? vi.index[i].syntaxCopy() : null;
ai.value[i] = vi.value[i].syntaxCopy();
}
return ai;
}

final switch (inx.kind)
{
case InitKind.void_: return new VoidInitializer(inx.loc);
case InitKind.error: return inx;
case InitKind.struct_: return copyStruct(cast(StructInitializer)inx);
case InitKind.array: return copyArray(cast(ArrayInitializer)inx);
case InitKind.exp: return new ExpInitializer(inx.loc, (cast(ExpInitializer)inx).exp.syntaxCopy());
}
}
15 changes: 4 additions & 11 deletions gcc/d/dmd/init.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ class Initializer : public RootObject
Loc loc;
unsigned char kind;

virtual Initializer *syntaxCopy() = 0;

const char *toChars();

ErrorInitializer *isErrorInitializer();
Expand All @@ -49,16 +47,12 @@ class VoidInitializer : public Initializer
public:
Type *type; // type that this will initialize to

Initializer *syntaxCopy();

void accept(Visitor *v) { v->visit(this); }
};

class ErrorInitializer : public Initializer
{
public:
Initializer *syntaxCopy();

void accept(Visitor *v) { v->visit(this); }
};

Expand All @@ -68,7 +62,6 @@ class StructInitializer : public Initializer
Identifiers field; // of Identifier *'s
Initializers value; // parallel array of Initializer *'s

Initializer *syntaxCopy();
void addInit(Identifier *field, Initializer *value);

void accept(Visitor *v) { v->visit(this); }
Expand All @@ -83,7 +76,6 @@ class ArrayInitializer : public Initializer
Type *type; // type that array will be used to initialize
bool sem; // true if semantic() is run

Initializer *syntaxCopy();
void addInit(Expression *index, Initializer *value);
bool isAssociativeArray();
Expression *toAssocArrayLiteral();
Expand All @@ -94,12 +86,13 @@ class ArrayInitializer : public Initializer
class ExpInitializer : public Initializer
{
public:
Expression *exp;
bool expandTuples;

Initializer *syntaxCopy();
Expression *exp;

void accept(Visitor *v) { v->visit(this); }
};

Expression *initializerToExpression(Initializer *init, Type *t = NULL);

Initializer *syntaxCopy(Initializer *inx);

279 changes: 107 additions & 172 deletions gcc/d/dmd/initsem.d

Large diffs are not rendered by default.

151 changes: 51 additions & 100 deletions gcc/d/dmd/opover.d
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,45 @@ Objects* opToArg(Scope* sc, TOK op)
return tiargs;
}

// Try alias this on first operand
private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinExp e)
{
if (!ad || !ad.aliasthis)
return null;

/* Rewrite (e1 op e2) as:
* (e1.aliasthis op e2)
*/
if (e.att1 && e.e1.type == e.att1)
return null;
//printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars());
Expression e1 = new DotIdExp(e.loc, e.e1, ad.aliasthis.ident);
BinExp be = cast(BinExp)e.copy();
if (!be.att1 && e.e1.type.checkAliasThisRec())
be.att1 = e.e1.type;
be.e1 = e1;
return be.trySemantic(sc);
}

// Try alias this on second operand
private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinExp e)
{
if (!ad || !ad.aliasthis)
return null;
/* Rewrite (e1 op e2) as:
* (e1 op e2.aliasthis)
*/
if (e.att2 && e.e2.type == e.att2)
return null;
//printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars());
Expression e2 = new DotIdExp(e.loc, e.e2, ad.aliasthis.ident);
BinExp be = cast(BinExp)e.copy();
if (!be.att2 && e.e2.type.checkAliasThisRec())
be.att2 = e.e2.type;
be.e2 = e2;
return be.trySemantic(sc);
}

/************************************
* Operator overload.
* Check for operator overload, if so, replace
Expand Down Expand Up @@ -1026,45 +1065,18 @@ Expression op_overload(Expression e, Scope* sc)
}
}
}
// Try alias this on first operand
if (ad1 && ad1.aliasthis && !(e.op == TOK.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943

if (!(e.op == TOK.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
{
/* Rewrite (e1 op e2) as:
* (e1.aliasthis op e2)
*/
if (e.att1 && e.e1.type == e.att1)
result = checkAliasThisForLhs(ad1, sc, e);
if (result)
return;
//printf("att bin e1 = %s\n", this.e1.type.toChars());
Expression e1 = new DotIdExp(e.loc, e.e1, ad1.aliasthis.ident);
BinExp be = cast(BinExp)e.copy();
if (!be.att1 && e.e1.type.checkAliasThisRec())
be.att1 = e.e1.type;
be.e1 = e1;
result = be.trySemantic(sc);
return;
}
// Try alias this on second operand
/* https://issues.dlang.org/show_bug.cgi?id=2943
* make sure that when we're copying the struct, we don't
* just copy the alias this member
*/
if (ad2 && ad2.aliasthis && !(e.op == TOK.assign && ad1 && ad1 == ad2))
if (!(e.op == TOK.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
{
/* Rewrite (e1 op e2) as:
* (e1 op e2.aliasthis)
*/
if (e.att2 && e.e2.type == e.att2)
return;
//printf("att bin e2 = %s\n", e.e2.type.toChars());
Expression e2 = new DotIdExp(e.loc, e.e2, ad2.aliasthis.ident);
BinExp be = cast(BinExp)e.copy();
if (!be.att2 && e.e2.type.checkAliasThisRec())
be.att2 = e.e2.type;
be.e2 = e2;
result = be.trySemantic(sc);
result = checkAliasThisForRhs(ad2, sc, e);
return;
}
return;
}

override void visit(EqualExp e)
Expand Down Expand Up @@ -1496,41 +1508,11 @@ Expression op_overload(Expression e, Scope* sc)
return;
}
L1:
// Try alias this on first operand
if (ad1 && ad1.aliasthis)
{
/* Rewrite (e1 op e2) as:
* (e1.aliasthis op e2)
*/
if (e.att1 && e.e1.type == e.att1)
return;
//printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars());
Expression e1 = new DotIdExp(e.loc, e.e1, ad1.aliasthis.ident);
BinExp be = cast(BinExp)e.copy();
if (!be.att1 && e.e1.type.checkAliasThisRec())
be.att1 = e.e1.type;
be.e1 = e1;
result = be.trySemantic(sc);
return;
}
// Try alias this on second operand
AggregateDeclaration ad2 = isAggregate(e.e2.type);
if (ad2 && ad2.aliasthis)
{
/* Rewrite (e1 op e2) as:
* (e1 op e2.aliasthis)
*/
if (e.att2 && e.e2.type == e.att2)
return;
//printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars());
Expression e2 = new DotIdExp(e.loc, e.e2, ad2.aliasthis.ident);
BinExp be = cast(BinExp)e.copy();
if (!be.att2 && e.e2.type.checkAliasThisRec())
be.att2 = e.e2.type;
be.e2 = e2;
result = be.trySemantic(sc);
result = checkAliasThisForLhs(ad1, sc, e);
if (result)
return;
}

result = checkAliasThisForRhs(isAggregate(e.e2.type), sc, e);
}
}

Expand Down Expand Up @@ -1649,39 +1631,8 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id)
}
return result;
}
// Try alias this on first operand
if (ad1 && ad1.aliasthis)
{
/* Rewrite (e1 op e2) as:
* (e1.aliasthis op e2)
*/
if (e.att1 && e.e1.type == e.att1)
return null;
//printf("att cmp_bin e1 = %s\n", e.e1.type.toChars());
Expression e1 = new DotIdExp(e.loc, e.e1, ad1.aliasthis.ident);
BinExp be = cast(BinExp)e.copy();
if (!be.att1 && e.e1.type.checkAliasThisRec())
be.att1 = e.e1.type;
be.e1 = e1;
return be.trySemantic(sc);
}
// Try alias this on second operand
if (ad2 && ad2.aliasthis)
{
/* Rewrite (e1 op e2) as:
* (e1 op e2.aliasthis)
*/
if (e.att2 && e.e2.type == e.att2)
return null;
//printf("att cmp_bin e2 = %s\n", e.e2.type.toChars());
Expression e2 = new DotIdExp(e.loc, e.e2, ad2.aliasthis.ident);
BinExp be = cast(BinExp)e.copy();
if (!be.att2 && e.e2.type.checkAliasThisRec())
be.att2 = e.e2.type;
be.e2 = e2;
return be.trySemantic(sc);
}
return null;
Expression result = checkAliasThisForLhs(ad1, sc, e);
return result ? result : checkAliasThisForRhs(isAggregate(e.e2.type), sc, e);
}

/***********************************
Expand Down
2 changes: 2 additions & 0 deletions gcc/d/dmd/root/dcompat.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#pragma once

#include <stddef.h>

/// Represents a D [ ] array
template<typename T>
struct DArray
Expand Down
1 change: 0 additions & 1 deletion gcc/d/dmd/root/filename.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ struct FileName
private:
DArray<const char> str;
public:
FileName(const char *str);
static bool equals(const char *name1, const char *name2);
static bool absolute(const char *name);
static const char *toAbsolute(const char *name, const char *base = NULL);
Expand Down
2 changes: 1 addition & 1 deletion gcc/d/dmd/root/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

#pragma once

#define POSIX (__linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __DragonFly__ || __sun)
#define POSIX (__linux__ || __GLIBC__ || __gnu_hurd__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun)

#include "dcompat.h"
#include <stddef.h>
Expand Down
11 changes: 1 addition & 10 deletions gcc/d/dmd/root/port.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,9 @@
// Portable wrapper around compiler/system specific things.
// The idea is to minimize #ifdef's in the app code.

#include <stdlib.h> // for alloca
#include <stddef.h>
#include <stdint.h>

#if _MSC_VER
#include <alloca.h>
typedef __int64 longlong;
typedef unsigned __int64 ulonglong;
#else
typedef long long longlong;
typedef unsigned long long ulonglong;
#endif

typedef unsigned char utf8_t;

struct Port
Expand Down
27 changes: 11 additions & 16 deletions gcc/d/dmd/typesem.d
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,13 @@ private extern (C++) final class TypeSemanticVisitor : Visitor

bool errors = false;

if (mtype.inuse > 500)
{
mtype.inuse = 0;
.error(loc, "recursive type");
return error();
}

/* Copy in order to not mess up original.
* This can produce redundant copies if inferring return type,
* as semantic() will get called again on this.
Expand Down Expand Up @@ -1257,10 +1264,9 @@ private extern (C++) final class TypeSemanticVisitor : Visitor
for (size_t i = 0; i < dim; i++)
{
Parameter fparam = Parameter.getNth(tf.parameters, i);
tf.inuse++;
mtype.inuse++;
fparam.type = fparam.type.typeSemantic(loc, argsc);
if (tf.inuse == 1)
tf.inuse--;
mtype.inuse--;
if (fparam.type.ty == Terror)
{
errors = true;
Expand Down Expand Up @@ -1500,13 +1506,6 @@ private extern (C++) final class TypeSemanticVisitor : Visitor
}
tf.iswild = wildparams;

if (tf.inuse)
{
.error(loc, "recursive type");
tf.inuse = 0;
errors = true;
}

if (tf.isproperty && (tf.varargs || Parameter.dim(tf.parameters) > 2))
{
.error(loc, "properties can only have zero, one, or two parameter");
Expand Down Expand Up @@ -3436,16 +3435,12 @@ private extern(C++) final class DotExpVisitor : Visitor

/* See if we should forward to the alias this.
*/
if (sym.aliasthis)
auto alias_e = resolveAliasThis(sc, e, gagError);
if (alias_e && alias_e != e)
{
/* Rewrite e.ident as:
* e.aliasthis.ident
*/
auto alias_e = resolveAliasThis(sc, e, gagError);

if (!alias_e)
return returnExp(null);

auto die = new DotIdExp(e.loc, alias_e, ident);

auto errors = gagError ? 0 : global.startGagging();
Expand Down
14 changes: 6 additions & 8 deletions gcc/d/dmd/utf.d
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@ nothrow pure @nogc:
/// except the UTF-16 surrogate pairs in the range [0xD800,0xDFFF]
bool utf_isValidDchar(dchar c)
{
// TODO: Whether non-char code points should be rejected is pending review
// largest character code point
if (c > 0x10FFFF)
return false;
// TODO: Whether non-char code points should be rejected is pending review.
// 0xFFFE and 0xFFFF are valid for internal use, like Phobos std.utf.isValidDChar
// See also https://issues.dlang.org/show_bug.cgi?id=1357
// surrogate pairs
if (0xD800 <= c && c <= 0xDFFF)
return false;
return true;
if (c < 0xD800) // Almost all characters in a typical document.
return true;
if (c > 0xDFFF && c <= 0x10FFFF)
return true;
return false;
}

/*******************************
Expand Down
2 changes: 1 addition & 1 deletion gcc/d/verstr.h
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"2.083.0-beta.1"
"2.083.0"
164 changes: 164 additions & 0 deletions gcc/testsuite/gdc.test/compilable/cppmangle.d
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,8 @@ extern (C++, std)
uint foof();
}

struct vector (T);

struct test18957 {}
}

Expand Down Expand Up @@ -771,3 +773,165 @@ version(Windows)
"??$test19043b@U?$test19043@$$CBD@@@@YAXU?$test19043@$$CBD@@@Z");
}

// https://issues.dlang.org/show_bug.cgi?id=16479
// Missing substitution while mangling C++ template parameter for functions
version (Posix) extern (C++)
{
// Make sure aliases are still resolved
alias Alias16479 = int;
Alias16479 func16479_0 (FuncT1) (FuncT1, Alias16479);
static assert(func16479_0!(int).mangleof == `_Z11func16479_0IiEiT_i`);

// Simple substitution on return type
FuncT1* func16479_1 (FuncT1) ();
static assert(func16479_1!(int).mangleof == `_Z11func16479_1IiEPT_v`);

// Simple substitution on parameter
void func16479_2 (FuncT1) (FuncT1);
static assert(func16479_2!(int).mangleof == `_Z11func16479_2IiEvT_`);

// Make sure component substition is prefered over template parameter
FuncT1* func16479_3 (FuncT1) (FuncT1);
static assert(func16479_3!(int).mangleof == `_Z11func16479_3IiEPT_S0_`);

struct Array16479 (Arg) { Arg* data; }
struct Array16479_2 (Arg, int Size) { Arg[Size] data; }
struct Value16479 (int Value1, int Value2) { int data; }

// Make sure template parameter substitution happens on templated return
Array16479!(FuncT2) func16479_4 (FuncT1, FuncT2) (FuncT1);
static assert(func16479_4!(int, float).mangleof
== `_Z11func16479_4IifE10Array16479IT0_ET_`);

// Make sure template parameter substitution happens with values
Value16479!(Value2, Value1)* func16479_5 (int Value1, int Value2) ();
static assert(func16479_5!(1, 1).mangleof
== `_Z11func16479_5ILi1ELi1EEP10Value16479IXT0_EXT_EEv`);

// But make sure it's not substituting *too many* values
Value16479!(1, 1)* func16479_6 (int Value1, int Value2) ();
static assert(func16479_6!(1, 1).mangleof
== `_Z11func16479_6ILi1ELi1EEP10Value16479ILi1ELi1EEv`);

// Or too many types
Array16479!(int) func16479_7 (FuncT1, FuncT2) (FuncT1);
static assert(func16479_7!(int, int).mangleof
== `_Z11func16479_7IiiE10Array16479IiET_`);

// Also must check the parameters for template param substitution
void func16479_8 (FuncT1) (Array16479!(FuncT1));
static assert(func16479_8!(int).mangleof
== `_Z11func16479_8IiEv10Array16479IT_E`);

// And non-substitution
void func16479_9 (FuncT1) (Array16479!(int));
static assert(func16479_9!(int).mangleof
== `_Z11func16479_9IiEv10Array16479IiE`);

// Now let's have a bit of fun with alias parameters,
// starting with C functions
// TODO: Why is this mangled by g++:
/*
extern "C"
{
void externC16479 (int);
}
template<void (*Print)(int)>
void func16479_10 ();
void foo () { func16479_10<externC16479>(); }
*/
extern (C) void externC16479 (int);
void func16479_10 (alias Print) ();
static assert(func16479_10!(externC16479).mangleof
== `_Z12func16479_10IXadL_Z12externC16479EEEvv`);

/**
* Let's not exclude C++ functions
* Note:
* Passing a function as template parameter has an implicit
* `&` operator prepended to it, so the following code:
* ---
* void CPPPrinter16479(const char*);
* template<void (*Print)(const char*)> void func16479_11 ();
* void foo () { func16479_11<CPPPrinter16479>(); }
* ---
* Gets mangled as `func16479_11<&CPPPrinter16479>()` would,
* which means the expression part of the template argument is
* mangled as `XadL_Z[...]E` not `XL_Z[...]E`
* (expressions always begin with a code anyway).
*/
extern(C++) void CPPPrinter16479(const(char)*);
extern(C++, Namespace16479) void CPPPrinterNS16479(const(char)*);
void func16479_11 (alias Print) ();
static assert(func16479_11!(CPPPrinter16479).mangleof
== `_Z12func16479_11IXadL_Z15CPPPrinter16479PKcEEEvv`);
static assert(func16479_11!(CPPPrinterNS16479).mangleof
== `_Z12func16479_11IXadL_ZN14Namespace1647917CPPPrinterNS16479EPKcEEEvv`);

// Functions are fine, but templates are finer
// ---
// template<template<typename, int> class Container, typename T, int Val>
// Container<T, Val> func16479_12 ();
// ---
Container!(T, Val) func16479_12 (alias Container, T, int Val) ();
static assert(func16479_12!(Array16479_2, int, 42).mangleof
== `_Z12func16479_12I12Array16479_2iLi42EET_IT0_XT1_EEv`);

// Substitution needs to happen on the most specialized type
// Iow, `ref T identity (T) (ref T v);` should be mangled as
// `_Z8identityIiET_*S1_*`, not as `_Z8identityIiET_*RS0_*`
ref FuncT1 func16479_13_1 (FuncT1) (ref FuncT1);
FuncT1* func16479_13_2 (FuncT1) (FuncT1*);
void func16479_13_3 (FuncT1) (FuncT1*, FuncT1*);
FuncT1** func16479_13_4 (FuncT1) (FuncT1*, FuncT1);
FuncT1 func16479_13_5 (FuncT1) (FuncT1*, FuncT1**);
static assert(func16479_13_1!(int).mangleof == `_Z14func16479_13_1IiERT_S1_`);
static assert(func16479_13_2!(float).mangleof == `_Z14func16479_13_2IfEPT_S1_`);
static assert(func16479_13_3!(int).mangleof == `_Z14func16479_13_3IiEvPT_S1_`);
static assert(func16479_13_4!(int).mangleof == `_Z14func16479_13_4IiEPPT_S1_S0_`);
static assert(func16479_13_5!(int).mangleof == `_Z14func16479_13_5IiET_PS0_PS1_`);

// Opaque types result in a slightly different AST
vector!T* func16479_14 (T) (T v);
static assert(func16479_14!(int).mangleof == `_Z12func16479_14IiEPSt6vectorIT_ES1_`);

struct Foo16479_15 (T);
struct Baguette16479_15 (T);
struct Bar16479_15 (T);
struct FooBar16479_15 (A, B);
void inst16479_15_2 (A, B) ();
void inst16479_15_3 (A, B, C) ();

static assert(inst16479_15_2!(Bar16479_15!int, int).mangleof
== `_Z14inst16479_15_2I11Bar16479_15IiEiEvv`);
static assert(inst16479_15_2!(int, Bar16479_15!int).mangleof
== `_Z14inst16479_15_2Ii11Bar16479_15IiEEvv`);
static assert(inst16479_15_2!(Bar16479_15!int, FooBar16479_15!(Bar16479_15!int, Foo16479_15!(Bar16479_15!(Foo16479_15!int)))).mangleof
== `_Z14inst16479_15_2I11Bar16479_15IiE14FooBar16479_15IS1_11Foo16479_15IS0_IS3_IiEEEEEvv`);
static assert(inst16479_15_3!(int, Bar16479_15!int, FooBar16479_15!(Bar16479_15!int, Foo16479_15!(Bar16479_15!(Foo16479_15!int)))).mangleof
== `_Z14inst16479_15_3Ii11Bar16479_15IiE14FooBar16479_15IS1_11Foo16479_15IS0_IS3_IiEEEEEvv`);

static import cppmangle2;
cppmangle2.Struct18922* func16479_16_1 (T) (T*);
static assert(func16479_16_1!int.mangleof == `_Z14func16479_16_1IiEPN14Namespace1892211Struct18922EPT_`);
T* func16479_16_2 (T) (T*);
static assert(func16479_16_2!int.mangleof == `_Z14func16479_16_2IiEPT_S1_`);
static assert(func16479_16_2!(cppmangle2.vector!int).mangleof == `_Z14func16479_16_2ISt6vectorIiEEPT_S3_`);
static assert(func16479_16_2!(cppmangle2.vector!int).mangleof
== func16479_16_2!(cppmangle2.vector!int).mangleof);
cppmangle2.vector!T* func16479_16_3 (T) (T*);
static assert(func16479_16_3!int.mangleof == `_Z14func16479_16_3IiEPSt6vectorIiEPT_`);

extern(C++, `fakestd`) {
extern (C++, `__1`) {
struct allocator16479 (T);
struct vector16479(T, alloc = allocator16479!T);
}
}
vector16479!(T, allocator16479!T)* func16479_17_1(T)();
vector16479!(T)* func16479_17_2(T)();
static assert(func16479_17_1!int.mangleof == `_Z14func16479_17_1IiEPN7fakestd3__111vector16479IT_NS1_14allocator16479IS3_EEEEv`);
static assert(func16479_17_2!int.mangleof == `_Z14func16479_17_2IiEPN7fakestd3__111vector16479IT_NS1_14allocator16479IS3_EEEEv`);
}
5 changes: 5 additions & 0 deletions gcc/testsuite/gdc.test/compilable/cppmangle2.d
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ extern(C++, Namespace18922)
{
struct Struct18922 { int i; }
}

extern(C++, std)
{
struct vector (T);
}
41 changes: 41 additions & 0 deletions gcc/testsuite/gdc.test/compilable/test5973.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// https://issues.dlang.org/show_bug.cgi?id=5973

class A { int a = 1; }
class B { int b = 2; }
class C : A
{
B obj;
alias obj this;
this(){ obj = new B(); }
}
class X : C {}

class D
{
int i;
}

class E
{
D x;
alias x this;
}

class F : E
{
void test()
{
i = 5;
}
}

void main()
{
auto c = new C();
assert(c.a == 1); // lookup C -> A, OK
assert(c.b == 2); // lookup C => B, OK

auto x = new X();
assert(x.a == 1); // lookup X -> C -> A, OK
assert(x.b == 2); // lookup X -> C => B, NG (Line 17)
}
1 change: 0 additions & 1 deletion gcc/testsuite/gdc.test/compilable/testDIP37.d
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ void test7()
static import pkgDIP37.datetime;
static assert(!__traits(compiles, def()));
pkgDIP37.datetime.def();
pkgDIP37.datetime.common.def();
}

// https://issues.dlang.org/show_bug.cgi?id=17629
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module object;
17 changes: 17 additions & 0 deletions gcc/testsuite/gdc.test/fail_compilation/fail19319a.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
DFLAGS:
REQUIRED_ARGS: -conf= -Ifail_compilation/extra-files/minimal
TEST_OUTPUT:
---
fail_compilation/fail19319a.d(16): Error: `7 ^^ g19319` requires `std.math` for `^^` operators
fail_compilation/fail19319a.d(17): Error: `g19319 ^^ 7` requires `std.math` for `^^` operators
---
*/

__gshared int g19319 = 0;

static assert(!__traits(compiles, 7 ^^ g19319));
static assert(!__traits(compiles, g19319 ^^= 7));

__gshared int e19319 = 7 ^^ g19319;
__gshared int a19319 = g19319 ^^= 7;;
18 changes: 18 additions & 0 deletions gcc/testsuite/gdc.test/fail_compilation/fail19319b.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
DFLAGS:
REQUIRED_ARGS: -conf= -Ifail_compilation/extra-files/minimal
TEST_OUTPUT:
---
fail_compilation/fail19319b.d(16): Error: `7 ^^ x` requires `std.math` for `^^` operators
fail_compilation/fail19319b.d(17): Error: `x ^^ 7` requires `std.math` for `^^` operators
---
*/

void test19319(int x)
{
static assert(!__traits(compiles, 7 ^^ x));
static assert(!__traits(compiles, x ^^= 7));

int i = 7 ^^ x;
x ^^= 7;
}
11 changes: 5 additions & 6 deletions gcc/testsuite/gdc.test/fail_compilation/fail313.d
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
/*
REQUIRED_ARGS: -de
TEST_OUTPUT:
---
fail_compilation/fail313.d(18): Deprecation: module `imports.b313` is not accessible here, perhaps add `static import imports.b313;`
fail_compilation/fail313.d(25): Deprecation: `imports.a313.core` is not visible from module `test313`
fail_compilation/fail313.d(25): Deprecation: package `core.stdc` is not accessible here
fail_compilation/fail313.d(25): Deprecation: module `core.stdc.stdio` is not accessible here, perhaps add `static import core.stdc.stdio;`
fail_compilation/fail313.d(30): Deprecation: package `imports.pkg313` is not accessible here, perhaps add `static import imports.pkg313;`
fail_compilation/fail313.d(17): Error: module `imports.b313` is not accessible here, perhaps add `static import imports.b313;`
fail_compilation/fail313.d(24): Deprecation: `imports.a313.core` is not visible from module `test313`
fail_compilation/fail313.d(24): Error: package `core.stdc` is not accessible here
fail_compilation/fail313.d(24): Error: module `core.stdc.stdio` is not accessible here, perhaps add `static import core.stdc.stdio;`
fail_compilation/fail313.d(29): Error: package `imports.pkg313` is not accessible here, perhaps add `static import imports.pkg313;`
---
*/
module test313;
Expand Down
29 changes: 29 additions & 0 deletions gcc/testsuite/gdc.test/runnable/betterc.d
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ extern (C) void main()
test(1);
test18472();
testRuntimeLowerings();
test18457();
}

/*******************************************/
Expand Down Expand Up @@ -156,3 +157,31 @@ void testRuntimeLowerings()
break;
}
}

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=18457

__gshared int dtor;

struct S18457
{
int a = 3;
~this() { a = 0; ++dtor; }
}

S18457 myFunction()
{
S18457 s = S18457();
return s;
}

void test18457()
{
{
S18457 s = myFunction();
assert(s.a == 3);
assert(dtor == 0);
}
assert(dtor == 1);
}

59 changes: 59 additions & 0 deletions gcc/testsuite/gdc.test/runnable/cpp_stdlib.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// DISABLED: win32 win64 osx32
// EXTRA_CPP_SOURCES: cpp_stdlib.cpp
// CXXFLAGS: -std=c++11
import core.stdc.stdio;

// Disabled on windows because it needs bindings
// Disabled on osx32 because size_t is not properly mangled

version (CppRuntime_Clang)
{
extern(C++, `std`, `__1`)
{
struct allocator(T);
struct vector (T, A = allocator!T);
struct array (T, size_t N);
}
}
else
{
extern(C++, `std`)
{
struct allocator(T);
struct vector (T, A = allocator!T);
struct array (T, size_t N);
}
}

extern(C++):

ref T identity (T) (ref T v);
T** identityPP (T) (T** v);
vector!T* getVector (T) (size_t length, const T* ptr);
array!(T, N)* getArray(T, size_t N) (const T* ptr);

void main ()
{
int i = 42;
float f = 21.0f;

int* pi = &i;
float* pf = &f;

assert(42 == identity(i));
assert(21.0f == identity(f));
assert(&pi == identityPP(&pi));
assert(&pf == identityPP(&pf));

auto vi = getVector(1, &i);
auto vf = getVector(3, [f, f, f].ptr);
assert(vi !is null);
assert(vf !is null);

auto ai = getArray!(int, 4)([2012, 10, 11, 42].ptr);
auto af = getArray!(float, 4)([42.0f, 21.0f, 14.0f, 1957.0f].ptr);
assert(ai !is null);
assert(af !is null);

printf("Success\n");
}
53 changes: 53 additions & 0 deletions gcc/testsuite/gdc.test/runnable/extra-files/cpp_stdlib.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include <array>
#include <string>
#include <vector>

template<typename T>
T& identity (T& v) { return v; }
template<typename T>
T** identityPP (T** v) { return v; }

template<typename T>
std::vector<T>* getVector(size_t len, const T* ptr)
{
std::vector<T>* ret = new std::vector<T>(len);
for (size_t i = 0; i < len; ++i)
(*ret)[i] = ptr[i];
return ret;
}

std::string* getString(int len, const char* ptr)
{
return new std::string(ptr, len);
}

template<typename T, size_t N>
std::array<T, N>* getArray(const T* ptr)
{
std::array<T, N>* ret = new std::array<T, N>();
for (size_t x = 0; x < N; ++x)
(*ret)[x] = ptr[x];
return ret;
}

// This function should never be called
void instantiate ()
{
int i;
float f;
int* pi;
float* pf;

identityPP(&pi);
identityPP(&pf);
identity(i);
identity(f);

getVector<int>(0, 0);
getVector<float>(0, 0);
getVector<std::vector<float> >(0, 0);

getArray<int, 4>(0);
getArray<float, 4>(0);
//getArray<Foo<int, 42>, 4>(0);
}
10 changes: 5 additions & 5 deletions gcc/testsuite/gdc.test/runnable/testdstress.d
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:

module dstress.run.module_01;
module run.module_01;

import core.memory;
import core.exception;
Expand Down Expand Up @@ -170,9 +170,9 @@ int i;

void test7()
{
assert(dstress.run.module_01.i==0);
dstress.run.module_01.i++;
assert(dstress.run.module_01.i==1);
assert(run.module_01.i==0);
run.module_01.i++;
assert(run.module_01.i==1);
}

/* ================================ */
Expand Down Expand Up @@ -699,7 +699,7 @@ void test32()
assert(!(ti is null));
writefln("%s %d %d", ti.toString(), ti.tsize, (MyUnion32*).sizeof);
assert(ti.tsize==(MyUnion32*).sizeof);
assert(ti.toString()=="dstress.run.module_01.MyUnion32*");
assert(ti.toString()=="run.module_01.MyUnion32*");
}

/* ================================ */
Expand Down
4 changes: 2 additions & 2 deletions gcc/testsuite/gdc.test/runnable/testmodule.d
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
// @uri@ news:ct428n$2qoe$1@digitaldaemon.com
// @url@ nntp://news.digitalmars.com/D.gnu/983

module dstress.run.unicode_06_哪里;
module run.unicode_06_哪里;

int 哪里(int ö){
return ö+2;
}

int main(){
assert(dstress.run.unicode_06_哪里.哪里(2)==4);
assert(run.unicode_06_哪里.哪里(2)==4);
return 0;
}
4 changes: 4 additions & 0 deletions libphobos/libdruntime/MERGE
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ebccd9887592cbe712cca7e02b858abdf0b0bc61

The first line of this file holds the git revision number of the last
merge done from the dlang/druntime repository.
27 changes: 14 additions & 13 deletions libphobos/libdruntime/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/dlfcn.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/time.d
core/sys/freebsd/time.d core/sys/freebsd/unistd.d

DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
core/sys/linux/dlfcn.d core/sys/linux/elf.d core/sys/linux/epoll.d \
Expand Down Expand Up @@ -279,18 +279,19 @@ DRUNTIME_DSOURCES_POSIX = core/sys/posix/aio.d \
core/sys/posix/netinet/in_.d core/sys/posix/netinet/tcp.d \
core/sys/posix/poll.d core/sys/posix/pthread.d core/sys/posix/pwd.d \
core/sys/posix/sched.d core/sys/posix/semaphore.d \
core/sys/posix/setjmp.d core/sys/posix/signal.d core/sys/posix/stdio.d \
core/sys/posix/stdlib.d core/sys/posix/sys/filio.d \
core/sys/posix/sys/ioccom.d core/sys/posix/sys/ioctl.d \
core/sys/posix/sys/ipc.d core/sys/posix/sys/mman.d \
core/sys/posix/sys/msg.d core/sys/posix/sys/resource.d \
core/sys/posix/sys/select.d core/sys/posix/sys/shm.d \
core/sys/posix/sys/socket.d core/sys/posix/sys/stat.d \
core/sys/posix/sys/statvfs.d core/sys/posix/sys/time.d \
core/sys/posix/sys/ttycom.d core/sys/posix/sys/types.d \
core/sys/posix/sys/uio.d core/sys/posix/sys/un.d \
core/sys/posix/sys/utsname.d core/sys/posix/sys/wait.d \
core/sys/posix/syslog.d core/sys/posix/termios.d core/sys/posix/time.d \
core/sys/posix/setjmp.d core/sys/posix/signal.d core/sys/posix/spawn.d \
core/sys/posix/stdio.d core/sys/posix/stdlib.d \
core/sys/posix/sys/filio.d core/sys/posix/sys/ioccom.d \
core/sys/posix/sys/ioctl.d core/sys/posix/sys/ipc.d \
core/sys/posix/sys/mman.d core/sys/posix/sys/msg.d \
core/sys/posix/sys/resource.d core/sys/posix/sys/select.d \
core/sys/posix/sys/shm.d core/sys/posix/sys/socket.d \
core/sys/posix/sys/stat.d core/sys/posix/sys/statvfs.d \
core/sys/posix/sys/time.d core/sys/posix/sys/ttycom.d \
core/sys/posix/sys/types.d core/sys/posix/sys/uio.d \
core/sys/posix/sys/un.d core/sys/posix/sys/utsname.d \
core/sys/posix/sys/wait.d core/sys/posix/syslog.d \
core/sys/posix/termios.d core/sys/posix/time.d \
core/sys/posix/ucontext.d core/sys/posix/unistd.d \
core/sys/posix/utime.d

Expand Down
63 changes: 35 additions & 28 deletions libphobos/libdruntime/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -212,20 +212,20 @@ am__objects_5 = core/sys/posix/aio.lo core/sys/posix/arpa/inet.lo \
core/sys/posix/pthread.lo core/sys/posix/pwd.lo \
core/sys/posix/sched.lo core/sys/posix/semaphore.lo \
core/sys/posix/setjmp.lo core/sys/posix/signal.lo \
core/sys/posix/stdio.lo core/sys/posix/stdlib.lo \
core/sys/posix/sys/filio.lo core/sys/posix/sys/ioccom.lo \
core/sys/posix/sys/ioctl.lo core/sys/posix/sys/ipc.lo \
core/sys/posix/sys/mman.lo core/sys/posix/sys/msg.lo \
core/sys/posix/sys/resource.lo core/sys/posix/sys/select.lo \
core/sys/posix/sys/shm.lo core/sys/posix/sys/socket.lo \
core/sys/posix/sys/stat.lo core/sys/posix/sys/statvfs.lo \
core/sys/posix/sys/time.lo core/sys/posix/sys/ttycom.lo \
core/sys/posix/sys/types.lo core/sys/posix/sys/uio.lo \
core/sys/posix/sys/un.lo core/sys/posix/sys/utsname.lo \
core/sys/posix/sys/wait.lo core/sys/posix/syslog.lo \
core/sys/posix/termios.lo core/sys/posix/time.lo \
core/sys/posix/ucontext.lo core/sys/posix/unistd.lo \
core/sys/posix/utime.lo
core/sys/posix/spawn.lo core/sys/posix/stdio.lo \
core/sys/posix/stdlib.lo core/sys/posix/sys/filio.lo \
core/sys/posix/sys/ioccom.lo core/sys/posix/sys/ioctl.lo \
core/sys/posix/sys/ipc.lo core/sys/posix/sys/mman.lo \
core/sys/posix/sys/msg.lo core/sys/posix/sys/resource.lo \
core/sys/posix/sys/select.lo core/sys/posix/sys/shm.lo \
core/sys/posix/sys/socket.lo core/sys/posix/sys/stat.lo \
core/sys/posix/sys/statvfs.lo core/sys/posix/sys/time.lo \
core/sys/posix/sys/ttycom.lo core/sys/posix/sys/types.lo \
core/sys/posix/sys/uio.lo core/sys/posix/sys/un.lo \
core/sys/posix/sys/utsname.lo core/sys/posix/sys/wait.lo \
core/sys/posix/syslog.lo core/sys/posix/termios.lo \
core/sys/posix/time.lo core/sys/posix/ucontext.lo \
core/sys/posix/unistd.lo core/sys/posix/utime.lo
@DRUNTIME_OS_UNIX_TRUE@am__objects_6 = $(am__objects_5)
am__objects_7 = core/sys/darwin/dlfcn.lo core/sys/darwin/execinfo.lo \
core/sys/darwin/mach/dyld.lo core/sys/darwin/mach/getsect.lo \
Expand Down Expand Up @@ -255,7 +255,7 @@ am__objects_12 = 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/time.lo
core/sys/freebsd/time.lo core/sys/freebsd/unistd.lo
@DRUNTIME_OS_FREEBSD_TRUE@am__objects_13 = $(am__objects_12)
am__objects_14 = core/sys/openbsd/dlfcn.lo
@DRUNTIME_OS_OPENBSD_TRUE@am__objects_15 = $(am__objects_14)
Expand Down Expand Up @@ -784,7 +784,7 @@ DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/dlfcn.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/time.d
core/sys/freebsd/time.d core/sys/freebsd/unistd.d

DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
core/sys/linux/dlfcn.d core/sys/linux/elf.d core/sys/linux/epoll.d \
Expand Down Expand Up @@ -826,18 +826,19 @@ DRUNTIME_DSOURCES_POSIX = core/sys/posix/aio.d \
core/sys/posix/netinet/in_.d core/sys/posix/netinet/tcp.d \
core/sys/posix/poll.d core/sys/posix/pthread.d core/sys/posix/pwd.d \
core/sys/posix/sched.d core/sys/posix/semaphore.d \
core/sys/posix/setjmp.d core/sys/posix/signal.d core/sys/posix/stdio.d \
core/sys/posix/stdlib.d core/sys/posix/sys/filio.d \
core/sys/posix/sys/ioccom.d core/sys/posix/sys/ioctl.d \
core/sys/posix/sys/ipc.d core/sys/posix/sys/mman.d \
core/sys/posix/sys/msg.d core/sys/posix/sys/resource.d \
core/sys/posix/sys/select.d core/sys/posix/sys/shm.d \
core/sys/posix/sys/socket.d core/sys/posix/sys/stat.d \
core/sys/posix/sys/statvfs.d core/sys/posix/sys/time.d \
core/sys/posix/sys/ttycom.d core/sys/posix/sys/types.d \
core/sys/posix/sys/uio.d core/sys/posix/sys/un.d \
core/sys/posix/sys/utsname.d core/sys/posix/sys/wait.d \
core/sys/posix/syslog.d core/sys/posix/termios.d core/sys/posix/time.d \
core/sys/posix/setjmp.d core/sys/posix/signal.d core/sys/posix/spawn.d \
core/sys/posix/stdio.d core/sys/posix/stdlib.d \
core/sys/posix/sys/filio.d core/sys/posix/sys/ioccom.d \
core/sys/posix/sys/ioctl.d core/sys/posix/sys/ipc.d \
core/sys/posix/sys/mman.d core/sys/posix/sys/msg.d \
core/sys/posix/sys/resource.d core/sys/posix/sys/select.d \
core/sys/posix/sys/shm.d core/sys/posix/sys/socket.d \
core/sys/posix/sys/stat.d core/sys/posix/sys/statvfs.d \
core/sys/posix/sys/time.d core/sys/posix/sys/ttycom.d \
core/sys/posix/sys/types.d core/sys/posix/sys/uio.d \
core/sys/posix/sys/un.d core/sys/posix/sys/utsname.d \
core/sys/posix/sys/wait.d core/sys/posix/syslog.d \
core/sys/posix/termios.d core/sys/posix/time.d \
core/sys/posix/ucontext.d core/sys/posix/unistd.d \
core/sys/posix/utime.d

Expand Down Expand Up @@ -1232,6 +1233,7 @@ core/sys/posix/sched.lo: core/sys/posix/$(am__dirstamp)
core/sys/posix/semaphore.lo: core/sys/posix/$(am__dirstamp)
core/sys/posix/setjmp.lo: core/sys/posix/$(am__dirstamp)
core/sys/posix/signal.lo: core/sys/posix/$(am__dirstamp)
core/sys/posix/spawn.lo: core/sys/posix/$(am__dirstamp)
core/sys/posix/stdio.lo: core/sys/posix/$(am__dirstamp)
core/sys/posix/stdlib.lo: core/sys/posix/$(am__dirstamp)
core/sys/posix/sys/$(am__dirstamp):
Expand Down Expand Up @@ -1346,6 +1348,7 @@ core/sys/freebsd/sys/link_elf.lo: \
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/time.lo: core/sys/freebsd/$(am__dirstamp)
core/sys/freebsd/unistd.lo: core/sys/freebsd/$(am__dirstamp)
core/sys/openbsd/$(am__dirstamp):
@$(MKDIR_P) core/sys/openbsd
@: > core/sys/openbsd/$(am__dirstamp)
Expand Down Expand Up @@ -1844,6 +1847,8 @@ mostlyclean-compile:
-rm -f core/sys/freebsd/sys/mount.lo
-rm -f core/sys/freebsd/time.$(OBJEXT)
-rm -f core/sys/freebsd/time.lo
-rm -f core/sys/freebsd/unistd.$(OBJEXT)
-rm -f core/sys/freebsd/unistd.lo
-rm -f core/sys/linux/config.$(OBJEXT)
-rm -f core/sys/linux/config.lo
-rm -f core/sys/linux/dlfcn.$(OBJEXT)
Expand Down Expand Up @@ -1974,6 +1979,8 @@ mostlyclean-compile:
-rm -f core/sys/posix/setjmp.lo
-rm -f core/sys/posix/signal.$(OBJEXT)
-rm -f core/sys/posix/signal.lo
-rm -f core/sys/posix/spawn.$(OBJEXT)
-rm -f core/sys/posix/spawn.lo
-rm -f core/sys/posix/stdio.$(OBJEXT)
-rm -f core/sys/posix/stdio.lo
-rm -f core/sys/posix/stdlib.$(OBJEXT)
Expand Down
24 changes: 23 additions & 1 deletion libphobos/libdruntime/core/internal/convert.d
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ const(ubyte)[] toUbyte(T)(const T[] arr) if ((is(typeof(toUbyte(arr[0])) == cons
}

@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const ref T val) if (__traits(isIntegral, T) && !is(T == enum))
const(ubyte)[] toUbyte(T)(const ref T val) if (__traits(isIntegral, T) && !is(T == enum) && !is(T == __vector))
{
static if (T.sizeof == 1)
{
Expand Down Expand Up @@ -630,6 +630,28 @@ const(ubyte)[] toUbyte(T)(const ref T val) if (__traits(isIntegral, T) && !is(T
}
}

@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const ref T val) if (is(T == __vector))
{
if (!__ctfe)
return (cast(const ubyte*) &val)[0 .. T.sizeof];
else static if (is(typeof(val[0]) : void))
assert(0, "Unable to compute byte representation of " ~ T.stringof ~ " at compile time.");
else
{
// This code looks like it should work in CTFE but it segfaults:
// auto a = val.array;
// return toUbyte(a);
alias E = typeof(val[0]);
ubyte[] result = ctfe_alloc(T.sizeof);
for (size_t i = 0, j = 0; i < T.sizeof; i += E.sizeof, ++j)
{
result[i .. i + E.sizeof] = toUbyte(val[j]);
}
return result;
}
}

@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const ref T val) if (is(Unqual!T == cfloat) || is(Unqual!T == cdouble) ||is(Unqual!T == creal))
{
Expand Down
54 changes: 47 additions & 7 deletions libphobos/libdruntime/core/internal/hash.d
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
module core.internal.hash;

import core.internal.convert;
import core.internal.traits : allSatisfy;
import core.internal.traits : allSatisfy, Unconst;

// If true ensure that positive zero and negative zero have the same hash.
// Historically typeid(float).getHash did this but hashOf(float) did not.
Expand Down Expand Up @@ -129,7 +129,7 @@ private template canBitwiseHash(T)
}
}

private template UnqualUnsigned(T) if (__traits(isIntegral, T))
private template UnqualUnsigned(T) if (__traits(isIntegral, T) && !is(T == __vector))
{
static if (T.sizeof == ubyte.sizeof) alias UnqualUnsigned = ubyte;
else static if (T.sizeof == ushort.sizeof) alias UnqualUnsigned = ushort;
Expand Down Expand Up @@ -342,15 +342,15 @@ if (!is(T == enum) && !is(T : typeof(null)) && is(T S: S[]) && !__traits(isStati
//arithmetic type hash
@trusted @nogc nothrow pure
size_t hashOf(T)(scope const T val) if (!is(T == enum) && __traits(isArithmetic, T)
&& __traits(isIntegral, T) && T.sizeof <= size_t.sizeof)
&& __traits(isIntegral, T) && T.sizeof <= size_t.sizeof && !is(T == __vector))
{
return cast(UnqualUnsigned!T) val;
}

//arithmetic type hash
@trusted @nogc nothrow pure
size_t hashOf(T)(scope const T val, size_t seed) if (!is(T == enum) && __traits(isArithmetic, T)
&& __traits(isIntegral, T) && T.sizeof <= size_t.sizeof)
&& __traits(isIntegral, T) && T.sizeof <= size_t.sizeof && !is(T == __vector))
{
static if (size_t.sizeof < ulong.sizeof)
{
Expand Down Expand Up @@ -381,7 +381,7 @@ size_t hashOf(T)(scope const T val, size_t seed) if (!is(T == enum) && __traits(
//arithmetic type hash
@trusted @nogc nothrow pure
size_t hashOf(T)(scope const T val, size_t seed = 0) if (!is(T == enum) && __traits(isArithmetic, T)
&& (!__traits(isIntegral, T) || T.sizeof > size_t.sizeof))
&& (!__traits(isIntegral, T) || T.sizeof > size_t.sizeof) && !is(T == __vector))
{
static if (__traits(isFloating, val))
{
Expand Down Expand Up @@ -423,6 +423,28 @@ size_t hashOf(T)(scope const T val, size_t seed = 0) if (!is(T == enum) && __tra
}
}

size_t hashOf(T)(scope const auto ref T val, size_t seed = 0) @safe @nogc nothrow pure
if (is(T == __vector) && !is(T == enum))
{
static if (__traits(isFloating, T) && (floatCoalesceZeroes || floatCoalesceNaNs))
{
if (__ctfe)
{
// Workaround for CTFE bug.
alias E = Unqual!(typeof(val[0]));
E[T.sizeof / E.sizeof] array;
foreach (i; 0 .. T.sizeof / E.sizeof)
array[i] = val[i];
return hashOf(array, seed);
}
return hashOf(val.array, seed);
}
else
{
return bytesHashAlignedBy!T(toUbyte(val), seed);
}
}

//typeof(null) hash. CTFE supported
@trusted @nogc nothrow pure
size_t hashOf(T)(scope const T val) if (!is(T == enum) && is(T : typeof(null)))
Expand Down Expand Up @@ -484,7 +506,7 @@ private enum _hashOfStruct =
q{
enum bool isChained = is(typeof(seed) : size_t);
static if (!isChained) enum size_t seed = 0;
static if (hasCallableToHash!T) //CTFE depends on toHash()
static if (hasCallableToHash!(typeof(val))) //CTFE depends on toHash()
{
static if (isChained)
return hashOf(cast(size_t) val.toHash(), seed);
Expand All @@ -495,7 +517,15 @@ q{
{
static if (__traits(hasMember, T, "toHash") && is(typeof(T.toHash) == function))
{
pragma(msg, "Warning: struct "~__traits(identifier, T)~" has method toHash, however it cannot be called with "~T.stringof~" this.");
// TODO: in the future maybe this should be changed to a static
// assert(0), because if there's a `toHash` the programmer probably
// expected it to be called and a compilation failure here will
// expose a bug in his code.
// In the future we also might want to disallow non-const toHash
// altogether.
pragma(msg, "Warning: struct "~__traits(identifier, T)
~" has method toHash, however it cannot be called with "
~typeof(val).stringof~" this.");
}

static if (T.tupleof.length == 0)
Expand Down Expand Up @@ -531,6 +561,7 @@ q{
//struct or union hash
size_t hashOf(T)(scope const auto ref T val, size_t seed = 0)
if (!is(T == enum) && (is(T == struct) || is(T == union))
&& !is(T == const) && !is(T == immutable)
&& canBitwiseHash!T)
{
mixin(_hashOfStruct);
Expand All @@ -552,6 +583,15 @@ if (!is(T == enum) && (is(T == struct) || is(T == union))
mixin(_hashOfStruct);
}

//struct or union hash - https://issues.dlang.org/show_bug.cgi?id=19332 (support might be removed in future)
size_t hashOf(T)(scope auto ref T val, size_t seed = 0)
if (!is(T == enum) && (is(T == struct) || is(T == union))
&& (is(T == const) || is(T == immutable))
&& canBitwiseHash!T && !canBitwiseHash!(Unconst!T))
{
mixin(_hashOfStruct);
}

//delegate hash. CTFE unsupported
@trusted @nogc nothrow pure
size_t hashOf(T)(scope const T val, size_t seed = 0) if (!is(T == enum) && is(T == delegate))
Expand Down
43 changes: 18 additions & 25 deletions libphobos/libdruntime/core/internal/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -128,45 +128,38 @@ template dtorIsNothrow(T)
enum dtorIsNothrow = is(typeof(function{T t=void;}) : void function() nothrow);
}

/*
Tests whether all given items satisfy a template predicate, i.e. evaluates to
$(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])).
*/
// taken from std.meta.allSatisfy
package(core.internal)
template allSatisfy(alias F, T...)
{
static if (T.length == 0)
{
enum allSatisfy = true;
}
else static if (T.length == 1)
static foreach (Ti; T)
{
enum allSatisfy = F!(T[0]);
static if (!is(typeof(allSatisfy) == bool) && // not yet defined
!F!(Ti))
{
enum allSatisfy = false;
}
}
else
static if (!is(typeof(allSatisfy) == bool)) // if not yet defined
{
static if (allSatisfy!(F, T[0 .. $/2]))
enum allSatisfy = allSatisfy!(F, T[$/2 .. $]);
else
enum allSatisfy = false;
enum allSatisfy = true;
}
}

// taken from std.meta.anySatisfy
template anySatisfy(alias F, T...)
{
static if (T.length == 0)
{
enum anySatisfy = false;
}
else static if (T.length == 1)
static foreach (Ti; T)
{
enum anySatisfy = F!(T[0]);
static if (!is(typeof(anySatisfy) == bool) && // not yet defined
F!(Ti))
{
enum anySatisfy = true;
}
}
else
static if (!is(typeof(anySatisfy) == bool)) // if not yet defined
{
enum anySatisfy =
anySatisfy!(F, T[ 0 .. $/2]) ||
anySatisfy!(F, T[$/2 .. $ ]);
enum anySatisfy = false;
}
}

Expand Down
19 changes: 19 additions & 0 deletions libphobos/libdruntime/core/sys/freebsd/unistd.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//Written in the D programming language

/++
D header file for FreeBSD's extensions to POSIX's unistd.h.
Copyright: Copyright 2018
License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
Authors: $(HTTP jmdavisprog.com, Jonathan M Davis)
+/
module core.sys.freebsd.unistd;

public import core.sys.posix.unistd;

version (FreeBSD):
extern(C):
@nogc:
nothrow:

int getosreldate() pure @trusted;
59 changes: 55 additions & 4 deletions libphobos/libdruntime/core/sys/posix/aio.d
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ version (CRuntime_Glibc)
}
}
}
else version (OSX)
{
struct aiocb
{
int aio_filedes;
off_t aio_offset;
void* aio_buf; // volatile
size_t aio_nbytes;
int reqprio;
sigevent aio_sigevent;
int aio_lio_opcode;
}
}
else version (FreeBSD)
{
struct __aiocb_private
Expand Down Expand Up @@ -127,11 +140,32 @@ else
static assert(false, "Unsupported platform");

/* Return values of cancelation function. */
enum
version (CRuntime_Glibc)
{
AIO_CANCELED,
AIO_NOTCANCELED,
AIO_ALLDONE
enum
{
AIO_CANCELED,
AIO_NOTCANCELED,
AIO_ALLDONE
}
}
else version (OSX)
{
enum
{
AIO_ALLDONE = 0x1,
AIO_CANCELED = 0x2,
AIO_NOTCANCELED = 0x4,
}
}
else version (BSD_Posix)
{
enum
{
AIO_CANCELED,
AIO_NOTCANCELED,
AIO_ALLDONE
}
}

/* Operation codes for `aio_lio_opcode'. */
Expand All @@ -144,6 +178,15 @@ version (CRuntime_Glibc)
LIO_NOP
}
}
else version (OSX)
{
enum
{
LIO_NOP = 0x0,
LIO_READ = 0x1,
LIO_WRITE = 0x2,
}
}
else version (BSD_Posix)
{
enum
Expand All @@ -163,6 +206,14 @@ version (CRuntime_Glibc)
LIO_NOWAIT
}
}
else version (OSX)
{
enum
{
LIO_NOWAIT = 0x1,
LIO_WAIT = 0x2,
}
}
else version (BSD_Posix)
{
enum
Expand Down
8 changes: 8 additions & 0 deletions libphobos/libdruntime/core/sys/posix/signal.d
Original file line number Diff line number Diff line change
Expand Up @@ -3552,6 +3552,14 @@ else version (DragonFlyBSD)
}
else version (Darwin)
{
struct sigevent
{
int sigev_notify;
int sigev_signo;
sigval sigev_value;
void function(sigval) sigev_notify_function;
pthread_attr_t* sigev_notify_attributes;
}
}
else version (Solaris)
{
Expand Down
370 changes: 370 additions & 0 deletions libphobos/libdruntime/core/sys/posix/spawn.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,370 @@
/**
* D header file for spawn.h.
*
* Copyright: Copyright (C) 2018 by The D Language Foundation, All Rights Reserved
* Authors: Petar Kirov
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Source: $(LINK2 https://github.com/dlang/druntime/blob/master/src/core/sys/posix/spawn.d, _spawn.d)
* Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
*/
module core.sys.posix.spawn;

/*
Based on the following system headers:
Glibc: https://sourceware.org/git/?p=glibc.git;a=blob;f=posix/spawn.h;hb=HEAD
Bionic libc: https://android.googlesource.com/platform/bionic.git/+/master/libc/include/spawn.h
Musl libc: https://git.musl-libc.org/cgit/musl/tree/include/spawn.h
uClibc: https://git.uclibc.org/uClibc/tree/include/spawn.h
Darwin XNU:
https://opensource.apple.com/source/xnu/xnu-4570.71.2/libsyscall/wrappers/spawn/spawn.h.auto.html
https://opensource.apple.com/source/xnu/xnu-4570.71.2/bsd/sys/spawn.h.auto.html
https://github.com/opensource-apple/xnu (GitHub mirror)
FreeBSD: https://github.com/freebsd/freebsd/blob/master/include/spawn.h
NetBSD: https://github.com/NetBSD/src/blob/trunk/sys/sys/spawn.h
OpenBSD: https://github.com/openbsd/src/blob/master/include/spawn.h
DragonFlyBSD: https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/include/spawn.h
Solaris: https://github.com/illumos/illumos-gate/blob/master/usr/src/head/spawn.h
*/

version (OSX) // macOS and iOS only as this API is prohibited on WatchOS and TVOS
version = Darwin;
else version (iOS)
version = Darwin;

version (Posix):
public import core.sys.posix.sys.types : mode_t, pid_t;
public import core.sys.posix.signal : sigset_t;
public import core.sys.posix.sched : sched_param;

extern(C):
@nogc:
nothrow:

int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t*, int);
int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t*, int, int);
int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t*, int, const char*, int, mode_t);
int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t*);
int posix_spawn_file_actions_init(posix_spawn_file_actions_t*);
int posix_spawnattr_destroy(posix_spawnattr_t*);
int posix_spawnattr_getflags(const posix_spawnattr_t*, short*);
int posix_spawnattr_getpgroup(const posix_spawnattr_t*, pid_t*);

version (Darwin)
{ } // Not supported
else
{
int posix_spawnattr_getschedparam(const posix_spawnattr_t*, sched_param*);
int posix_spawnattr_getschedpolicy(const posix_spawnattr_t*, int*);
int posix_spawnattr_setschedparam(posix_spawnattr_t*, const sched_param*);
int posix_spawnattr_setschedpolicy(posix_spawnattr_t*, int);
}

int posix_spawnattr_getsigdefault(const posix_spawnattr_t*, sigset_t*);
int posix_spawnattr_getsigmask(const posix_spawnattr_t*, sigset_t*);
int posix_spawnattr_init(posix_spawnattr_t*);
int posix_spawnattr_setflags(posix_spawnattr_t*, short);
int posix_spawnattr_setpgroup(posix_spawnattr_t*, pid_t);
int posix_spawnattr_setsigdefault(posix_spawnattr_t*, const sigset_t*);
int posix_spawnattr_setsigmask(posix_spawnattr_t*, const sigset_t*);
int posix_spawn(pid_t*pid, const char* path,
const posix_spawn_file_actions_t* file_actions,
const posix_spawnattr_t* attrp,
const char** argv, const char** envp);
int posix_spawnp(pid_t* pid, const char* file,
const posix_spawn_file_actions_t* file_actions,
const posix_spawnattr_t* attrp,
const char** argv, const char** envp);

version (linux)
{
version (CRuntime_Glibc)
{
// Source: https://sourceware.org/git/?p=glibc.git;a=blob;f=posix/spawn.h;hb=HEAD
enum
{
POSIX_SPAWN_RESETIDS = 0x01,
POSIX_SPAWN_SETPGROUP = 0x02,
POSIX_SPAWN_SETSIGDEF = 0x04,
POSIX_SPAWN_SETSIGMASK = 0x08,
POSIX_SPAWN_SETSCHEDPARAM = 0x10,
POSIX_SPAWN_SETSCHEDULER = 0x20
}
import core.sys.posix.config : __USE_GNU;
static if (__USE_GNU)
{
enum
{
POSIX_SPAWN_USEVFORK = 0x40,
POSIX_SPAWN_SETSID = 0x80
}
}
struct posix_spawnattr_t
{
short __flags;
pid_t __pgrp;
sigset_t __sd;
sigset_t __ss;
sched_param __sp;
int __policy;
int[16] __pad;
}
struct __spawn_action;
struct posix_spawn_file_actions_t
{
int __allocated;
int __used;
__spawn_action* __actions;
int[16] __pad;
}
}
else version (CRuntime_Bionic)
{
// Source: https://android.googlesource.com/platform/bionic.git/+/master/libc/include/spawn.h
enum
{
POSIX_SPAWN_RESETIDS = 1,
POSIX_SPAWN_SETPGROUP = 2,
POSIX_SPAWN_SETSIGDEF = 4,
POSIX_SPAWN_SETSIGMASK = 8,
POSIX_SPAWN_SETSCHEDPARAM = 16,
POSIX_SPAWN_SETSCHEDULER = 32
}
import core.sys.posix.config : __USE_GNU;
static if (__USE_GNU)
{
enum
{
POSIX_SPAWN_USEVFORK = 64,
POSIX_SPAWN_SETSID = 128
}
}
alias posix_spawnattr_t = __posix_spawnattr*;
alias posix_spawn_file_actions_t = __posix_spawn_file_actions*;
struct __posix_spawnattr;
struct __posix_spawn_file_actions;
}
else version (CRuntime_Musl)
{
// Source: https://git.musl-libc.org/cgit/musl/tree/include/spawn.h
enum
{
POSIX_SPAWN_RESETIDS = 1,
POSIX_SPAWN_SETPGROUP = 2,
POSIX_SPAWN_SETSIGDEF = 4,
POSIX_SPAWN_SETSIGMASK = 8,
POSIX_SPAWN_SETSCHEDPARAM = 16,
POSIX_SPAWN_SETSCHEDULER = 32,
POSIX_SPAWN_USEVFORK = 64,
POSIX_SPAWN_SETSID = 128
}
struct posix_spawnattr_t
{
int __flags;
pid_t __pgrp;
sigset_t __def, __mask;
int __prio, __pol;
void* __fn;
char[64 - (void*).sizeof] __pad;
}
struct posix_spawn_file_actions_t
{
int[2] __pad0;
void* __actions;
int[16] __pad;
}
}
else version (CRuntime_UClibc)
{
// Source: https://git.uclibc.org/uClibc/tree/include/spawn.h
enum
{
POSIX_SPAWN_RESETIDS = 0x01,
POSIX_SPAWN_SETPGROUP = 0x02,
POSIX_SPAWN_SETSIGDEF = 0x04,
POSIX_SPAWN_SETSIGMASK = 0x08,
POSIX_SPAWN_SETSCHEDPARAM = 0x10,
POSIX_SPAWN_SETSCHEDULER = 0x20
}
import core.sys.posix.config : __USE_GNU;
static if (__USE_GNU)
{
enum
{
POSIX_SPAWN_USEVFORK = 0x40,
}
}
struct posix_spawnattr_t
{
short __flags;
pid_t __pgrp;
sigset_t __sd;
sigset_t __ss;
sched_param __sp;
int __policy;
int[16] __pad;
}
struct posix_spawn_file_actions_t
{
int __allocated;
int __used;
__spawn_action* __actions;
int[16] __pad;
}
}
else
static assert(0, "Unsupported Linux libc");
}
else version (Darwin)
{
// Sources:
// https://opensource.apple.com/source/xnu/xnu-4570.71.2/libsyscall/wrappers/spawn/spawn.h.auto.html
// https://opensource.apple.com/source/xnu/xnu-4570.71.2/bsd/sys/spawn.h.auto.html
enum
{
POSIX_SPAWN_RESETIDS = 0x01,
POSIX_SPAWN_SETPGROUP = 0x02,
POSIX_SPAWN_SETSIGDEF = 0x04,
POSIX_SPAWN_SETSIGMASK = 0x08,
// POSIX_SPAWN_SETSCHEDPARAM = 0x10, // not supported
// POSIX_SPAWN_SETSCHEDULER = 0x20, // ditto
POSIX_SPAWN_SETEXEC = 0x40,
POSIX_SPAWN_START_SUSPENDED = 0x80
}
alias posix_spawnattr_t = void*;
alias posix_spawn_file_actions_t = void*;
}
else version (FreeBSD)
{
// Source: https://github.com/freebsd/freebsd/blob/master/include/spawn.h
enum
{
POSIX_SPAWN_RESETIDS = 0x01,
POSIX_SPAWN_SETPGROUP = 0x02,
POSIX_SPAWN_SETSCHEDPARAM = 0x04,
POSIX_SPAWN_SETSCHEDULER = 0x08,
POSIX_SPAWN_SETSIGDEF = 0x10,
POSIX_SPAWN_SETSIGMASK = 0x20
}
alias posix_spawnattr_t = void*;
alias posix_spawn_file_actions_t = void*;
}
else version (NetBSD)
{
// Source: https://github.com/NetBSD/src/blob/trunk/sys/sys/spawn.h
enum
{
POSIX_SPAWN_RESETIDS = 0x01,
POSIX_SPAWN_SETPGROUP = 0x02,
POSIX_SPAWN_SETSCHEDPARAM = 0x04,
POSIX_SPAWN_SETSCHEDULER = 0x08,
POSIX_SPAWN_SETSIGDEF = 0x10,
POSIX_SPAWN_SETSIGMASK = 0x20,
POSIX_SPAWN_RETURNERROR = 0x40 // NetBSD specific
}
struct posix_spawnattr
{
short sa_flags;
pid_t sa_pgroup;
sched_param sa_schedparam;
int sa_schedpolicy;
sigset_t sa_sigdefault;
sigset_t sa_sigmask;
}
struct posix_spawn_file_actions_entry_t;
struct posix_spawn_file_actions
{
uint size;
uint len;
posix_spawn_file_actions_entry_t* fae;
}
}
else version (OpenBSD)
{
// Source: https://github.com/openbsd/src/blob/master/include/spawn.h
enum
{
POSIX_SPAWN_RESETIDS = 0x01,
POSIX_SPAWN_SETPGROUP = 0x02,
POSIX_SPAWN_SETSCHEDPARAM = 0x04,
POSIX_SPAWN_SETSCHEDULER = 0x08,
POSIX_SPAWN_SETSIGDEF = 0x10,
POSIX_SPAWN_SETSIGMASK = 0x20
}
alias posix_spawnattr_t = __posix_spawnattr*;
alias posix_spawn_file_actions_t = __posix_spawn_file_actions*;
struct __posix_spawnattr;
struct __posix_spawn_file_actions;
}
else version (DragonFlyBSD)
{
// Source: https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/include/spawn.h
enum
{
POSIX_SPAWN_RESETIDS = 0x01,
POSIX_SPAWN_SETPGROUP = 0x02,
POSIX_SPAWN_SETSCHEDPARAM = 0x04,
POSIX_SPAWN_SETSCHEDULER = 0x08,
POSIX_SPAWN_SETSIGDEF = 0x10,
POSIX_SPAWN_SETSIGMASK = 0x20
}
alias posix_spawnattr_t = __posix_spawnattr*;
alias posix_spawn_file_actions_t = __posix_spawn_file_actions*;
struct __posix_spawnattr;
struct __posix_spawn_file_actions;
}
else version (Solaris)
{
// Source: https://github.com/illumos/illumos-gate/blob/master/usr/src/head/spawn.h
enum
{
POSIX_SPAWN_RESETIDS = 0x01,
POSIX_SPAWN_SETPGROUP = 0x02,
POSIX_SPAWN_SETSIGDEF = 0x04,
POSIX_SPAWN_SETSIGMASK = 0x08,
POSIX_SPAWN_SETSCHEDPARAM = 0x10,
POSIX_SPAWN_SETSCHEDULER = 0x20,
}
version (none)
{
// Non-portable Solaris extensions.
enum
{
POSIX_SPAWN_SETSIGIGN_NP = 0x0800,
POSIX_SPAWN_NOSIGCHLD_NP = 0x1000,
POSIX_SPAWN_WAITPID_NP = 0x2000,
POSIX_SPAWN_NOEXECERR_NP = 0x4000,
}
}
struct posix_spawnattr_t
{
void* __spawn_attrp;
}
struct posix_spawn_file_actions_t
{
void* __file_attrp;
}
version (none)
{
// Non-portable Solaris extensions.
alias boolean_t = int;
int posix_spawn_file_actions_addclosefrom_np(posix_spawn_file_actions_t* file_actions,
int lowfiledes);
int posix_spawn_pipe_np(pid_t* pidp, int* fdp, const char* cmd, boolean_t write,
posix_spawn_file_actions_t* fact,
posix_spawnattr_t* attr);
int posix_spawnattr_getsigignore_np(const posix_spawnattr_t* attr, sigset_t* sigignore);
int posix_spawnattr_setsigignore_np(posix_spawnattr_t* attr, const sigset_t* sigignore);
}
}
else
static assert(0, "Unsupported OS");
8 changes: 6 additions & 2 deletions libphobos/libdruntime/core/thread.d
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,10 @@ class Thread
*/
~this() nothrow @nogc
{
if ( m_addr == m_addr.init )
bool no_context = m_addr == m_addr.init;
bool not_registered = !next && !prev && (sm_tbeg !is this);

if (no_context || not_registered)
{
return;
}
Expand Down Expand Up @@ -1860,8 +1863,9 @@ private:
do
{
// Thread was already removed earlier, might happen b/c of thread_detachInstance
if (!t.next && !t.prev)
if (!t.next && !t.prev && (sm_tbeg !is t))
return;

slock.lock_nothrow();
{
// NOTE: When a thread is removed from the global thread list its
Expand Down
8 changes: 8 additions & 0 deletions libphobos/libdruntime/gc/impl/conservative/gc.d
Original file line number Diff line number Diff line change
Expand Up @@ -2384,6 +2384,14 @@ struct Gcx
*/
size_t fullcollect(bool nostack = false) nothrow
{
// It is possible that `fullcollect` will be called from a thread which
// is not yet registered in runtime (because allocating `new Thread` is
// part of `thread_attachThis` implementation). In that case it is
// better not to try actually collecting anything

if (Thread.getThis() is null)
return 0;

MonoTime start, stop, begin;

if (config.profile)
Expand Down
4 changes: 4 additions & 0 deletions libphobos/src/MERGE
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
f961aa86863938c964baea345684309b85021000

The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
4 changes: 2 additions & 2 deletions libphobos/src/std/algorithm/mutation.d
Original file line number Diff line number Diff line change
Expand Up @@ -1644,8 +1644,8 @@ concerns the swapping of elements that are not the core concern of the
algorithm. For example, consider an algorithm that sorts $(D [ "abc",
"b", "aBc" ]) according to `toUpper(a) < toUpper(b)`. That
algorithm might choose to swap the two equivalent strings `"abc"`
and `"aBc"`. That does not affect the sorting since both `$D(
"abc", "aBc", "b" ]) and `[ "aBc", "abc", "b" ]` are valid
and `"aBc"`. That does not affect the sorting since both
`["abc", "aBc", "b" ]` and `[ "aBc", "abc", "b" ]` are valid
outcomes.
Some situations require that the algorithm must NOT ever change the
Expand Down
21 changes: 11 additions & 10 deletions libphobos/src/std/algorithm/sorting.d
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,9 @@ Returns:
The right part of `r` after partitioning.
If `ss == SwapStrategy.stable`, `partition` preserves the relative
ordering of all elements `a`, `b` in `r` for which `predicate(a) =$D(
predicate(b)). If `ss == SwapStrategy.semistable`, `partition` preserves
ordering of all elements `a`, `b` in `r` for which
`predicate(a) == predicate(b)`.
If `ss == SwapStrategy.semistable`, `partition` preserves
the relative ordering of all elements `a`, `b` in the left part of `r`
for which `predicate(a) == predicate(b)`.
*/
Expand Down Expand Up @@ -943,8 +944,9 @@ Params:
index = The resulting index.
Returns: The pointer-based version returns a `SortedRange` wrapper
over index, of type `SortedRange!(RangeIndex, (a, b) =$D(
binaryFun!less(*a, *b))) thus reflecting the ordering of the
over index, of type
`SortedRange!(RangeIndex, (a, b) => binaryFun!less(*a, *b))`
thus reflecting the ordering of the
index. The index-based version returns `void` because the ordering
relation involves not only `index` but also `r`.
Expand Down Expand Up @@ -2896,8 +2898,7 @@ Params:
r = The range to sort.
Returns: The initial range wrapped as a `SortedRange` with the
predicate `(a, b) => binaryFun!less(transform(a)$D(
transform(b))).
predicate `(a, b) => binaryFun!less(transform(a), transform(b))`.
*/
SortedRange!(R, ((a, b) => binaryFun!less(unaryFun!transform(a),
unaryFun!transform(b))))
Expand Down Expand Up @@ -3014,8 +3015,8 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R)

// partialSort
/**
Reorders the random-access range `r` such that the range `r[$D(
.. mid]) is the same as if the entire `r` were sorted, and leaves
Reorders the random-access range `r` such that the range `r[0 .. mid]`
is the same as if the entire `r` were sorted, and leaves
the range `r[mid .. r.length]` in no particular order. Performs
$(BIGOH r.length * log(mid)) evaluations of `pred`. The
implementation simply calls `topN!(less, ss)(r, n)` and then $(D
Expand Down Expand Up @@ -3669,8 +3670,8 @@ if (isRandomAccessRange!(Range1) && hasLength!Range1 &&
/**
Copies the top `n` elements of the
$(REF_ALTTEXT input range, isInputRange, std,range,primitives) `source` into the
random-access range `target`, where `n $D(
target.length). Elements of `source` are not touched. If $(D
random-access range `target`, where `n = target.length`.
Elements of `source` are not touched. If $(D
sorted) is `true`, the target is sorted. Otherwise, the target
respects the $(HTTP en.wikipedia.org/wiki/Binary_heap, heap property).
Expand Down
190 changes: 178 additions & 12 deletions libphobos/src/std/array.d
Original file line number Diff line number Diff line change
Expand Up @@ -410,16 +410,25 @@ if (isNarrowString!String)
}

/**
Returns a newly allocated associative array from a range of key/value tuples.
Returns a newly allocated associative array from a range of key/value tuples
or from a range of keys and a range of values.
Params:
r = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
of tuples of keys and values.
Returns: A newly allocated associative array out of elements of the input
range, which must be a range of tuples (Key, Value). Returns a null associative
array reference when given an empty range.
Duplicates: Associative arrays have unique keys. If r contains duplicate keys,
then the result will contain the value of the last pair for that key in r.
keys = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of keys
values = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of values
Returns:
A newly allocated associative array out of elements of the input
range, which must be a range of tuples (Key, Value) or
a range of keys and a range of values. If given two ranges of unequal
lengths after the elements of the shorter are exhausted the remaining
elements of the longer will not be considered.
Returns a null associative array reference when given an empty range.
Duplicates: Associative arrays have unique keys. If r contains duplicate keys,
then the result will contain the value of the last pair for that key in r.
See_Also: $(REF Tuple, std,typecons), $(REF zip, std,range)
*/
Expand All @@ -442,18 +451,98 @@ if (isInputRange!Range)
return aa;
}

/// ditto
auto assocArray(Keys, Values)(Keys keys, Values values)
if (isInputRange!Values && isInputRange!Keys)
{
static if (isDynamicArray!Keys && isDynamicArray!Values
&& !isNarrowString!Keys && !isNarrowString!Values)
{
void* aa;
{
// aaLiteral is nothrow when the destructors don't throw
static if (is(typeof(() nothrow
{
import std.range : ElementType;
import std.traits : hasElaborateDestructor;
alias KeyElement = ElementType!Keys;
static if (hasElaborateDestructor!KeyElement)
KeyElement.init.__xdtor();

alias ValueElement = ElementType!Values;
static if (hasElaborateDestructor!ValueElement)
ValueElement.init.__xdtor();
})))
{
scope(failure) assert(0);
}
if (values.length > keys.length)
values = values[0 .. keys.length];
else if (keys.length > values.length)
keys = keys[0 .. values.length];
aa = aaLiteral(keys, values);
}
alias Key = typeof(keys[0]);
alias Value = typeof(values[0]);
return (() @trusted => cast(Value[Key]) aa)();
}
else
{
// zip is not always able to infer nothrow
alias Key = ElementType!Keys;
alias Value = ElementType!Values;
static assert(isMutable!Value, "assocArray: value type must be mutable");
Value[Key] aa;
foreach (key; keys)
{
if (values.empty) break;

// aa[key] is incorrectly not @safe if the destructor throws
// https://issues.dlang.org/show_bug.cgi?id=18592
static if (is(typeof(() @safe
{
import std.range : ElementType;
import std.traits : hasElaborateDestructor;
alias KeyElement = ElementType!Keys;
static if (hasElaborateDestructor!KeyElement)
KeyElement.init.__xdtor();

alias ValueElement = ElementType!Values;
static if (hasElaborateDestructor!ValueElement)
ValueElement.init.__xdtor();
})))
{
() @trusted {
aa[key] = values.front;
}();
}
else
{
aa[key] = values.front;
}
values.popFront();
}
return aa;
}
}

///
@safe pure /*nothrow*/ unittest
{
import std.range;
import std.typecons;
import std.range : repeat, zip;
import std.typecons : tuple;
auto a = assocArray(zip([0, 1, 2], ["a", "b", "c"])); // aka zipMap
assert(is(typeof(a) == string[int]));
static assert(is(typeof(a) == string[int]));
assert(a == [0:"a", 1:"b", 2:"c"]);

auto b = assocArray([ tuple("foo", "bar"), tuple("baz", "quux") ]);
assert(is(typeof(b) == string[string]));
static assert(is(typeof(b) == string[string]));
assert(b == ["foo":"bar", "baz":"quux"]);

auto c = assocArray("ABCD", true.repeat);
static assert(is(typeof(c) == bool[dchar]));
bool[dchar] expected = ['D':true, 'A':true, 'B':true, 'C':true];
assert(c == expected);
}

// @@@11053@@@ - Cannot be version (unittest) - recursive instantiation error
Expand All @@ -476,6 +565,79 @@ if (isInputRange!Range)
static assert(!__traits(compiles, assocArray(b)));
}

// https://issues.dlang.org/show_bug.cgi?id=5502
@safe unittest
{
auto a = assocArray([0, 1, 2], ["a", "b", "c"]);
static assert(is(typeof(a) == string[int]));
assert(a == [0:"a", 1:"b", 2:"c"]);

auto b = assocArray([0, 1, 2], [3L, 4, 5]);
static assert(is(typeof(b) == long[int]));
assert(b == [0: 3L, 1: 4, 2: 5]);
}

// https://issues.dlang.org/show_bug.cgi?id=5502
@safe unittest
{
import std.algorithm.iteration : filter, map;
import std.range : enumerate;

auto r = "abcde".enumerate.filter!(a => a.index == 2);
auto a = assocArray(r.map!(a => a.value), r.map!(a => a.index));
assert(is(typeof(a) == size_t[dchar]));
assert(a == [dchar('c'): size_t(2)]);
}

@safe nothrow pure unittest
{
import std.range : iota;
auto b = assocArray(3.iota, 3.iota(6));
static assert(is(typeof(b) == int[int]));
assert(b == [0: 3, 1: 4, 2: 5]);

b = assocArray([0, 1, 2], [3, 4, 5]);
assert(b == [0: 3, 1: 4, 2: 5]);
}

@safe unittest
{
struct ThrowingElement
{
int i;
static bool b;
~this(){
if (b)
throw new Exception("");
}
}
static assert(!__traits(compiles, () nothrow { assocArray([ThrowingElement()], [0]);}));
assert(assocArray([ThrowingElement()], [0]) == [ThrowingElement(): 0]);

static assert(!__traits(compiles, () nothrow { assocArray([0], [ThrowingElement()]);}));
assert(assocArray([0], [ThrowingElement()]) == [0: ThrowingElement()]);

import std.range : iota;
static assert(!__traits(compiles, () nothrow { assocArray(1.iota, [ThrowingElement()]);}));
assert(assocArray(1.iota, [ThrowingElement()]) == [0: ThrowingElement()]);
}

@system unittest
{
import std.range : iota;
struct UnsafeElement
{
int i;
static bool b;
~this(){
int[] arr;
void* p = arr.ptr + 1; // unsafe
}
}
static assert(!__traits(compiles, () @safe { assocArray(1.iota, [UnsafeElement()]);}));
assert(assocArray(1.iota, [UnsafeElement()]) == [0: UnsafeElement()]);
}

/**
Construct a range iterating over an associative array by key/value tuples.
Expand Down Expand Up @@ -708,8 +870,12 @@ if (isDynamicArray!T && allSatisfy!(isIntegral, I))

auto arr = minimallyInitializedArray!(int[])(42);
assert(arr.length == 42);
// Elements aren't necessarily initialized to 0
assert(!arr.equal(0.repeat(42)));

// Elements aren't necessarily initialized to 0, so don't do this:
// assert(arr.equal(0.repeat(42)));
// If that is needed, initialize the array normally instead:
auto arr2 = new int[42];
assert(arr2.equal(0.repeat(42)));
}

@safe pure nothrow unittest
Expand Down
20 changes: 15 additions & 5 deletions libphobos/src/std/bitmanip.d
Original file line number Diff line number Diff line change
Expand Up @@ -1362,11 +1362,18 @@ public:
*/
size_t count()
{
size_t bitCount;
foreach (i; 0 .. fullWords)
bitCount += countBitsSet(_ptr[i]);
bitCount += countBitsSet(_ptr[fullWords] & endMask);
return bitCount;
if (_ptr)
{
size_t bitCount;
foreach (i; 0 .. fullWords)
bitCount += countBitsSet(_ptr[i]);
bitCount += countBitsSet(_ptr[fullWords] & endMask);
return bitCount;
}
else
{
return 0;
}
}

///
Expand All @@ -1375,6 +1382,9 @@ public:
auto a = BitArray([0, 1, 1, 0, 0, 1, 1]);
assert(a.count == 4);

BitArray b;
assert(b.count == 0);

bool[200] boolArray;
boolArray[45 .. 130] = true;
auto c = BitArray(boolArray);
Expand Down
25 changes: 19 additions & 6 deletions libphobos/src/std/concurrency.d
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,26 @@ import std.traits;

private
{
template hasLocalAliasing(T...)
bool hasLocalAliasing(Types...)()
{
static if (!T.length)
enum hasLocalAliasing = false;
else
enum hasLocalAliasing = (std.traits.hasUnsharedAliasing!(T[0]) && !is(T[0] == Tid)) ||
std.concurrency.hasLocalAliasing!(T[1 .. $]);
// Works around "statement is not reachable"
bool doesIt = false;
static foreach (T; Types)
{
static if (is(T == Tid))
{ /* Allowed */ }
else static if (is(T == struct))
doesIt |= hasLocalAliasing!(typeof(T.tupleof));
else
doesIt |= std.traits.hasUnsharedAliasing!(T);
}
return doesIt;
}

@safe unittest
{
static struct Container { Tid t; }
static assert(!hasLocalAliasing!(Tid, Container, int));
}

enum MsgType
Expand Down
49 changes: 35 additions & 14 deletions libphobos/src/std/datetime/date.d
Original file line number Diff line number Diff line change
Expand Up @@ -1053,8 +1053,8 @@ public:


/++
Adds the given number of years or months to this $(LREF DateTime). A
negative number will subtract.
Adds the given number of years or months to this $(LREF DateTime),
mutating it. A negative number will subtract.

Note that if day overflow is allowed, and the date with the adjusted
year/month overflows the number of days in the new month, then the month
Expand All @@ -1070,6 +1070,9 @@ public:
$(LREF DateTime).
allowOverflow = Whether the days should be allowed to overflow,
causing the month to increment.

Returns:
A reference to the `DateTime` (`this`).
+/
ref DateTime add(string units)
(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow @nogc
Expand Down Expand Up @@ -1115,8 +1118,8 @@ public:


/++
Adds the given number of years or months to this $(LREF DateTime). A
negative number will subtract.
Adds the given number of years or months to this $(LREF DateTime),
mutating it. A negative number will subtract.

The difference between rolling and adding is that rolling does not
affect larger units. Rolling a $(LREF DateTime) 12 months
Expand All @@ -1132,6 +1135,9 @@ public:
$(LREF DateTime).
allowOverflow = Whether the days should be allowed to overflow,
causing the month to increment.

Returns:
A reference to the `DateTime` (`this`).
+/
ref DateTime roll(string units)
(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow @nogc
Expand Down Expand Up @@ -1185,8 +1191,8 @@ public:


/++
Adds the given number of units to this $(LREF DateTime). A negative
number will subtract.
Adds the given number of units to this $(LREF DateTime), mutating it. A
negative number will subtract.

The difference between rolling and adding is that rolling does not
affect larger units. For instance, rolling a $(LREF DateTime) one
Expand All @@ -1199,6 +1205,9 @@ public:
units = The units to add.
value = The number of $(D_PARAM units) to add to this
$(LREF DateTime).

Returns:
A reference to the `DateTime` (`this`).
+/
ref DateTime roll(string units)(long value) @safe pure nothrow @nogc
if (units == "days")
Expand Down Expand Up @@ -4436,8 +4445,8 @@ public:


/++
Adds the given number of years or months to this $(LREF Date). A
negative number will subtract.
Adds the given number of years or months to this $(LREF Date), mutating
it. A negative number will subtract.

Note that if day overflow is allowed, and the date with the adjusted
year/month overflows the number of days in the new month, then the month
Expand All @@ -4453,6 +4462,9 @@ public:
$(LREF Date).
allowOverflow = Whether the day should be allowed to overflow,
causing the month to increment.

Returns:
A reference to the `Date` (`this`).
+/
@safe pure nothrow @nogc
ref Date add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
Expand Down Expand Up @@ -5218,8 +5230,8 @@ public:


/++
Adds the given number of years or months to this $(LREF Date). A negative
number will subtract.
Adds the given number of years or months to this $(LREF Date), mutating
it. A negative number will subtract.

The difference between rolling and adding is that rolling does not
affect larger units. Rolling a $(LREF Date) 12 months gets
Expand All @@ -5235,6 +5247,9 @@ public:
$(LREF Date).
allowOverflow = Whether the day should be allowed to overflow,
causing the month to increment.

Returns:
A reference to the `Date` (`this`).
+/
@safe pure nothrow @nogc
ref Date roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
Expand Down Expand Up @@ -5863,8 +5878,8 @@ public:


/++
Adds the given number of units to this $(LREF Date). A negative number
will subtract.
Adds the given number of units to this $(LREF Date), mutating it. A
negative number will subtract.

The difference between rolling and adding is that rolling does not
affect larger units. For instance, rolling a $(LREF Date) one
Expand All @@ -5875,6 +5890,9 @@ public:
Params:
units = The units to add. Must be `"days"`.
days = The number of days to add to this $(LREF Date).

Returns:
A reference to the `Date` (`this`).
+/
ref Date roll(string units)(long days) @safe pure nothrow @nogc
if (units == "days")
Expand Down Expand Up @@ -8438,8 +8456,8 @@ public:


/++
Adds the given number of units to this $(LREF TimeOfDay). A negative
number will subtract.
Adds the given number of units to this $(LREF TimeOfDay), mutating it. A
negative number will subtract.

The difference between rolling and adding is that rolling does not
affect larger units. For instance, rolling a $(LREF TimeOfDay)
Expand All @@ -8452,6 +8470,9 @@ public:
units = The units to add.
value = The number of $(D_PARAM units) to add to this
$(LREF TimeOfDay).

Returns:
A reference to the `TimeOfDay` (`this`).
+/
ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc
if (units == "hours")
Expand Down
6 changes: 3 additions & 3 deletions libphobos/src/std/internal/math/errorfunction.d
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,7 @@ real normalDistributionImpl(real a)

@safe unittest
{
assert(fabs(normalDistributionImpl(1L) - (0.841344746068543))< 0.0000000000000005);
assert(fabs(normalDistributionImpl(1L) - (0.841344746068543)) < 0.0000000000000005);
assert(isIdentical(normalDistributionImpl(NaN(0x325)), NaN(0x325)));
}

Expand Down Expand Up @@ -1130,8 +1130,8 @@ static immutable real[8] Q3 =
{
// TODO: Use verified test points.
// The values below are from Excel 2003.
assert(fabs(normalDistributionInvImpl(0.001) - (-3.09023230616779))< 0.00000000000005);
assert(fabs(normalDistributionInvImpl(1e-50) - (-14.9333375347885))< 0.00000000000005);
assert(fabs(normalDistributionInvImpl(0.001) - (-3.09023230616779)) < 0.00000000000005);
assert(fabs(normalDistributionInvImpl(1e-50) - (-14.9333375347885)) < 0.00000000000005);
assert(feqrel(normalDistributionInvImpl(0.999), -normalDistributionInvImpl(0.001)) > real.mant_dig-6);

// Excel 2003 gets all the following values wrong!
Expand Down
55 changes: 46 additions & 9 deletions libphobos/src/std/json.d
Original file line number Diff line number Diff line change
Expand Up @@ -661,29 +661,66 @@ struct JSONValue
// Default doesn't work well since store is a union. Compare only
// what should be in store.
// This is @trusted to remain nogc, nothrow, fast, and usable from @safe code.
if (type_tag != rhs.type_tag) return false;

final switch (type_tag)
{
case JSONType.string:
return store.str == rhs.store.str;
case JSONType.integer:
return store.integer == rhs.store.integer;
switch (rhs.type_tag)
{
case JSONType.integer:
return store.integer == rhs.store.integer;
case JSONType.uinteger:
return store.integer == rhs.store.uinteger;
case JSONType.float_:
return store.integer == rhs.store.floating;
default:
return false;
}
case JSONType.uinteger:
return store.uinteger == rhs.store.uinteger;
switch (rhs.type_tag)
{
case JSONType.integer:
return store.uinteger == rhs.store.integer;
case JSONType.uinteger:
return store.uinteger == rhs.store.uinteger;
case JSONType.float_:
return store.uinteger == rhs.store.floating;
default:
return false;
}
case JSONType.float_:
return store.floating == rhs.store.floating;
switch (rhs.type_tag)
{
case JSONType.integer:
return store.floating == rhs.store.integer;
case JSONType.uinteger:
return store.floating == rhs.store.uinteger;
case JSONType.float_:
return store.floating == rhs.store.floating;
default:
return false;
}
case JSONType.string:
return type_tag == rhs.type_tag && store.str == rhs.store.str;
case JSONType.object:
return store.object == rhs.store.object;
return type_tag == rhs.type_tag && store.object == rhs.store.object;
case JSONType.array:
return store.array == rhs.store.array;
return type_tag == rhs.type_tag && store.array == rhs.store.array;
case JSONType.true_:
case JSONType.false_:
case JSONType.null_:
return true;
return type_tag == rhs.type_tag;
}
}

///
@safe unittest
{
assert(JSONValue(0u) == JSONValue(0));
assert(JSONValue(0u) == JSONValue(0.0));
assert(JSONValue(0) == JSONValue(0.0));
}

/// Implements the foreach `opApply` interface for json arrays.
int opApply(scope int delegate(size_t index, ref JSONValue) dg) @system
{
Expand Down
6 changes: 4 additions & 2 deletions libphobos/src/std/math.d
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ version (MIPS32) version = MIPS_Any;
version (MIPS64) version = MIPS_Any;
version (AArch64) version = ARM_Any;
version (ARM) version = ARM_Any;
version (SPARC) version = SPARC_Any;
version (SPARC64) version = SPARC_Any;

version (D_InlineAsm_X86)
{
Expand Down Expand Up @@ -6066,7 +6068,7 @@ nothrow @nogc:
| inexactException,
}
}
else version (SPARC64)
else version (SPARC_Any)
{
enum : ExceptionMask
{
Expand Down Expand Up @@ -6208,7 +6210,7 @@ private:
{
alias ControlState = uint;
}
else version (SPARC64)
else version (SPARC_Any)
{
alias ControlState = ulong;
}
Expand Down
62 changes: 24 additions & 38 deletions libphobos/src/std/meta.d
Original file line number Diff line number Diff line change
Expand Up @@ -277,13 +277,13 @@ if (!isAggregateType!T || is(Unqual!T == T))
*/
template staticIndexOf(T, TList...)
{
enum staticIndexOf = genericIndexOf!(T, TList).index;
enum staticIndexOf = genericIndexOf!(T, TList);
}

/// Ditto
template staticIndexOf(alias T, TList...)
{
enum staticIndexOf = genericIndexOf!(T, TList).index;
enum staticIndexOf = genericIndexOf!(T, TList);
}

///
Expand All @@ -303,27 +303,17 @@ template staticIndexOf(alias T, TList...)
private template genericIndexOf(args...)
if (args.length >= 1)
{
alias e = OldAlias!(args[0]);
alias tuple = args[1 .. $];

static if (tuple.length)
static foreach (idx, arg; args[1 .. $])
{
alias head = OldAlias!(tuple[0]);
alias tail = tuple[1 .. $];

static if (isSame!(e, head))
static if (is(typeof(genericIndexOf) == void) && // not yet defined
isSame!(args[0], arg))
{
enum index = 0;
}
else
{
enum next = genericIndexOf!(e, tail).index;
enum index = (next == -1) ? -1 : 1 + next;
enum genericIndexOf = idx;
}
}
else
static if (is(typeof(genericIndexOf) == void)) // no hit
{
enum index = -1;
enum genericIndexOf = -1;
}
}

Expand Down Expand Up @@ -844,19 +834,17 @@ template predicate must be instantiable with all the given items.
*/
template allSatisfy(alias F, T...)
{
static if (T.length == 0)
{
enum allSatisfy = true;
}
else static if (T.length == 1)
static foreach (Ti; T)
{
enum allSatisfy = F!(T[0]);
static if (!is(typeof(allSatisfy) == bool) && // not yet defined
!F!(Ti))
{
enum allSatisfy = false;
}
}
else
static if (!is(typeof(allSatisfy) == bool)) // if not yet defined
{
enum allSatisfy =
allSatisfy!(F, T[ 0 .. $/2]) &&
allSatisfy!(F, T[$/2 .. $ ]);
enum allSatisfy = true;
}
}

Expand All @@ -878,19 +866,17 @@ template predicate must be instantiable with one of the given items.
*/
template anySatisfy(alias F, T...)
{
static if (T.length == 0)
static foreach (Ti; T)
{
enum anySatisfy = false;
}
else static if (T.length == 1)
{
enum anySatisfy = F!(T[0]);
static if (!is(typeof(anySatisfy) == bool) && // not yet defined
F!(Ti))
{
enum anySatisfy = true;
}
}
else
static if (!is(typeof(anySatisfy) == bool)) // if not yet defined
{
enum anySatisfy =
anySatisfy!(F, T[ 0 .. $/2]) ||
anySatisfy!(F, T[$/2 .. $ ]);
enum anySatisfy = false;
}
}

Expand Down
4 changes: 2 additions & 2 deletions libphobos/src/std/regex/internal/ir.d
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ if (!hasElaborateDestructor!T)
return internalSlice[] == a.internalSlice[];
}

size_t toHash()
size_t toHash() const
{
return hashOf(internalSlice[]);
}
Expand Down Expand Up @@ -1117,4 +1117,4 @@ if (!hasElaborateDestructor!T)
a = a;
assert(a.big.refcount == 2); // a & c
}
}
}
36 changes: 22 additions & 14 deletions libphobos/src/std/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -6931,17 +6931,20 @@ template isInstanceOf(alias S, alias T)
*
* See_Also: $(LREF isTypeTuple).
*/
template isExpressions(T ...)
template isExpressions(T...)
{
static if (T.length >= 2)
enum bool isExpressions =
isExpressions!(T[0 .. $/2]) &&
isExpressions!(T[$/2 .. $]);
else static if (T.length == 1)
enum bool isExpressions =
!is(T[0]) && __traits(compiles, { auto ex = T[0]; });
else
enum bool isExpressions = true; // default
static foreach (Ti; T)
{
static if (!is(typeof(isExpressions) == bool) && // not yet defined
(is(Ti) || !__traits(compiles, { auto ex = Ti; })))
{
enum isExpressions = false;
}
}
static if (!is(typeof(isExpressions) == bool)) // if not yet defined
{
enum isExpressions = true;
}
}

///
Expand Down Expand Up @@ -8487,13 +8490,18 @@ private template getSymbolsByUDAImpl(alias symbol, alias attribute, names...)
*/
template allSameType(T...)
{
static if (T.length <= 1)
static foreach (idx, Ti; T)
{
enum bool allSameType = true;
static if (idx + 1 < T.length &&
!is(typeof(allSameType) == bool) &&
!is(T[idx] == T[idx + 1]))
{
enum bool allSameType = false;
}
}
else
static if (!is(typeof(allSameType) == bool))
{
enum bool allSameType = is(T[0] == T[1]) && allSameType!(T[1..$]);
enum bool allSameType = true;
}
}

Expand Down
30 changes: 30 additions & 0 deletions libphobos/testsuite/libphobos.hash/test_hash.d
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ void main()
issue18918();
issue18925();
issue19005();
issue19204();
issue19262();
issue19282();
testTypeInfoArrayGetHash1();
Expand Down Expand Up @@ -87,6 +88,35 @@ void issue19005() @nogc nothrow pure @safe
auto hash = date.hashOf;
}

/// Accept SIMD vectors.
void issue19204() @nogc nothrow pure @safe
{
version (D_SIMD)
{
static import simd = core.simd;
static if (is(simd.int4)) // __traits(isArithmetic)
{{
enum simd.int4 val = [1,2,3,4];
enum ctfeHash = hashOf(val);
simd.int4 rtVal = val;
auto rtHash = hashOf(rtVal);
assert(ctfeHash == rtHash);
}}
static if (is(simd.void16)) // non __traits(isArithmetic)
{{
auto h = hashOf(simd.void16.init);
}}
static if (is(simd.float4)) // __traits(isArithmetic) and __traits(isFloating)
{{
enum simd.float4 val = [1.1f, 2.2f, 3.3f, 4.4f];
enum ctfeHash = hashOf(val);
simd.float4 rtVal = val;
auto rtHash = hashOf(rtVal);
assert(ctfeHash == rtHash);
}}
}
}

/// hashOf associative array should infer nothrow
void issue19262() nothrow
{
Expand Down
50 changes: 50 additions & 0 deletions libphobos/testsuite/libphobos.thread/external_threads.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import core.sys.posix.pthread;
import core.memory;
import core.thread;

extern (C) void rt_moduleTlsCtor();
extern (C) void rt_moduleTlsDtor();

extern(C)
void* entry_point1(void*)
{
// try collecting - GC must ignore this call because this thread
// is not registered in runtime
GC.collect();
return null;
}

extern(C)
void* entry_point2(void*)
{
// This thread gets registered in druntime, does some work and gets
// unregistered to be cleaned up manually
thread_attachThis();
rt_moduleTlsCtor();

auto x = new int[10];

rt_moduleTlsDtor();
thread_detachThis();
return null;
}

void main()
{
// allocate some garbage
auto x = new int[1000];

{
pthread_t thread;
auto status = pthread_create(&thread, null, &entry_point1, null);
assert(status == 0);
pthread_join(thread, null);
}

{
pthread_t thread;
auto status = pthread_create(&thread, null, &entry_point2, null);
assert(status == 0);
pthread_join(thread, null);
}
}