diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-02-13 20:17:53 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-02-16 11:15:02 +0100 |
commit | d75691877c4a7521a995d2601021fcaf30f65d94 (patch) | |
tree | 36509d835d63b98ad1130ac9d4695b5033c10428 /libphobos/src/std/array.d | |
parent | 023327643969d5469902a9ecfa6738a315f9e362 (diff) | |
download | gcc-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.d | 133 |
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. |