mirror of git://gcc.gnu.org/git/gcc.git
d: Merge upstream dmd, druntime af92b68a81, phobos c970ca67f
D front-end changes: - Import dmd v2.108.1. D runtime changes: - Import druntime v2.108.1. Phobos changes: - Import phobos v2.108.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd af92b68a81. * dmd/VERSION: Bump version to v2.108.1. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime af92b68a81. * src/MERGE: Merge upstream phobos c970ca67f.
This commit is contained in:
parent
bc8569984e
commit
c6b1b62f11
|
@ -1,4 +1,4 @@
|
|||
b65767825f365dbc153457fc86e1054b03196c6d
|
||||
af92b68a81888702896620db1d10ee477b6b31e8
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
|
|
@ -1 +1 @@
|
|||
v2.108.0
|
||||
v2.108.1
|
||||
|
|
|
@ -1919,6 +1919,14 @@ final class CParser(AST) : Parser!AST
|
|||
auto s = cparseFunctionDefinition(id, dt.isTypeFunction(), specifier);
|
||||
typedefTab.setDim(typedefTabLengthSave);
|
||||
symbols = symbolsSave;
|
||||
if (specifier.mod & MOD.x__stdcall)
|
||||
{
|
||||
// If this function is __stdcall, wrap it in a LinkDeclaration so that
|
||||
// it's extern(Windows) when imported in D.
|
||||
auto decls = new AST.Dsymbols(1);
|
||||
(*decls)[0] = s;
|
||||
s = new AST.LinkDeclaration(s.loc, LINK.windows, decls);
|
||||
}
|
||||
symbols.push(s);
|
||||
return;
|
||||
}
|
||||
|
@ -2071,13 +2079,14 @@ final class CParser(AST) : Parser!AST
|
|||
}
|
||||
}
|
||||
s = applySpecifier(s, specifier);
|
||||
if (level == LVL.local)
|
||||
if (level == LVL.local || (specifier.mod & MOD.x__stdcall))
|
||||
{
|
||||
// Wrap the declaration in `extern (C) { declaration }`
|
||||
// Wrap the declaration in `extern (C/Windows) { declaration }`
|
||||
// Necessary for function pointers, but harmless to apply to all.
|
||||
auto decls = new AST.Dsymbols(1);
|
||||
(*decls)[0] = s;
|
||||
s = new AST.LinkDeclaration(s.loc, linkage, decls);
|
||||
const lkg = specifier.mod & MOD.x__stdcall ? LINK.windows : linkage;
|
||||
s = new AST.LinkDeclaration(s.loc, lkg, decls);
|
||||
}
|
||||
symbols.push(s);
|
||||
}
|
||||
|
@ -5860,13 +5869,15 @@ final class CParser(AST) : Parser!AST
|
|||
|
||||
const(char)* endp = &slice[length - 7];
|
||||
|
||||
AST.Dsymbols newSymbols;
|
||||
|
||||
size_t[void*] defineTab; // hash table of #define's turned into Symbol's
|
||||
// indexed by Identifier, returns index into symbols[]
|
||||
// indexed by Identifier, returns index into newSymbols[]
|
||||
// The memory for this is leaked
|
||||
|
||||
void addVar(AST.Dsymbol s)
|
||||
void addSym(AST.Dsymbol s)
|
||||
{
|
||||
//printf("addVar() %s\n", s.toChars());
|
||||
//printf("addSym() %s\n", s.toChars());
|
||||
if (auto v = s.isVarDeclaration())
|
||||
v.isCmacro(true); // mark it as coming from a C #define
|
||||
/* If it's already defined, replace the earlier
|
||||
|
@ -5874,13 +5885,22 @@ final class CParser(AST) : Parser!AST
|
|||
*/
|
||||
if (size_t* pd = cast(void*)s.ident in defineTab)
|
||||
{
|
||||
//printf("replacing %s\n", v.toChars());
|
||||
(*symbols)[*pd] = s;
|
||||
//printf("replacing %s\n", s.toChars());
|
||||
newSymbols[*pd] = s;
|
||||
return;
|
||||
}
|
||||
assert(symbols, "symbols is null");
|
||||
defineTab[cast(void*)s.ident] = symbols.length;
|
||||
symbols.push(s);
|
||||
defineTab[cast(void*)s.ident] = newSymbols.length;
|
||||
newSymbols.push(s);
|
||||
}
|
||||
|
||||
void removeSym(Identifier ident)
|
||||
{
|
||||
//printf("removeSym() %s\n", ident.toChars());
|
||||
if (size_t* pd = cast(void*)ident in defineTab)
|
||||
{
|
||||
//printf("removing %s\n", ident.toChars());
|
||||
newSymbols[*pd] = null;
|
||||
}
|
||||
}
|
||||
|
||||
while (p < endp)
|
||||
|
@ -5924,7 +5944,7 @@ final class CParser(AST) : Parser!AST
|
|||
*/
|
||||
AST.Expression e = new AST.IntegerExp(scanloc, intvalue, t);
|
||||
auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
|
||||
addVar(v);
|
||||
addSym(v);
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
|
@ -5947,7 +5967,7 @@ final class CParser(AST) : Parser!AST
|
|||
*/
|
||||
AST.Expression e = new AST.RealExp(scanloc, floatvalue, t);
|
||||
auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
|
||||
addVar(v);
|
||||
addSym(v);
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
|
@ -5965,7 +5985,7 @@ final class CParser(AST) : Parser!AST
|
|||
*/
|
||||
AST.Expression e = new AST.StringExp(scanloc, str[0 .. len], len, 1, postfix);
|
||||
auto v = new AST.VarDeclaration(scanloc, null, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
|
||||
addVar(v);
|
||||
addSym(v);
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
|
@ -6001,7 +6021,7 @@ final class CParser(AST) : Parser!AST
|
|||
AST.TemplateParameters* tpl = new AST.TemplateParameters();
|
||||
AST.Expression constraint = null;
|
||||
auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false);
|
||||
addVar(tempdecl);
|
||||
addSym(tempdecl);
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
|
@ -6092,7 +6112,7 @@ final class CParser(AST) : Parser!AST
|
|||
AST.Dsymbols* decldefs = new AST.Dsymbols();
|
||||
decldefs.push(fd);
|
||||
auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, null, decldefs, false);
|
||||
addVar(tempdecl);
|
||||
addSym(tempdecl);
|
||||
|
||||
++p;
|
||||
continue;
|
||||
|
@ -6103,6 +6123,14 @@ final class CParser(AST) : Parser!AST
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (p[0 .. 6] == "#undef")
|
||||
{
|
||||
p += 6;
|
||||
nextToken();
|
||||
//printf("undef %s\n", token.toChars());
|
||||
if (token.value == TOK.identifier)
|
||||
removeSym(token.ident);
|
||||
}
|
||||
// scan to end of line
|
||||
while (*p)
|
||||
++p;
|
||||
|
@ -6110,6 +6138,16 @@ final class CParser(AST) : Parser!AST
|
|||
scanloc.linnum = scanloc.linnum + 1;
|
||||
}
|
||||
|
||||
if (newSymbols.length)
|
||||
{
|
||||
assert(symbols, "symbols is null");
|
||||
symbols.reserve(newSymbols.length);
|
||||
|
||||
foreach (sym; newSymbols)
|
||||
if (sym) // undefined entries are null
|
||||
symbols.push(sym);
|
||||
}
|
||||
|
||||
scanloc = scanlocSave;
|
||||
eSink = save;
|
||||
defines = buf;
|
||||
|
|
|
@ -1542,7 +1542,7 @@ private bool inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope)
|
|||
* e = expression to be returned by value
|
||||
* er = where to place collected data
|
||||
* live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
|
||||
* retRefTransition = if `e` is returned through a `return ref scope` function call
|
||||
* retRefTransition = if `e` is returned through a `return (ref) scope` function call
|
||||
*/
|
||||
public
|
||||
void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false)
|
||||
|
@ -1786,7 +1786,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
|
|||
}
|
||||
}
|
||||
else
|
||||
escapeByValue(arg, er, live, retRefTransition);
|
||||
escapeByValue(arg, er, live, true);
|
||||
}
|
||||
else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
|
||||
{
|
||||
|
@ -1941,7 +1941,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
|
|||
* e = expression to be returned by 'ref'
|
||||
* er = where to place collected data
|
||||
* live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
|
||||
* retRefTransition = if `e` is returned through a `return ref scope` function call
|
||||
* retRefTransition = if `e` is returned through a `return (ref) scope` function call
|
||||
*/
|
||||
private
|
||||
void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false)
|
||||
|
@ -2189,7 +2189,7 @@ struct EscapeByResults
|
|||
import dmd.root.array: Array;
|
||||
|
||||
/**
|
||||
* Whether the variable / expression went through a `return ref scope` function call
|
||||
* Whether the variable / expression went through a `return (ref) scope` function call
|
||||
*
|
||||
* This is needed for the dip1000 by default transition, since the rules for
|
||||
* disambiguating `return scope ref` have changed. Therefore, functions in legacy code
|
||||
|
@ -2197,6 +2197,10 @@ struct EscapeByResults
|
|||
* are being escaped, which is an error even in `@system` code. By keeping track of this
|
||||
* information, variables escaped through `return ref` can be treated as a deprecation instead
|
||||
* of error, see test/fail_compilation/dip1000_deprecation.d
|
||||
*
|
||||
* Additionally, return scope can be inferred wrongly instead of scope, in which
|
||||
* case the code could give false positives even without @safe or dip1000:
|
||||
* https://issues.dlang.org/show_bug.cgi?id=23657
|
||||
*/
|
||||
private Array!bool refRetRefTransition;
|
||||
private Array!bool expRetRefTransition;
|
||||
|
@ -2218,7 +2222,7 @@ struct EscapeByResults
|
|||
* Escape variable `v` by reference
|
||||
* Params:
|
||||
* v = variable to escape
|
||||
* retRefTransition = `v` is escaped through a `return ref scope` function call
|
||||
* retRefTransition = `v` is escaped through a `return (ref) scope` function call
|
||||
*/
|
||||
void pushRef(VarDeclaration v, bool retRefTransition)
|
||||
{
|
||||
|
@ -2230,7 +2234,7 @@ struct EscapeByResults
|
|||
* Escape a reference to expression `e`
|
||||
* Params:
|
||||
* e = expression to escape
|
||||
* retRefTransition = `e` is escaped through a `return ref scope` function call
|
||||
* retRefTransition = `e` is escaped through a `return (ref) scope` function call
|
||||
*/
|
||||
void pushExp(Expression e, bool retRefTransition)
|
||||
{
|
||||
|
|
|
@ -5335,7 +5335,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
lowering = new DotIdExp(exp.loc, lowering, Id.object);
|
||||
|
||||
auto tbn = exp.type.nextOf();
|
||||
while (tbn.ty == Tarray)
|
||||
size_t i = nargs;
|
||||
while (tbn.ty == Tarray && --i)
|
||||
tbn = tbn.nextOf();
|
||||
auto unqualTbn = tbn.unqualify(MODFlags.wild | MODFlags.const_ |
|
||||
MODFlags.immutable_ | MODFlags.shared_);
|
||||
|
|
|
@ -868,11 +868,13 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
|
|||
* by the initializer syntax. if a CInitializer has a Designator, it is probably
|
||||
* a nested anonymous struct
|
||||
*/
|
||||
if (cix.initializerList.length)
|
||||
int found;
|
||||
foreach (dix; cix.initializerList)
|
||||
{
|
||||
DesigInit dix = cix.initializerList[0];
|
||||
Designators* dlistx = dix.designatorList;
|
||||
if (dlistx && (*dlistx).length == 1 && (*dlistx)[0].ident)
|
||||
if (!dlistx)
|
||||
continue;
|
||||
if ((*dlistx).length == 1 && (*dlistx)[0].ident)
|
||||
{
|
||||
auto id = (*dlistx)[0].ident;
|
||||
foreach (k, f; sd.fields[]) // linear search for now
|
||||
|
@ -883,11 +885,18 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
|
|||
si.addInit(id, dix.initializer);
|
||||
++fieldi;
|
||||
++index;
|
||||
continue Loop1;
|
||||
++found;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
error(ci.loc, "only 1 designator currently allowed for C struct field initializer `%s`", toChars(ci));
|
||||
}
|
||||
}
|
||||
|
||||
if (found == cix.initializerList.length)
|
||||
continue Loop1;
|
||||
}
|
||||
|
||||
VarDeclaration field;
|
||||
|
|
|
@ -1245,7 +1245,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
|
|||
// @@@DEPRECATION 2.100.2
|
||||
if (auto td = s.isTemplateDeclaration())
|
||||
{
|
||||
if (td.overnext || td.overroot)
|
||||
if (td.overnext)
|
||||
{
|
||||
deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not the overload set `%s`", td.ident.toChars());
|
||||
deprecationSupplemental(e.loc, "the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from");
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// Stack pointers are being escaped here, but without
|
||||
// @safe and dip1000, it should still be allowed
|
||||
// because return scope could have been inferred incorrectly,
|
||||
// and it breaks existing code:
|
||||
// https://issues.dlang.org/show_bug.cgi?id=23657
|
||||
|
||||
int* identity(return scope int* x);
|
||||
|
||||
auto identityAuto(int* x) => x;
|
||||
|
||||
int* f()
|
||||
{
|
||||
int x;
|
||||
return identity(&x);
|
||||
return identityAuto(&x);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=24479
|
||||
|
||||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
1
|
||||
2
|
||||
---
|
||||
*/
|
||||
|
||||
struct S
|
||||
{
|
||||
@1
|
||||
S opBinary(string op: "-")(S rhs) const pure nothrow @nogc
|
||||
{
|
||||
return rhs;
|
||||
}
|
||||
@2
|
||||
S opBinary(string op: "*")(S dur) const pure nothrow @nogc
|
||||
{
|
||||
return dur;
|
||||
}
|
||||
}
|
||||
|
||||
private enum hasExternalUDA(alias A) = is(A == External) || is(typeof(A) == External);
|
||||
|
||||
void foo()
|
||||
{
|
||||
static foreach (t; __traits(getOverloads, S, "opBinary", true))
|
||||
static foreach(attr; __traits(getAttributes, t))
|
||||
pragma(msg, attr);
|
||||
|
||||
static assert(__traits(getOverloads, S, "opBinary", true).length == 2);
|
||||
alias A = __traits(getAttributes, __traits(getOverloads, S, "opBinary", true)[1]);
|
||||
}
|
|
@ -248,3 +248,9 @@ void func12(const(char)*[] args = [baseName(__FILE__.ptr),
|
|||
printf(" %s", arg);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24519
|
||||
void func13(string file = __FILE__[])
|
||||
{
|
||||
printf("%s: %s\n", __FUNCTION__.ptr, file.ptr);
|
||||
}
|
||||
|
|
|
@ -20,10 +20,13 @@ imports.issue18919b.func9.fp: issue18919b.d:216 imports.issue18919b
|
|||
imports.issue18919b.func10: expr1=imports.issue18919b, expr2=imports.issue18919b
|
||||
imports.issue18919b.func11: issue18919b.d:233 imports.issue18919b
|
||||
imports.issue18919b.func12: issue18919.d issue18919.main void issue18919.main() issue18919
|
||||
imports.issue18919b.func13: runnable/issue18919.d
|
||||
---
|
||||
*/
|
||||
import imports.issue18919b;
|
||||
|
||||
#line 26
|
||||
|
||||
void main()
|
||||
{
|
||||
func1();
|
||||
|
@ -44,4 +47,5 @@ void main()
|
|||
func10();
|
||||
func11();
|
||||
func12();
|
||||
func13();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import core.memory;
|
||||
|
||||
void main()
|
||||
{
|
||||
{
|
||||
int[][] a = new int[][](2, 2);
|
||||
assert(!(GC.getAttr(a.ptr) & GC.BlkAttr.NO_SCAN));
|
||||
assert(GC.getAttr(a[0].ptr) & GC.BlkAttr.NO_SCAN);
|
||||
}
|
||||
{
|
||||
void*[][] a = new void*[][](2, 2);
|
||||
assert(!(GC.getAttr(a.ptr) & GC.BlkAttr.NO_SCAN));
|
||||
assert(!(GC.getAttr(a[0].ptr) & GC.BlkAttr.NO_SCAN));
|
||||
}
|
||||
{
|
||||
int[][][] a = new int[][][](2, 2);
|
||||
assert(!(GC.getAttr(a.ptr) & GC.BlkAttr.NO_SCAN));
|
||||
assert(!(GC.getAttr(a[0].ptr) & GC.BlkAttr.NO_SCAN));
|
||||
assert(a[0][0].ptr is null);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
b65767825f365dbc153457fc86e1054b03196c6d
|
||||
af92b68a81888702896620db1d10ee477b6b31e8
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
|
|
@ -526,7 +526,7 @@ Tarr _d_newarraymTX(Tarr : U[], T, U)(size_t[] dims, bool isShared=false) @trust
|
|||
|
||||
auto dim = dims[0];
|
||||
|
||||
debug(PRINTF) printf("__allocateInnerArray(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, dims.length);
|
||||
debug(PRINTF) printf("__allocateInnerArray(UnqT = %s, dim = %lu, ndims = %lu\n", UnqT.stringof.ptr, dim, dims.length);
|
||||
if (dims.length == 1)
|
||||
{
|
||||
auto r = _d_newarrayT!UnqT(dim, isShared);
|
||||
|
@ -534,8 +534,9 @@ Tarr _d_newarraymTX(Tarr : U[], T, U)(size_t[] dims, bool isShared=false) @trust
|
|||
}
|
||||
|
||||
auto allocSize = (void[]).sizeof * dim;
|
||||
auto info = __arrayAlloc!UnqT(allocSize);
|
||||
__setArrayAllocLength!UnqT(info, allocSize, isShared);
|
||||
// the array-of-arrays holds pointers! Don't use UnqT here!
|
||||
auto info = __arrayAlloc!(void[])(allocSize);
|
||||
__setArrayAllocLength!(void[])(info, allocSize, isShared);
|
||||
auto p = __arrayStart(info)[0 .. dim];
|
||||
|
||||
foreach (i; 0..dim)
|
||||
|
@ -579,6 +580,16 @@ unittest
|
|||
}
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24436
|
||||
@system unittest
|
||||
{
|
||||
import core.memory : GC;
|
||||
|
||||
int[][] a = _d_newarraymTX!(int[][], int)([2, 2]);
|
||||
|
||||
assert(!(GC.getAttr(a.ptr) & GC.BlkAttr.NO_SCAN));
|
||||
}
|
||||
|
||||
version (D_ProfileGC)
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
92dc5a4e98591a0e6b0af4ff0f84f096fea09016
|
||||
c970ca67f25eab9f975da285d6cb4a56902c525a
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/phobos repository.
|
||||
|
|
|
@ -23,3 +23,94 @@ module std.internal.test.range;
|
|||
auto r = R().chunks(3);
|
||||
assert(r.equal!equal([[ 0, 1, 2 ], [ 3, 4 ]]));
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24415
|
||||
@safe unittest
|
||||
{
|
||||
import std.range : only;
|
||||
|
||||
static struct S(T)
|
||||
{
|
||||
T i;
|
||||
|
||||
this(ref return scope inout(S) rhs) scope @safe inout pure nothrow
|
||||
{
|
||||
i = rhs.i;
|
||||
}
|
||||
}
|
||||
{
|
||||
auto a = only(S!int(42));
|
||||
auto b = a;
|
||||
assert(!b.empty);
|
||||
assert(b.front == S!int(42));
|
||||
|
||||
a.popFront();
|
||||
auto c = a;
|
||||
assert(c.empty);
|
||||
}
|
||||
{
|
||||
auto a = only(S!(const int)(42));
|
||||
auto b = a;
|
||||
assert(!b.empty);
|
||||
assert(b.front == S!(const int)(42));
|
||||
|
||||
a.popFront();
|
||||
auto c = a;
|
||||
assert(c.empty);
|
||||
}
|
||||
{
|
||||
auto a = only(S!(immutable int)(42));
|
||||
auto b = a;
|
||||
assert(!b.empty);
|
||||
assert(b.front == S!(immutable int)(42));
|
||||
|
||||
a.popFront();
|
||||
auto c = a;
|
||||
assert(c.empty);
|
||||
}
|
||||
{
|
||||
auto a = only(S!int(42), S!int(192));
|
||||
auto b = a;
|
||||
assert(!b.empty);
|
||||
assert(b.front == S!int(42));
|
||||
|
||||
a.popFront();
|
||||
auto c = a;
|
||||
assert(!c.empty);
|
||||
assert(c.front == S!int(192));
|
||||
|
||||
a.popFront();
|
||||
auto d = a;
|
||||
assert(d.empty);
|
||||
}
|
||||
{
|
||||
auto a = only(S!(const int)(42), S!(const int)(192));
|
||||
auto b = a;
|
||||
assert(!b.empty);
|
||||
assert(b.front == S!(const int)(42));
|
||||
|
||||
a.popFront();
|
||||
auto c = a;
|
||||
assert(!c.empty);
|
||||
assert(c.front == S!(const int)(192));
|
||||
|
||||
a.popFront();
|
||||
auto d = a;
|
||||
assert(d.empty);
|
||||
}
|
||||
{
|
||||
auto a = only(S!(immutable int)(42), S!(immutable int)(192));
|
||||
auto b = a;
|
||||
assert(!b.empty);
|
||||
assert(b.front == S!(immutable int)(42));
|
||||
|
||||
a.popFront();
|
||||
auto c = a;
|
||||
assert(!c.empty);
|
||||
assert(c.front == S!(immutable int)(192));
|
||||
|
||||
a.popFront();
|
||||
auto d = a;
|
||||
assert(d.empty);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1473,15 +1473,15 @@ if (sharedLog !is myLogger)
|
|||
atomicStore!(MemoryOrder.seq)(stdSharedLogger, atomicLoad(logger));
|
||||
}
|
||||
|
||||
/** This methods get and set the global `LogLevel`.
|
||||
/** These methods get and set the global `LogLevel`.
|
||||
|
||||
Every log message with a `LogLevel` lower as the global `LogLevel`
|
||||
Every log message with a `LogLevel` lower than the global `LogLevel`
|
||||
will be discarded before it reaches `writeLogMessage` method of any
|
||||
`Logger`.
|
||||
*/
|
||||
/* Implementation note:
|
||||
For any public logging call, the global log level shall only be queried once on
|
||||
entry. Otherwise when another threads changes the level, we would work with
|
||||
entry. Otherwise when another thread changes the level, we would work with
|
||||
different levels at different spots in the code.
|
||||
*/
|
||||
@property LogLevel globalLogLevel() @safe @nogc
|
||||
|
|
|
@ -313,16 +313,18 @@ if (isBidirectionalRange!(Unqual!Range))
|
|||
{
|
||||
@property void front(ElementType!R val)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
source.back = move(val);
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
source.back = __ctfe ? val : forward!val;
|
||||
}
|
||||
|
||||
@property void back(ElementType!R val)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
source.front = move(val);
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
source.front = __ctfe ? val : forward!val;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,9 +336,10 @@ if (isBidirectionalRange!(Unqual!Range))
|
|||
{
|
||||
void opIndexAssign(ElementType!R val, size_t n)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
source[retroIndex(n)] = move(val);
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
source[retroIndex(n)] = __ctfe ? val : forward!val;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -494,6 +497,32 @@ pure @safe nothrow unittest
|
|||
assert(equal(r, [S(3), S(2), S(1)]));
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24481
|
||||
@safe unittest
|
||||
{
|
||||
bool called;
|
||||
struct Handle
|
||||
{
|
||||
int entry;
|
||||
void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
|
||||
}
|
||||
|
||||
const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
|
||||
auto range = arr[].retro();
|
||||
|
||||
called = false;
|
||||
range.front = Handle(42);
|
||||
assert(called);
|
||||
|
||||
called = false;
|
||||
range.back = Handle(42);
|
||||
assert(called);
|
||||
|
||||
called = false;
|
||||
range[2] = Handle(42);
|
||||
assert(called);
|
||||
}
|
||||
|
||||
/**
|
||||
Iterates range `r` with stride `n`. If the range is a
|
||||
random-access range, moves by indexing into the range; otherwise,
|
||||
|
@ -604,9 +633,10 @@ do
|
|||
{
|
||||
@property void front(ElementType!R val)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
source.front = move(val);
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
source.front = __ctfe ? val : forward!val;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -899,6 +929,24 @@ pure @safe nothrow unittest
|
|||
assert(equal(r, [S(1), S(4)]));
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24481
|
||||
@safe unittest
|
||||
{
|
||||
bool called;
|
||||
struct Handle
|
||||
{
|
||||
int entry;
|
||||
void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
|
||||
}
|
||||
|
||||
const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
|
||||
auto range = arr[].stride(2);
|
||||
|
||||
called = false;
|
||||
range.front = Handle(42);
|
||||
assert(called);
|
||||
}
|
||||
|
||||
/**
|
||||
Spans multiple ranges in sequence. The function `chain` takes any
|
||||
number of ranges and returns a $(D Chain!(R1, R2,...)) object. The
|
||||
|
@ -1120,14 +1168,15 @@ if (Ranges.length > 0 &&
|
|||
|
||||
@property void front(RvalueElementType v)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
sw: switch (frontIndex)
|
||||
{
|
||||
static foreach (i; 0 .. R.length)
|
||||
{
|
||||
case i:
|
||||
source[i].front = move(v);
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
source[i].front = __ctfe ? v : forward!v;
|
||||
break sw;
|
||||
}
|
||||
|
||||
|
@ -1246,14 +1295,15 @@ if (Ranges.length > 0 &&
|
|||
{
|
||||
@property void back(RvalueElementType v)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
sw: switch (backIndex)
|
||||
{
|
||||
static foreach_reverse (i; 1 .. R.length + 1)
|
||||
{
|
||||
case i:
|
||||
source[i-1].back = move(v);
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
source[i - 1].back = __ctfe ? v : forward!v;
|
||||
break sw;
|
||||
}
|
||||
|
||||
|
@ -1359,7 +1409,7 @@ if (Ranges.length > 0 &&
|
|||
static if (allSameType && allSatisfy!(hasAssignableElements, R))
|
||||
void opIndexAssign(ElementType v, size_t index)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
sw: switch (frontIndex)
|
||||
{
|
||||
|
@ -1376,7 +1426,8 @@ if (Ranges.length > 0 &&
|
|||
}
|
||||
}
|
||||
|
||||
source[i][index] = move(v);
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
source[i][index] = __ctfe ? v : forward!v;
|
||||
break sw;
|
||||
}
|
||||
|
||||
|
@ -1727,6 +1778,32 @@ pure @safe nothrow unittest
|
|||
assert(typeof(range).init.empty);
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24481
|
||||
@safe unittest
|
||||
{
|
||||
bool called;
|
||||
struct Handle
|
||||
{
|
||||
int entry;
|
||||
void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
|
||||
}
|
||||
|
||||
const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
|
||||
auto range = arr[0 .. 2].chain(arr[4 .. 5]);
|
||||
|
||||
called = false;
|
||||
range.front = Handle(42);
|
||||
assert(called);
|
||||
|
||||
called = false;
|
||||
range.back = Handle(42);
|
||||
assert(called);
|
||||
|
||||
called = false;
|
||||
range[2] = Handle(42);
|
||||
assert(called);
|
||||
}
|
||||
|
||||
/**
|
||||
Choose one of two ranges at runtime depending on a Boolean condition.
|
||||
|
||||
|
@ -2694,12 +2771,14 @@ if (isInputRange!(Unqual!Range) &&
|
|||
/// ditto
|
||||
@property void front(ElementType!R v)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
assert(!empty,
|
||||
"Attempting to assign to the front of an empty "
|
||||
~ Take.stringof);
|
||||
source.front = move(v);
|
||||
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
source.front = __ctfe ? v : forward!v;
|
||||
}
|
||||
|
||||
static if (hasMobileElements!R)
|
||||
|
@ -2996,6 +3075,25 @@ pure @safe nothrow @nogc unittest
|
|||
assert(r.take(2).equal(repeat(1, 2)));
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24481
|
||||
@safe unittest
|
||||
{
|
||||
import std.algorithm.iteration : filter;
|
||||
|
||||
bool called;
|
||||
struct Handle
|
||||
{
|
||||
int entry;
|
||||
void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
|
||||
}
|
||||
|
||||
const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
|
||||
auto range = arr[].filter!(a => true)().take(3);
|
||||
|
||||
called = false;
|
||||
range.front = Handle(42);
|
||||
assert(called);
|
||||
}
|
||||
|
||||
/**
|
||||
Similar to $(LREF take), but assumes that `range` has at least $(D
|
||||
|
@ -3075,12 +3173,14 @@ if (isInputRange!R)
|
|||
{
|
||||
@property auto ref front(ElementType!R v)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
assert(!empty,
|
||||
"Attempting to assign to the front of an empty "
|
||||
~ typeof(this).stringof);
|
||||
return _input.front = move(v);
|
||||
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
return _input.front = __ctfe ? v : forward!v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3217,6 +3317,26 @@ pure @safe nothrow unittest
|
|||
}}
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24481
|
||||
@safe unittest
|
||||
{
|
||||
import std.algorithm.iteration : filter;
|
||||
|
||||
bool called;
|
||||
struct Handle
|
||||
{
|
||||
int entry;
|
||||
void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
|
||||
}
|
||||
|
||||
const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
|
||||
auto range = arr[].filter!(a => true)().takeExactly(3);
|
||||
|
||||
called = false;
|
||||
range.front = Handle(42);
|
||||
assert(called);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a range with at most one element; for example, $(D
|
||||
takeOne([42, 43, 44])) returns a range consisting of the integer $(D
|
||||
|
@ -4310,9 +4430,10 @@ if (isForwardRange!R && !isInfinite!R)
|
|||
/// ditto
|
||||
@property void front(ElementType!R val)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
_original[_index] = move(val);
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
_original[_index] = __ctfe ? val : forward!val;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4422,9 +4543,10 @@ if (isForwardRange!R && !isInfinite!R)
|
|||
/// ditto
|
||||
@property auto front(ElementType!R val)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
return _current.front = move(val);
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
return _current.front = __ctfe ? val : forward!val;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4767,6 +4889,35 @@ pure @safe unittest
|
|||
assert(equal(r.save, "foof"));
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24481
|
||||
@safe unittest
|
||||
{
|
||||
import std.algorithm.iteration : filter;
|
||||
|
||||
bool called;
|
||||
struct Handle
|
||||
{
|
||||
int entry;
|
||||
void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
|
||||
}
|
||||
|
||||
const(Handle)[3] arr = [Handle(0), Handle(1), Handle(2)];
|
||||
{
|
||||
auto range = arr[].cycle().take(5);
|
||||
|
||||
called = false;
|
||||
range.front = Handle(42);
|
||||
assert(called);
|
||||
}
|
||||
{
|
||||
auto range = arr[].filter!(a => true)().cycle().take(5);
|
||||
|
||||
called = false;
|
||||
range.front = Handle(42);
|
||||
assert(called);
|
||||
}
|
||||
}
|
||||
|
||||
private alias lengthType(R) = typeof(R.init.length.init);
|
||||
|
||||
/**
|
||||
|
@ -7438,9 +7589,10 @@ struct FrontTransversal(Ror,
|
|||
{
|
||||
@property void front(ElementType val)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
_input.front.front = move(val);
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
_input.front.front = __ctfe ? val : forward!val;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7497,9 +7649,10 @@ struct FrontTransversal(Ror,
|
|||
{
|
||||
@property void back(ElementType val)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
_input.back.front = move(val);
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
_input.back.front = __ctfe ? val : forward!val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7532,9 +7685,10 @@ struct FrontTransversal(Ror,
|
|||
{
|
||||
void opIndexAssign(ElementType val, size_t n)
|
||||
{
|
||||
import std.algorithm.mutation : move;
|
||||
import core.lifetime : forward;
|
||||
|
||||
_input[n].front = move(val);
|
||||
// __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
|
||||
_input[n].front = __ctfe ? val : forward!val;
|
||||
}
|
||||
}
|
||||
mixin ImplementLength!_input;
|
||||
|
@ -7675,6 +7829,50 @@ pure @safe unittest
|
|||
assert(ft.empty);
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24481
|
||||
@safe unittest
|
||||
{
|
||||
bool called;
|
||||
struct Handle
|
||||
{
|
||||
int entry;
|
||||
void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
|
||||
}
|
||||
|
||||
const(Handle)[][] arr = [[Handle(0), Handle(10)],
|
||||
[Handle(1), Handle(11)],
|
||||
[Handle(2), Handle(12)],
|
||||
[Handle(3), Handle(13)],
|
||||
[Handle(4), Handle(14)]];
|
||||
|
||||
{
|
||||
auto range = arr.frontTransversal();
|
||||
|
||||
called = false;
|
||||
range.front = Handle(42);
|
||||
assert(called == true);
|
||||
|
||||
called = false;
|
||||
range.back = Handle(42);
|
||||
assert(called == true);
|
||||
}
|
||||
{
|
||||
auto range = arr.frontTransversal!(TransverseOptions.assumeNotJagged)();
|
||||
|
||||
called = false;
|
||||
range.front = Handle(42);
|
||||
assert(called == true);
|
||||
|
||||
called = false;
|
||||
range.back = Handle(42);
|
||||
assert(called == true);
|
||||
|
||||
called = false;
|
||||
range[0] = Handle(42);
|
||||
assert(called == true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Given a range of ranges, iterate transversally through the
|
||||
`n`th element of each of the enclosed ranges. This function
|
||||
|
@ -10375,6 +10573,14 @@ private struct OnlyResult(T)
|
|||
}
|
||||
alias opDollar = length;
|
||||
|
||||
// FIXME Workaround for https://issues.dlang.org/show_bug.cgi?id=24415
|
||||
import std.traits : hasElaborateCopyConstructor;
|
||||
static if (hasElaborateCopyConstructor!T)
|
||||
{
|
||||
private static struct WorkaroundBugzilla24415 {}
|
||||
public this()(WorkaroundBugzilla24415) {}
|
||||
}
|
||||
|
||||
private this()(return scope auto ref T value)
|
||||
{
|
||||
ref @trusted unqual(ref T x){return cast() x;}
|
||||
|
|
Loading…
Reference in New Issue