Fortran: Fix PR 47485.
[gcc.git] / libphobos / libdruntime / core / internal / lifetime.d
bloba7446debae656495e63369bd5240832750a6da95
1 module core.internal.lifetime;
3 import core.lifetime : forward;
5 /+
6 emplaceRef is a package function for druntime internal use. It works like
7 emplace, but takes its argument by ref (as opposed to "by pointer").
8 This makes it easier to use, easier to be safe, and faster in a non-inline
9 build.
10 Furthermore, emplaceRef optionally takes a type parameter, which specifies
11 the type we want to build. This helps to build qualified objects on mutable
12 buffer, without breaking the type system with unsafe casts.
14 void emplaceRef(T, UT, Args...)(ref UT chunk, auto ref Args args)
16 static if (args.length == 0)
18 static assert(is(typeof({static T i;})),
19 "Cannot emplace a " ~ T.stringof ~ " because " ~ T.stringof ~
20 ".this() is annotated with @disable.");
21 static if (is(T == class)) static assert(!__traits(isAbstractClass, T),
22 T.stringof ~ " is abstract and it can't be emplaced");
23 emplaceInitializer(chunk);
25 else static if (
26 !is(T == struct) && Args.length == 1 /* primitives, enums, arrays */
28 Args.length == 1 && is(typeof({T t = forward!(args[0]);})) /* conversions */
30 is(typeof(T(forward!args))) /* general constructors */)
32 static struct S
34 T payload;
35 this()(auto ref Args args)
37 static if (__traits(compiles, payload = forward!args))
38 payload = forward!args;
39 else
40 payload = T(forward!args);
43 if (__ctfe)
45 static if (__traits(compiles, chunk = T(forward!args)))
46 chunk = T(forward!args);
47 else static if (args.length == 1 && __traits(compiles, chunk = forward!(args[0])))
48 chunk = forward!(args[0]);
49 else assert(0, "CTFE emplace doesn't support "
50 ~ T.stringof ~ " from " ~ Args.stringof);
52 else
54 S* p = () @trusted { return cast(S*) &chunk; }();
55 static if (UT.sizeof > 0)
56 emplaceInitializer(*p);
57 p.__ctor(forward!args);
60 else static if (is(typeof(chunk.__ctor(forward!args))))
62 // This catches the rare case of local types that keep a frame pointer
63 emplaceInitializer(chunk);
64 chunk.__ctor(forward!args);
66 else
68 //We can't emplace. Try to diagnose a disabled postblit.
69 static assert(!(Args.length == 1 && is(Args[0] : T)),
70 "Cannot emplace a " ~ T.stringof ~ " because " ~ T.stringof ~
71 ".this(this) is annotated with @disable.");
73 //We can't emplace.
74 static assert(false,
75 T.stringof ~ " cannot be emplaced from " ~ Args[].stringof ~ ".");
79 // ditto
80 static import core.internal.traits;
81 void emplaceRef(UT, Args...)(ref UT chunk, auto ref Args args)
82 if (is(UT == core.internal.traits.Unqual!UT))
84 emplaceRef!(UT, UT)(chunk, forward!args);
88 Emplaces T.init.
89 In contrast to `emplaceRef(chunk)`, there are no checks for disabled default
90 constructors etc.
92 void emplaceInitializer(T)(scope ref T chunk) nothrow pure @trusted
93 if (!is(T == const) && !is(T == immutable) && !is(T == inout))
95 import core.internal.traits : hasElaborateAssign;
97 static if (__traits(isZeroInit, T))
99 import core.stdc.string : memset;
100 memset(cast(void*) &chunk, 0, T.sizeof);
102 else static if (__traits(isScalar, T) ||
103 T.sizeof <= 16 && !hasElaborateAssign!T && __traits(compiles, (){ T chunk; chunk = T.init; }))
105 chunk = T.init;
107 else static if (__traits(isStaticArray, T))
109 // For static arrays there is no initializer symbol created. Instead, we emplace elements one-by-one.
110 foreach (i; 0 .. T.length)
112 emplaceInitializer(chunk[i]);
115 else
117 import core.stdc.string : memcpy;
118 const initializer = __traits(initSymbol, T);
119 memcpy(cast(void*)&chunk, initializer.ptr, initializer.length);
123 @safe unittest
125 static void testInitializer(T)()
127 // mutable T
129 T dst = void;
130 emplaceInitializer(dst);
131 assert(dst is T.init);
134 // shared T
136 shared T dst = void;
137 emplaceInitializer(dst);
138 assert(dst is shared(T).init);
141 // const T
143 const T dst = void;
144 static assert(!__traits(compiles, emplaceInitializer(dst)));
148 static struct ElaborateAndZero
150 int a;
151 this(this) {}
154 static struct ElaborateAndNonZero
156 int a = 42;
157 this(this) {}
160 static union LargeNonZeroUnion
162 byte[128] a = 1;
165 testInitializer!int();
166 testInitializer!double();
167 testInitializer!ElaborateAndZero();
168 testInitializer!ElaborateAndNonZero();
169 testInitializer!LargeNonZeroUnion();
171 static if (is(__vector(double[4])))
173 // DMD 2.096 and GDC 11.1 can't compare vectors with `is` so can't use
174 // testInitializer.
175 enum VE : __vector(double[4])
177 a = [1.0, 2.0, 3.0, double.nan],
178 b = [4.0, 5.0, 6.0, double.nan],
180 const VE expected = VE.a;
181 VE dst = VE.b;
182 shared VE sharedDst = VE.b;
183 emplaceInitializer(dst);
184 emplaceInitializer(sharedDst);
185 () @trusted {
186 import core.stdc.string : memcmp;
187 assert(memcmp(&expected, &dst, VE.sizeof) == 0);
188 assert(memcmp(&expected, cast(void*) &sharedDst, VE.sizeof) == 0);
189 }();
190 static assert(!__traits(compiles, emplaceInitializer(expected)));
195 Simple swap function.
197 void swap(T)(ref T lhs, ref T rhs)
199 import core.lifetime : move, moveEmplace;
201 T tmp = move(lhs);
202 moveEmplace(rhs, lhs);
203 moveEmplace(tmp, rhs);