aboutsummaryrefslogtreecommitdiff
path: root/libphobos/src/std/array.d
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2022-02-13 20:17:53 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2022-02-16 11:15:02 +0100
commitd75691877c4a7521a995d2601021fcaf30f65d94 (patch)
tree36509d835d63b98ad1130ac9d4695b5033c10428 /libphobos/src/std/array.d
parent023327643969d5469902a9ecfa6738a315f9e362 (diff)
downloadgcc-d75691877c4a7521a995d2601021fcaf30f65d94.zip
gcc-d75691877c4a7521a995d2601021fcaf30f65d94.tar.gz
gcc-d75691877c4a7521a995d2601021fcaf30f65d94.tar.bz2
d: Merge upstream dmd 52844d4b1, druntime dbd0c874, phobos 896b1d0e1.
D front-end changes: - Parsing and compiling C code is now possible using `import'. - `throw' statements can now be used as an expression. - Improvements to the D template emission strategy when compiling with `-funittest'. D Runtime changes: - New core.int128 module for implementing intrinsics to support 128-bit integer types. - C bindings for the kernel and C runtime have been better separated to allow compiling for hybrid targets, such as kFreeBSD. Phobos changes: - The std.experimental.checkedint module has been renamed to std.checkedint. gcc/d/ChangeLog: * d-builtins.cc (d_build_builtins_module): Set purity of DECL_PURE_P functions to PURE::const_. * d-gimplify.cc (bit_field_ref): New function. (d_gimplify_modify_expr): Handle implicit casting for assignments to bit-fields. (d_gimplify_unary_expr): New function. (d_gimplify_binary_expr): New function. (d_gimplify_expr): Handle UNARY_CLASS_P and BINARY_CLASS_P. * d-target.cc (Target::_init): Initialize bitFieldStyle. (TargetCPP::parameterType): Update signature. (Target::supportsLinkerDirective): New function. * dmd/MERGE: Merge upstream dmd 52844d4b1. * expr.cc (ExprVisitor::visit (ThrowExp *)): New function. * types.cc (d_build_bitfield_integer_type): New function. (insert_aggregate_bitfield): New function. (layout_aggregate_members): Handle inserting bit-fields into an aggregate type. libphobos/ChangeLog: * Makefile.in: Regenerate. * libdruntime/MERGE: Merge upstream druntime dbd0c874. * libdruntime/Makefile.am (DRUNTIME_CSOURCES): Add core/int128.d. (DRUNTIME_DISOURCES): Add __builtins.di. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 896b1d0e1. * src/Makefile.am (PHOBOS_DSOURCES): Add std/checkedint.d. * src/Makefile.in: Regenerate. * testsuite/testsuite_flags.in: Add -fall-instantiations to --gdcflags.
Diffstat (limited to 'libphobos/src/std/array.d')
-rw-r--r--libphobos/src/std/array.d133
1 files changed, 127 insertions, 6 deletions
diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d
index ffdda8e..b86e0f9 100644
--- a/libphobos/src/std/array.d
+++ b/libphobos/src/std/array.d
@@ -117,7 +117,7 @@ if (isIterable!Range && !isAutodecodableString!Range && !isInfinite!Range)
alias E = ForeachType!Range;
static if (hasLength!Range)
{
- auto length = r.length;
+ const length = r.length;
if (length == 0)
return null;
@@ -126,12 +126,35 @@ if (isIterable!Range && !isAutodecodableString!Range && !isInfinite!Range)
auto result = (() @trusted => uninitializedArray!(Unqual!E[])(length))();
// Every element of the uninitialized array must be initialized
- size_t i;
- foreach (e; r)
+ size_t cnt; //Number of elements that have been initialized
+ try
{
- emplaceRef!E(result[i], e);
- ++i;
+ foreach (e; r)
+ {
+ emplaceRef!E(result[cnt], e);
+ ++cnt;
+ }
+ } catch (Exception e)
+ {
+ //https://issues.dlang.org/show_bug.cgi?id=22185
+ //Make any uninitialized elements safely destructible.
+ foreach (ref elem; result[cnt..$])
+ {
+ import core.internal.lifetime : emplaceInitializer;
+ emplaceInitializer(elem);
+ }
+ throw e;
}
+ /*
+ https://issues.dlang.org/show_bug.cgi?id=22673
+
+ We preallocated an array, we should ensure that enough range elements
+ were gathered such that every slot in the array is filled. If not, the GC
+ will collect the allocated array, leading to the `length - cnt` left over elements
+ being collected too - despite their contents having no guarantee of destructibility.
+ */
+ assert(length == cnt,
+ "Range .length property was not equal to the length yielded by the range before becoming empty");
return (() @trusted => cast(E[]) result)();
}
else
@@ -439,6 +462,91 @@ if (isAutodecodableString!String)
assert(equal(r, [S(1), S(1)]));
});
}
+//https://issues.dlang.org/show_bug.cgi?id=22673
+@system unittest
+{
+ struct LyingRange
+ {
+ enum size_t length = 100;
+ enum theRealLength = 50;
+ size_t idx = 0;
+ bool empty()
+ {
+ return idx <= theRealLength;
+ }
+ void popFront()
+ {
+ ++idx;
+ }
+ size_t front()
+ {
+ return idx;
+ }
+ }
+ static assert(hasLength!LyingRange);
+ LyingRange rng;
+ import std.exception : assertThrown;
+ assertThrown!Error(array(rng));
+}
+//https://issues.dlang.org/show_bug.cgi?id=22185
+@system unittest
+{
+ import std.stdio;
+ static struct ThrowingCopy
+ {
+ int x = 420;
+ this(ref return scope ThrowingCopy rhs)
+ {
+ rhs.x = 420;
+ //
+ throw new Exception("This throws");
+ }
+ ~this()
+ {
+ /*
+ Any time this destructor runs, it should be running on "valid"
+ data. This is is mimicked by having a .init other than 0 (the value the memory
+ practically will be from the GC).
+ */
+ if (x != 420)
+ {
+ //This will only trigger during GC finalization so avoid writefln for now.
+ printf("Destructor failure in ThrowingCopy(%d) @ %p", x, &this);
+ assert(x == 420, "unittest destructor failed");
+ }
+ }
+ }
+ static struct LyingThrowingRange
+ {
+ enum size_t length = 100;
+ enum size_t evilRealLength = 50;
+ size_t idx;
+ ThrowingCopy front()
+ {
+ return ThrowingCopy(12);
+ }
+ bool empty()
+ {
+ return idx == evilRealLength;
+ }
+ void popFront()
+ {
+ ++idx;
+ }
+ }
+ static assert(hasLength!LyingThrowingRange);
+ import std.exception : assertThrown;
+ {
+ assertThrown(array(LyingThrowingRange()));
+ }
+ import core.memory : GC;
+ /*
+ Force a collection early. Doesn't always actually finalize the bad objects
+ but trying to collect soon after the allocation is thrown away means any potential failures
+ will happen earlier.
+ */
+ GC.collect();
+}
/**
Returns a newly allocated associative array from a range of key/value tuples
@@ -939,6 +1047,11 @@ if (isDynamicArray!T && allSatisfy!(isIntegral, I))
// from rt/lifetime.d
private extern(C) void[] _d_newarrayU(const TypeInfo ti, size_t length) pure nothrow;
+// from rt/tracegc.d
+version (D_ProfileGC)
+private extern (C) void[] _d_newarrayUTrace(string file, size_t line,
+ string funcname, const scope TypeInfo ti, size_t length) pure nothrow;
+
private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes) nothrow
{
static assert(I.length <= nDimensions!T,
@@ -992,7 +1105,15 @@ private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes) nothrow
_d_newarrayU returns a void[], but with the length set according
to E.sizeof.
+/
- *(cast(void[]*)&ret) = _d_newarrayU(typeid(E[]), size);
+ version (D_ProfileGC)
+ {
+ // FIXME: file, line, function should be propagated from the
+ // caller, not here.
+ *(cast(void[]*)&ret) = _d_newarrayUTrace(__FILE__, __LINE__,
+ __FUNCTION__, typeid(E[]), size);
+ }
+ else
+ *(cast(void[]*)&ret) = _d_newarrayU(typeid(E[]), size);
static if (minimallyInitialized && hasIndirections!E)
// _d_newarrayU would have asserted if the multiplication below
// had overflowed, so we don't have to check it again.