Fix Issue 22105 - std.container.array.Array.length setter creates values of init-less types

This commit is contained in:
wolframw 2021-12-28 18:47:15 +01:00 committed by The Dlang Bot
parent ef9ed4fa19
commit dc697c8dd8
2 changed files with 55 additions and 8 deletions

View file

@ -866,6 +866,9 @@ if (isInputRange!InputRange
Initializes all elements of `range` with their `.init` value.
Assumes that the elements of the range are uninitialized.
This function is unavailable if `T` is a `struct` and `T.this()` is annotated
with `@disable`.
Params:
range = An
$(REF_ALTTEXT input range, isInputRange, std,range,primitives)
@ -877,7 +880,8 @@ See_Also:
$(LREF uninitializedFill)
*/
void initializeAll(Range)(Range range)
if (isInputRange!Range && hasLvalueElements!Range && hasAssignableElements!Range)
if (isInputRange!Range && hasLvalueElements!Range && hasAssignableElements!Range
&& __traits(compiles, { static ElementType!Range _; }))
{
import core.stdc.string : memset, memcpy;
import std.traits : hasElaborateAssign, isDynamicArray;
@ -1037,6 +1041,18 @@ if (is(Range == char[]) || is(Range == wchar[]))
assert(xs[1].x == 3);
}
// https://issues.dlang.org/show_bug.cgi?id=22105
@system unittest
{
struct NoDefaultCtor
{
@disable this();
}
NoDefaultCtor[1] array = void;
static assert(!__traits(compiles, array[].initializeAll));
}
// move
/**
Moves `source` into `target`, via a destructive copy when necessary.

View file

@ -428,8 +428,6 @@ if (!is(immutable T == immutable bool))
@property void length(size_t newLength)
{
import std.algorithm.mutation : initializeAll;
if (length >= newLength)
{
// shorten
@ -440,10 +438,22 @@ if (!is(immutable T == immutable bool))
_payload = _payload.ptr[0 .. newLength];
return;
}
immutable startEmplace = length;
reserve(newLength);
initializeAll(_payload.ptr[startEmplace .. newLength]);
_payload = _payload.ptr[0 .. newLength];
static if (__traits(compiles, { static T _; }))
{
import std.algorithm.mutation : initializeAll;
immutable startEmplace = length;
reserve(newLength);
initializeAll(_payload.ptr[startEmplace .. newLength]);
_payload = _payload.ptr[0 .. newLength];
}
else
{
assert(0, "Cannot add elements to array because `" ~
fullyQualifiedName!T ~ ".this()` is annotated with " ~
"`@disable`.");
}
}
@property size_t capacity() const
@ -901,12 +911,16 @@ if (!is(immutable T == immutable bool))
/**
* Sets the number of elements in the array to `newLength`. If `newLength`
* is greater than `length`, the new elements are added to the end of the
* array and initialized with `T.init`.
* array and initialized with `T.init`. If `T` is a `struct` whose default
* constructor is annotated with `@disable`, `newLength` must be lower than
* or equal to `length`.
*
* Complexity:
* Guaranteed $(BIGOH abs(length - newLength)) if `capacity >= newLength`.
* If `capacity < newLength` the worst case is $(BIGOH newLength).
*
* Precondition: `__traits(compiles, { static T _; }) || newLength <= length`
*
* Postcondition: `length == newLength`
*/
@property void length(size_t newLength)
@ -1708,6 +1722,23 @@ if (!is(immutable T == immutable bool))
assert(equal(a[], [1,2,3,4,5,6,7,8]));
}
// https://issues.dlang.org/show_bug.cgi?id=22105
@system unittest
{
import core.exception : AssertError;
import std.exception : assertThrown, assertNotThrown;
struct NoDefaultCtor
{
int i;
@disable this();
this(int j) { i = j; }
}
auto array = Array!NoDefaultCtor([NoDefaultCtor(1), NoDefaultCtor(2)]);
assertNotThrown!AssertError(array.length = 1);
assertThrown!AssertError(array.length = 5);
}
////////////////////////////////////////////////////////////////////////////////
// Array!bool