mirror of
https://github.com/openRuyi-Project/gcc.git
synced 2026-09-06 14:01:37 +00:00
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.
239 lines
6.9 KiB
D
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();
|
|
}
|
|
}
|
|
}
|