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. Initializes all elements of `range` with their `.init` value.
Assumes that the elements of the range are uninitialized. 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: Params:
range = An range = An
$(REF_ALTTEXT input range, isInputRange, std,range,primitives) $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
@ -877,7 +880,8 @@ See_Also:
$(LREF uninitializedFill) $(LREF uninitializedFill)
*/ */
void initializeAll(Range)(Range range) 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 core.stdc.string : memset, memcpy;
import std.traits : hasElaborateAssign, isDynamicArray; import std.traits : hasElaborateAssign, isDynamicArray;
@ -1037,6 +1041,18 @@ if (is(Range == char[]) || is(Range == wchar[]))
assert(xs[1].x == 3); 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 // move
/** /**
Moves `source` into `target`, via a destructive copy when necessary. 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) @property void length(size_t newLength)
{ {
import std.algorithm.mutation : initializeAll;
if (length >= newLength) if (length >= newLength)
{ {
// shorten // shorten
@ -440,10 +438,22 @@ if (!is(immutable T == immutable bool))
_payload = _payload.ptr[0 .. newLength]; _payload = _payload.ptr[0 .. newLength];
return; return;
} }
immutable startEmplace = length;
reserve(newLength); static if (__traits(compiles, { static T _; }))
initializeAll(_payload.ptr[startEmplace .. newLength]); {
_payload = _payload.ptr[0 .. newLength]; 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 @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` * 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 * 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: * Complexity:
* Guaranteed $(BIGOH abs(length - newLength)) if `capacity >= newLength`. * Guaranteed $(BIGOH abs(length - newLength)) if `capacity >= newLength`.
* If `capacity < newLength` the worst case is $(BIGOH newLength). * If `capacity < newLength` the worst case is $(BIGOH newLength).
* *
* Precondition: `__traits(compiles, { static T _; }) || newLength <= length`
*
* Postcondition: `length == newLength` * Postcondition: `length == newLength`
*/ */
@property void length(size_t 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])); 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 // Array!bool