Skip to content

Commit edf6fb9

Browse files
authored
Merge pull request #9086 from kinke/merge_stable
Merge stable Signed-off-by: Nicholas Wilson <[email protected]> Merged-on-behalf-of: Nicholas Wilson <[email protected]>
2 parents db79868 + b0ef9ac commit edf6fb9

File tree

11 files changed

+553
-34
lines changed

11 files changed

+553
-34
lines changed

.github/workflows/main.yml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ jobs:
2424
# macOS
2525
- job_name: macOS 13 x64
2626
os: macos-13
27-
- job_name: macOS 12 x64
28-
os: macos-12
2927
# Windows
3028
- job_name: Windows x64
3129
os: windows-2022
@@ -83,13 +81,6 @@ jobs:
8381
with:
8482
arch: ${{ env.MODEL == '64' && 'x64' || 'x86' }}
8583

86-
# NOTE: Linker ICEs with Xcode 15.0.1 (default version on macos-13)
87-
# * https://issues.dlang.org/show_bug.cgi?id=24407
88-
# Remove this step if the default gets changed to 15.1 in actions/runner-images.
89-
- name: 'macOS 13: Switch to Xcode v15.1'
90-
if: matrix.os == 'macos-13'
91-
run: sudo xcode-select -switch /Applications/Xcode_15.1.app
92-
9384
- name: 'Posix: Install host compiler'
9485
if: runner.os != 'Windows'
9586
run: cd ../dmd && ci/run.sh install_host_compiler

std/algorithm/searching.d

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3735,6 +3735,47 @@ if (isInputRange!Range && !isInfinite!Range &&
37353735
assert(arr.minElement!"a.val".val == 0);
37363736
}
37373737

3738+
// https://issues.dlang.org/show_bug.cgi?id=24827
3739+
@safe unittest
3740+
{
3741+
static struct S
3742+
{
3743+
int i;
3744+
bool destroyed;
3745+
3746+
this(int i) @safe
3747+
{
3748+
this.i = i;
3749+
}
3750+
3751+
~this() @safe
3752+
{
3753+
destroyed = true;
3754+
}
3755+
3756+
bool opEquals()(auto ref S rhs)
3757+
{
3758+
return this.i == rhs.i;
3759+
}
3760+
3761+
int opCmp()(auto ref S rhs)
3762+
{
3763+
if (this.i < rhs.i)
3764+
return -1;
3765+
3766+
return this.i == rhs.i ? 0 : 1;
3767+
}
3768+
3769+
@safe invariant
3770+
{
3771+
assert(!destroyed);
3772+
}
3773+
}
3774+
3775+
auto arr = [S(19), S(2), S(145), S(7)];
3776+
assert(minElement(arr) == S(2));
3777+
}
3778+
37383779
/**
37393780
Iterates the passed range and returns the maximal element.
37403781
A custom mapping function can be passed to `map`.
@@ -3888,6 +3929,47 @@ if (isInputRange!Range && !isInfinite!Range &&
38883929
assert(arr[0].getI == 2);
38893930
}
38903931

3932+
// https://issues.dlang.org/show_bug.cgi?id=24827
3933+
@safe unittest
3934+
{
3935+
static struct S
3936+
{
3937+
int i;
3938+
bool destroyed;
3939+
3940+
this(int i) @safe
3941+
{
3942+
this.i = i;
3943+
}
3944+
3945+
~this() @safe
3946+
{
3947+
destroyed = true;
3948+
}
3949+
3950+
bool opEquals()(auto ref S rhs)
3951+
{
3952+
return this.i == rhs.i;
3953+
}
3954+
3955+
int opCmp()(auto ref S rhs)
3956+
{
3957+
if (this.i < rhs.i)
3958+
return -1;
3959+
3960+
return this.i == rhs.i ? 0 : 1;
3961+
}
3962+
3963+
@safe invariant
3964+
{
3965+
assert(!destroyed);
3966+
}
3967+
}
3968+
3969+
auto arr = [S(19), S(2), S(145), S(7)];
3970+
assert(maxElement(arr) == S(145));
3971+
}
3972+
38913973
// minPos
38923974
/**
38933975
Computes a subrange of `range` starting at the first occurrence of `range`'s

std/array.d

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3639,6 +3639,7 @@ if (isDynamicArray!A)
36393639
}
36403640
else
36413641
{
3642+
import core.stdc.string : memcpy, memset;
36423643
// Time to reallocate.
36433644
// We need to almost duplicate what's in druntime, except we
36443645
// have better access to the capacity field.
@@ -3650,6 +3651,15 @@ if (isDynamicArray!A)
36503651
if (u)
36513652
{
36523653
// extend worked, update the capacity
3654+
// if the type has indirections, we need to zero any new
3655+
// data that we requested, as the existing data may point
3656+
// at large unused blocks.
3657+
static if (hasIndirections!T)
3658+
{
3659+
immutable addedSize = u - (_data.capacity * T.sizeof);
3660+
() @trusted { memset(_data.arr.ptr + _data.capacity, 0, addedSize); }();
3661+
}
3662+
36533663
_data.capacity = u / T.sizeof;
36543664
return;
36553665
}
@@ -3665,10 +3675,20 @@ if (isDynamicArray!A)
36653675

36663676
auto bi = (() @trusted => GC.qalloc(nbytes, blockAttribute!T))();
36673677
_data.capacity = bi.size / T.sizeof;
3668-
import core.stdc.string : memcpy;
36693678
if (len)
36703679
() @trusted { memcpy(bi.base, _data.arr.ptr, len * T.sizeof); }();
3680+
36713681
_data.arr = (() @trusted => (cast(Unqual!T*) bi.base)[0 .. len])();
3682+
3683+
// we requested new bytes that are not in the existing
3684+
// data. If T has pointers, then this new data could point at stale
3685+
// objects from the last time this block was allocated. Zero that
3686+
// new data out, it may point at large unused blocks!
3687+
static if (hasIndirections!T)
3688+
() @trusted {
3689+
memset(bi.base + (len * T.sizeof), 0, (newlen - len) * T.sizeof);
3690+
}();
3691+
36723692
_data.tryExtendBlock = true;
36733693
// leave the old data, for safety reasons
36743694
}
@@ -4047,6 +4067,43 @@ if (isDynamicArray!A)
40474067
app2.toString();
40484068
}
40494069

4070+
// https://issues.dlang.org/show_bug.cgi?id=24856
4071+
@system unittest
4072+
{
4073+
import core.memory : GC;
4074+
import std.stdio : writeln;
4075+
import std.algorithm.searching : canFind;
4076+
GC.disable();
4077+
scope(exit) GC.enable();
4078+
void*[] freeme;
4079+
// generate some poison blocks to allocate from.
4080+
auto poison = cast(void*) 0xdeadbeef;
4081+
foreach (i; 0 .. 10)
4082+
{
4083+
auto blk = new void*[7];
4084+
blk[] = poison;
4085+
freeme ~= blk.ptr;
4086+
}
4087+
4088+
foreach (p; freeme)
4089+
GC.free(p);
4090+
4091+
int tests = 0;
4092+
foreach (i; 0 .. 10)
4093+
{
4094+
Appender!(void*[]) app;
4095+
app.put(null);
4096+
// if not a realloc of one of the deadbeef pointers, continue
4097+
if (!freeme.canFind(app.data.ptr))
4098+
continue;
4099+
++tests;
4100+
assert(!app.data.ptr[0 .. app.capacity].canFind(poison), "Appender not zeroing data!");
4101+
}
4102+
// just notify in the log whether this test actually could be done.
4103+
if (tests == 0)
4104+
writeln("WARNING: test of Appender zeroing did not occur");
4105+
}
4106+
40504107
//Calculates an efficient growth scheme based on the old capacity
40514108
//of data, and the minimum requested capacity.
40524109
//arg curLen: The current length

std/bitmanip.d

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ private template createAccessors(
106106
enum RightShiftOp = ">>>=";
107107
}
108108

109-
static if (is(T == bool))
109+
static if (is(T : bool))
110110
{
111111
enum createAccessors =
112112
// getter
@@ -4676,3 +4676,24 @@ if (isIntegral!T)
46764676
foreach (i; 0 .. 63)
46774677
assert(bitsSet(1UL << i).equal([i]));
46784678
}
4679+
4680+
// Fix https://issues.dlang.org/show_bug.cgi?id=24095
4681+
@safe @nogc pure unittest
4682+
{
4683+
enum Bar : bool
4684+
{
4685+
a,
4686+
b,
4687+
}
4688+
4689+
struct Foo
4690+
{
4691+
mixin(bitfields!(Bar, "bar", 1, ubyte, "", 7,));
4692+
}
4693+
4694+
Foo foo;
4695+
foo.bar = Bar.a;
4696+
assert(foo.bar == Bar.a);
4697+
foo.bar = Bar.b;
4698+
assert(foo.bar == Bar.b);
4699+
}

std/container/dlist.d

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ Implements a doubly-linked list.
185185
struct DList(T)
186186
{
187187
import std.range : Take;
188+
import std.traits : isMutable;
188189

189190
/*
190191
A Node with a Payload. A PayNode.
@@ -220,7 +221,10 @@ struct DList(T)
220221
{
221222
import std.algorithm.mutation : move;
222223

223-
return (new PayNode(BaseNode(prev, next), move(arg))).asBaseNode();
224+
static if (isMutable!Stuff)
225+
return (new PayNode(BaseNode(prev, next), move(arg))).asBaseNode();
226+
else
227+
return (new PayNode(BaseNode(prev, next), arg)).asBaseNode();
224228
}
225229

226230
void initialize() nothrow @safe pure
@@ -1149,3 +1153,22 @@ private:
11491153
list.removeFront();
11501154
assert(list[].walkLength == 0);
11511155
}
1156+
1157+
// https://issues.dlang.org/show_bug.cgi?id=24637
1158+
@safe unittest
1159+
{
1160+
import std.algorithm.comparison : equal;
1161+
1162+
struct A
1163+
{
1164+
int c;
1165+
}
1166+
1167+
DList!A B;
1168+
B.insert(A(1));
1169+
assert(B[].equal([A(1)]));
1170+
1171+
const a = A(3);
1172+
B.insert(a);
1173+
assert(B[].equal([A(1), A(3)]));
1174+
}

std/logger/core.d

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,7 +1433,7 @@ logger by the user, the default logger's log level is LogLevel.info.
14331433
14341434
Example:
14351435
-------------
1436-
sharedLog = new FileLogger(yourFile);
1436+
sharedLog = new shared FileLogger(yourFile);
14371437
-------------
14381438
The example sets a new `FileLogger` as new `sharedLog`.
14391439
@@ -1450,7 +1450,7 @@ writing `sharedLog`.
14501450
The default `Logger` is thread-safe.
14511451
-------------
14521452
if (sharedLog !is myLogger)
1453-
sharedLog = new myLogger;
1453+
sharedLog = new shared myLogger;
14541454
-------------
14551455
*/
14561456
@property shared(Logger) sharedLog() @safe

std/logger/filelogger.d

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class FileLogger : Logger
3737
auto l3 = new FileLogger("logFile", LogLevel.fatal, CreateFolder.yes);
3838
-------------
3939
*/
40-
this(const string fn, const LogLevel lv = LogLevel.all) @safe
40+
this(this This)(const string fn, const LogLevel lv = LogLevel.all)
4141
{
4242
this(fn, lv, CreateFolder.yes);
4343
}
@@ -63,7 +63,7 @@ class FileLogger : Logger
6363
auto l2 = new FileLogger(file, LogLevel.fatal);
6464
-------------
6565
*/
66-
this(const string fn, const LogLevel lv, CreateFolder createFileNameFolder) @safe
66+
this(this This)(const string fn, const LogLevel lv, CreateFolder createFileNameFolder)
6767
{
6868
import std.file : exists, mkdirRecurse;
6969
import std.path : dirName;
@@ -80,7 +80,8 @@ class FileLogger : Logger
8080
" created in '", d,"' could not be created."));
8181
}
8282

83-
this.file_.open(this.filename, "a");
83+
// Cast away `shared` when the constructor is inferred shared.
84+
() @trusted { (cast() this.file_).open(this.filename, "a"); }();
8485
}
8586

8687
/** A constructor for the `FileLogger` Logger that takes a reference to
@@ -270,3 +271,12 @@ class FileLogger : Logger
270271
assert(tl !is null);
271272
stdThreadLocalLog.logLevel = LogLevel.all;
272273
}
274+
275+
@safe unittest
276+
{
277+
// we don't need to actually run the code, only make sure
278+
// it compiles
279+
static _() {
280+
auto l = new shared FileLogger("");
281+
}
282+
}

std/logger/package.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ using the property called `sharedLog`. This property is a reference to the
6464
current default `Logger`. This reference can be used to assign a new
6565
default `Logger`.
6666
-------------
67-
sharedLog = new FileLogger("New_Default_Log_File.log");
67+
sharedLog = new shared FileLogger("New_Default_Log_File.log");
6868
-------------
6969
7070
Additional `Logger` can be created by creating a new instance of the

std/process.d

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4631,11 +4631,12 @@ else version (Posix)
46314631
if (childpid == 0)
46324632
{
46334633
// Trusted because args and all entries are always zero-terminated
4634-
(() @trusted =>
4635-
core.sys.posix.unistd.execvp(args[0], &args[0]) ||
4636-
perror(args[0]) // failed to execute
4637-
)();
4638-
return;
4634+
(() @trusted {
4635+
core.sys.posix.unistd.execvp(args[0], &args[0]);
4636+
perror(args[0]);
4637+
core.sys.posix.unistd._exit(1);
4638+
})();
4639+
assert(0, "Child failed to exec");
46394640
}
46404641
if (browser)
46414642
// Trusted because it's allocated via strdup above

std/traits.d

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9238,12 +9238,16 @@ enum isCopyable(S) = __traits(isCopyable, S);
92389238
* is the same as `T`. For pointer and slice types, it is `T` with the
92399239
* outer-most layer of qualifiers dropped.
92409240
*/
9241-
package(std) template DeducedParameterType(T)
9241+
package(std) alias DeducedParameterType(T) = DeducedParameterTypeImpl!T;
9242+
/// ditto
9243+
package(std) alias DeducedParameterType(alias T) = DeducedParameterTypeImpl!T;
9244+
9245+
private template DeducedParameterTypeImpl(T)
92429246
{
92439247
static if (is(T == U*, U) || is(T == U[], U))
9244-
alias DeducedParameterType = Unqual!T;
9248+
alias DeducedParameterTypeImpl = Unqual!T;
92459249
else
9246-
alias DeducedParameterType = T;
9250+
alias DeducedParameterTypeImpl = T;
92479251
}
92489252

92499253
@safe unittest
@@ -9263,6 +9267,7 @@ package(std) template DeducedParameterType(T)
92639267
}
92649268

92659269
static assert(is(DeducedParameterType!NoCopy == NoCopy));
9270+
static assert(is(DeducedParameterType!(inout(NoCopy)) == inout(NoCopy)));
92669271
}
92679272

92689273
@safe unittest

0 commit comments

Comments
 (0)