Files
Iain Buclaw 8b0ccc95f1 d: Merge upstream dmd, druntime e1f6680f50, phobos f87979028
D front-end changes:

	- Import latest fixes from v2.112.0-beta.1.
	- Associative array operations are now lowered to templates
	  defined in `core.internal.newaa'.

D runtime changes:

	- Import latest fixes from v2.112.0-beta.1.

Phobos changes:

	- Import latest fixes from v2.112.0-beta.1.

gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd e1f6680f50.
	* Make-lang.in (D_FRONTEND_OBJS): Remove d/gluelayer.o, d/iasm.o,
	d/iasmgcc.o.  Add d/iasm-package.o, d/iasm-gcc.o.
	(d/iasm-%.o): New recipe.
	* d-convert.cc (convert_expr): Remove library call to dynamic_cast.
	* d-lang.cc (d_init_options): Set errorSupplementLimit parameter.
	* decl.cc (DeclVisitor::visit): Update for new front-end interface.
	* expr.cc (ExprVisitor::visit (EqualExp *)): Update for front-end
	lowering expression using templates.
	(ExprVisitor::visit (InExp *)): Likewise.
	(ExprVisitor::visit (IndexExp *)): Likewise.
	(ExprVisitor::visit (CastExp *)): Likewise.
	(ExprVisitor::visit (RemoveExp *)): Likewise.
	(ExprVisitor::visit (AddrExp *)): Likewise.
	(ExprVisitor::visit (NewExp *)): Likewise.
	(ExprVisitor::visit (ArrayLiteralExp *)): Likewise.
	(ExprVisitor::visit (AssocArrayLiteralExp *)): Likewise.
	* imports.cc (ImportVisitor::visit (AliasDeclaration *)): Update for
	new front-end interface.
	* runtime.def (DYNAMIC_CAST): Remove.
	(INTERFACE_CAST): Remove.
	(ARRAYLITERALTX): Remove.
	(ADEQ2): Remove.
	(ASSOCARRAYLITERALTX): Remove.
	(AANEW): Remove.
	(AAEQUAL): Remove.
	(AAINX): Remove.
	(AAGETY): Remove.
	(AAGETRVALUEX): Remove.
	(AADELX): Remove.
	* typeinfo.cc (TypeInfoVisitor::visit): Layout xopEquals and xtoHash
	in TypeInfo_AssociativeArray.
	(create_typeinfo): Add new fields to internal typeinfo.
	(check_typeinfo_type): Print instantiation trace of error.
	* types.cc (TypeVisitor::visit (TypeStruct *)): Update for new
	front-end interface.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime e1f6680f50.
	* libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add
	core/internal/cast_.d.  Remove rt/aaA.d, rt/adi.d, rt/cast_.d.
	(DRUNTIME_DSOURCES_POSIX): Add core/sys/posix/endian.d.
	* libdruntime/Makefile.in: Regenerate.
	* src/MERGE: Merge upstream phobos f87979028.
	* src/Makefile.am (PHOBOS_DSOURCES): Add std/internal/entropy.d.
	* src/Makefile.in: Regenerate.
	* testsuite/libphobos.aa/test_aa.d: Adjust test.
	* testsuite/libphobos.init_fini/custom_gc.d: Likewise.

gcc/testsuite/ChangeLog:

	* gdc.dg/asm1.d: Adjust test.
	* gdc.dg/asm5.d: Likewise.
	* gdc.dg/pr100967.d: Likewise.
	* gdc.dg/rtti1.d: Likewise.
	* gdc.dg/rtti2.d: New test.
2026-01-31 09:37:45 +01:00

239 lines
6.9 KiB
D

module core.internal.lifetime;
import core.lifetime : forward;
/+
emplaceRef is a package function for druntime internal use. It works like
emplace, but takes its argument by ref (as opposed to "by pointer").
This makes it easier to use, easier to be safe, and faster in a non-inline
build.
Furthermore, emplaceRef optionally takes a type parameter, which specifies
the type we want to build. This helps to build qualified objects on mutable
buffer, without breaking the type system with unsafe casts.
+/
void emplaceRef(T, UT, Args...)(ref UT chunk, auto ref Args args)
{
static if (args.length == 0)
{
static assert(is(typeof({static T i;})),
"Cannot emplace a " ~ T.stringof ~ " because " ~ T.stringof ~
".this() is annotated with @disable.");
static if (is(T == class)) static assert(!__traits(isAbstractClass, T),
T.stringof ~ " is abstract and it can't be emplaced");
emplaceInitializer(chunk);
}
else static if (
!is(T == struct) && Args.length == 1 /* primitives, enums, arrays */
||
Args.length == 1 && is(typeof({T t = forward!(args[0]);})) /* conversions */
||
is(typeof(T(forward!args))) /* general constructors */)
{
static struct S
{
T payload;
this()(auto ref Args args)
{
static if (__traits(compiles, payload = forward!args))
payload = forward!args;
else
payload = T(forward!args);
}
}
if (__ctfe)
{
static if (__traits(compiles, chunk = T(forward!args)))
chunk = T(forward!args);
else static if (args.length == 1 && __traits(compiles, chunk = forward!(args[0])))
chunk = forward!(args[0]);
else assert(0, "CTFE emplace doesn't support "
~ T.stringof ~ " from " ~ Args.stringof);
}
else
{
S* p = () @trusted { return cast(S*) &chunk; }();
static if (UT.sizeof > 0)
emplaceInitializer(*p);
p.__ctor(forward!args);
}
}
else static if (is(typeof(chunk.__ctor(forward!args))))
{
// This catches the rare case of local types that keep a frame pointer
emplaceInitializer(chunk);
chunk.__ctor(forward!args);
}
else
{
//We can't emplace. Try to diagnose a disabled postblit.
static assert(!(Args.length == 1 && is(Args[0] : T)),
"Cannot emplace a " ~ T.stringof ~ " because " ~ T.stringof ~
".this(this) is annotated with @disable.");
//We can't emplace.
static assert(false,
T.stringof ~ " cannot be emplaced from " ~ Args[].stringof ~ ".");
}
}
// ditto
static import core.internal.traits;
void emplaceRef(UT, Args...)(ref UT chunk, auto ref Args args)
if (is(UT == core.internal.traits.Unqual!UT))
{
emplaceRef!(UT, UT)(chunk, forward!args);
}
/+
Emplaces T.init.
In contrast to `emplaceRef(chunk)`, there are no checks for disabled default
constructors etc.
+/
void emplaceInitializer(T)(scope ref T chunk) nothrow pure @trusted
if (!is(T == const) && !is(T == immutable) && !is(T == inout))
{
import core.internal.traits : hasElaborateAssign;
static if (__traits(isZeroInit, T))
{
import core.stdc.string : memset;
memset(cast(void*) &chunk, 0, T.sizeof);
}
else static if (__traits(isScalar, T) ||
T.sizeof <= 16 && !hasElaborateAssign!T && __traits(compiles, (){ T chunk; chunk = T.init; }))
{
chunk = T.init;
}
else static if (__traits(isStaticArray, T))
{
// For static arrays there is no initializer symbol created. Instead, we emplace elements one-by-one.
foreach (i; 0 .. T.length)
{
emplaceInitializer(chunk[i]);
}
}
else
{
import core.stdc.string : memcpy;
const initializer = __traits(initSymbol, T);
memcpy(cast(void*)&chunk, initializer.ptr, initializer.length);
}
}
@safe unittest
{
static void testInitializer(T)()
{
// mutable T
{
T dst = void;
emplaceInitializer(dst);
assert(dst is T.init);
}
// shared T
{
shared T dst = void;
emplaceInitializer(dst);
assert(dst is shared(T).init);
}
// const T
{
const T dst = void;
static assert(!__traits(compiles, emplaceInitializer(dst)));
}
}
static struct ElaborateAndZero
{
int a;
this(this) {}
}
static struct ElaborateAndNonZero
{
int a = 42;
this(this) {}
}
static union LargeNonZeroUnion
{
byte[128] a = 1;
}
testInitializer!int();
testInitializer!double();
testInitializer!ElaborateAndZero();
testInitializer!ElaborateAndNonZero();
testInitializer!LargeNonZeroUnion();
static if (is(__vector(double[4])))
{
// DMD 2.096 and GDC 11.1 can't compare vectors with `is` so can't use
// testInitializer.
enum VE : __vector(double[4])
{
a = [1.0, 2.0, 3.0, double.nan],
b = [4.0, 5.0, 6.0, double.nan],
}
const VE expected = VE.a;
VE dst = VE.b;
shared VE sharedDst = VE.b;
emplaceInitializer(dst);
emplaceInitializer(sharedDst);
() @trusted {
import core.stdc.string : memcmp;
assert(memcmp(&expected, &dst, VE.sizeof) == 0);
assert(memcmp(&expected, cast(void*) &sharedDst, VE.sizeof) == 0);
}();
static assert(!__traits(compiles, emplaceInitializer(expected)));
}
}
/*
Simple swap function.
*/
void swap(T)(ref T lhs, ref T rhs)
{
import core.lifetime : move, moveEmplace;
T tmp = move(lhs);
moveEmplace(rhs, lhs);
moveEmplace(tmp, rhs);
}
void __doPostblit(T)(T[] arr)
{
// infer static postblit type, run postblit if any
static if (__traits(hasPostblit, T))
{
static if (__traits(isStaticArray, T) && is(T : E[], E))
__doPostblit(cast(E[]) arr);
else
{
import core.internal.traits : Unqual;
foreach (ref elem; (() @trusted => cast(Unqual!T[]) arr)())
elem.__xpostblit();
}
}
}
// ditto, but with an index to keep track of how many elements have been postblitted
void __doPostblit(T)(T[] arr, ref size_t i)
{
// infer static postblit type, run postblit if any
static if (__traits(hasPostblit, T))
{
static if (__traits(isStaticArray, T) && is(T : E[], E))
__doPostblit(cast(E[]) arr, i);
else
{
i = 0;
import core.internal.traits : Unqual;
for(auto eptr = cast(Unqual!T*)&arr[0]; i < arr.length; ++i, ++eptr)
eptr.__xpostblit();
}
}
}