Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit b99260f

Browse files
authored
Merge pull request #3035 from kinke/emplace
[stable] Fix code bloat regressions wrt. core.internal.lifetime.emplaceInitializer merged-on-behalf-of: Nicholas Wilson <thewilsonator@users.noreply.github.com>
2 parents b6f45c8 + 1c74ef3 commit b99260f

File tree

2 files changed

+76
-28
lines changed

2 files changed

+76
-28
lines changed

src/core/internal/lifetime.d

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,23 +84,84 @@ if (is(UT == core.internal.traits.Unqual!UT))
8484
emplaceRef!(UT, UT)(chunk, forward!args);
8585
}
8686

87-
//emplace helper functions
88-
private nothrow pure @trusted
89-
void emplaceInitializer(T)(scope ref T chunk)
87+
/+
88+
Emplaces T.init.
89+
In contrast to `emplaceRef(chunk)`, there are no checks for disabled default
90+
constructors etc.
91+
+/
92+
void emplaceInitializer(T)(scope ref T chunk) nothrow pure @trusted
93+
if (!is(T == const) && !is(T == immutable) && !is(T == inout))
9094
{
91-
// Emplace T.init.
92-
// Previously, an immutable static and memcpy were used to hold an initializer.
93-
// With improved unions, this is no longer needed.
94-
union UntypedInit
95+
import core.internal.traits : hasElaborateAssign;
96+
97+
static if (!hasElaborateAssign!T && __traits(compiles, chunk = T.init))
98+
{
99+
chunk = T.init;
100+
}
101+
else static if (__traits(isZeroInit, T))
102+
{
103+
static if (is(T U == shared U))
104+
alias Unshared = U;
105+
else
106+
alias Unshared = T;
107+
108+
import core.stdc.string : memset;
109+
memset(cast(Unshared*) &chunk, 0, T.sizeof);
110+
}
111+
else
95112
{
96-
T dummy;
113+
// emplace T.init (an rvalue) without extra variable (and according destruction)
114+
alias RawBytes = void[T.sizeof];
115+
116+
static union U
117+
{
118+
T dummy = T.init; // U.init corresponds to T.init
119+
RawBytes data;
120+
}
121+
122+
*cast(RawBytes*) &chunk = U.init.data;
97123
}
98-
static struct UntypedStorage
124+
}
125+
126+
@safe unittest
127+
{
128+
static void testInitializer(T)()
129+
{
130+
// mutable T
131+
{
132+
T dst = void;
133+
emplaceInitializer(dst);
134+
assert(dst is T.init);
135+
}
136+
137+
// shared T
138+
{
139+
shared T dst = void;
140+
emplaceInitializer(dst);
141+
assert(dst is shared(T).init);
142+
}
143+
144+
// const T
145+
{
146+
const T dst = void;
147+
static assert(!__traits(compiles, emplaceInitializer(dst)));
148+
}
149+
}
150+
151+
static struct ElaborateAndZero
152+
{
153+
int a;
154+
this(this) {}
155+
}
156+
157+
static struct ElaborateAndNonZero
99158
{
100-
align(T.alignof) void[T.sizeof] dummy;
159+
int a = 42;
160+
this(this) {}
101161
}
102162

103-
() @trusted {
104-
*cast(UntypedStorage*) &chunk = cast(UntypedStorage) UntypedInit.init;
105-
} ();
163+
testInitializer!int();
164+
testInitializer!double();
165+
testInitializer!ElaborateAndZero();
166+
testInitializer!ElaborateAndNonZero();
106167
}

src/object.d

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3394,21 +3394,8 @@ void destroy(bool initialize = true, T)(ref T obj) if (is(T == struct))
33943394

33953395
static if (initialize)
33963396
{
3397-
// We need to re-initialize `obj`. Previously, an immutable static
3398-
// and memcpy were used to hold an initializer. With improved unions, this is no longer
3399-
// needed.
3400-
union UntypedInit
3401-
{
3402-
T dummy;
3403-
}
3404-
static struct UntypedStorage
3405-
{
3406-
align(T.alignof) void[T.sizeof] dummy;
3407-
}
3408-
3409-
() @trusted {
3410-
*cast(UntypedStorage*) &obj = cast(UntypedStorage) UntypedInit.init;
3411-
} ();
3397+
import core.internal.lifetime : emplaceInitializer;
3398+
emplaceInitializer(obj); // emplace T.init
34123399
}
34133400
}
34143401

0 commit comments

Comments
 (0)