Skip to content

Commit e15e7c0

Browse files
authored
Merge pull request #4734 from lodo1995/fix_emplace
Fix emplace for inner classes
2 parents bf3669f + b96a330 commit e15e7c0

File tree

3 files changed

+63
-10
lines changed

3 files changed

+63
-10
lines changed

std/conv.d

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4273,6 +4273,11 @@ Given a raw memory area $(D chunk), constructs an object of $(D class)
42734273
type $(D T) at that address. The constructor is passed the arguments
42744274
$(D Args).
42754275
4276+
If `T` is an inner class whose `outer` field can be used to access an instance
4277+
of the enclosing class, then `Args` must not be empty, and the first member of it
4278+
must be a valid initializer for that `outer` field. Correct initialization of
4279+
this field is essential to access members of the outer class inside `T` methods.
4280+
42764281
Preconditions:
42774282
$(D chunk) must be at least as large as $(D T) needs
42784283
and should have an alignment multiple of $(D T)'s alignment. (The size
@@ -4298,18 +4303,30 @@ if (is(T == class))
42984303
// Initialize the object in its pre-ctor state
42994304
chunk[0 .. classSize] = typeid(T).initializer[];
43004305

4306+
static if (isInnerClass!T)
4307+
{
4308+
static assert(Args.length > 0,
4309+
"Initializing an inner class requires a pointer to the outer class");
4310+
static assert(is(Args[0] : typeof(T.outer)),
4311+
"The first argument must be a pointer to the outer class");
4312+
4313+
result.outer = args[0];
4314+
alias args1 = args[1..$];
4315+
}
4316+
else alias args1 = args;
4317+
43014318
// Call the ctor if any
4302-
static if (is(typeof(result.__ctor(args))))
4319+
static if (is(typeof(result.__ctor(args1))))
43034320
{
43044321
// T defines a genuine constructor accepting args
43054322
// Go the classic route: write .init first, then call ctor
4306-
result.__ctor(args);
4323+
result.__ctor(args1);
43074324
}
43084325
else
43094326
{
4310-
static assert(args.length == 0 && !is(typeof(&T.__ctor)),
4327+
static assert(args1.length == 0 && !is(typeof(&T.__ctor)),
43114328
"Don't know how to initialize an object of type "
4312-
~ T.stringof ~ " with arguments " ~ Args.stringof);
4329+
~ T.stringof ~ " with arguments " ~ typeof(args1).stringof);
43134330
}
43144331
return result;
43154332
}
@@ -4327,6 +4344,22 @@ if (is(T == class))
43274344
assert(c.i == 5);
43284345
}
43294346

4347+
@system unittest
4348+
{
4349+
class Outer
4350+
{
4351+
int i = 3;
4352+
class Inner
4353+
{
4354+
auto getI() { return i; }
4355+
}
4356+
}
4357+
auto outerBuf = new void[__traits(classInstanceSize, Outer)];
4358+
auto innerBuf = new void[__traits(classInstanceSize, Outer.Inner)];
4359+
auto inner = innerBuf.emplace!(Outer.Inner)(outerBuf.emplace!Outer);
4360+
assert(inner.getI == 3);
4361+
}
4362+
43304363
@nogc pure nothrow unittest
43314364
{
43324365
int var = 6;

std/experimental/allocator/package.d

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,19 @@ unittest
476476
assert(cust.id == uint.max); // default initialized
477477
cust = theAllocator.make!Customer(42);
478478
assert(cust.id == 42);
479+
480+
// explicit passing of outer pointer
481+
static class Outer
482+
{
483+
int x = 3;
484+
class Inner
485+
{
486+
auto getX() { return x; }
487+
}
488+
}
489+
auto outer = theAllocator.make!Outer();
490+
auto inner = theAllocator.make!(Outer.Inner)(outer);
491+
assert(outer.x == inner.getX);
479492
}
480493

481494
unittest // bugzilla 15639 & 15772

std/traits.d

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
* $(LREF hasNested)
4747
* $(LREF hasUnsharedAliasing)
4848
* $(LREF InterfacesTuple)
49+
* $(LREF isInnerClass)
4950
* $(LREF isNested)
5051
* $(LREF MemberFunctionsTuple)
5152
* $(LREF RepresentationTypeTuple)
@@ -2036,8 +2037,11 @@ template isInnerClass(T)
20362037
{
20372038
import std.meta : staticIndexOf;
20382039

2039-
enum isInnerClass = __traits(isSame, typeof(T.outer), __traits(parent, T))
2040-
&& (staticIndexOf!(__traits(allMembers, T), "outer") == -1);
2040+
static if (is(typeof(T.outer)))
2041+
enum isInnerClass = __traits(isSame, typeof(T.outer), __traits(parent, T))
2042+
&& (staticIndexOf!(__traits(allMembers, T), "outer") == -1);
2043+
else
2044+
enum isInnerClass = false;
20412045
}
20422046

20432047
///
@@ -2051,15 +2055,18 @@ template isInnerClass(T)
20512055

20522056
class Outer1
20532057
{
2054-
class Inner
2058+
class Inner1 { }
2059+
class Inner2
20552060
{
2061+
int outer;
20562062
}
20572063
}
2058-
static assert(isInnerClass!(Outer1.Inner));
2064+
static assert(isInnerClass!(Outer1.Inner1));
2065+
static assert(!isInnerClass!(Outer1.Inner2));
20592066

2060-
class Outer2
2067+
static class Outer2
20612068
{
2062-
class Inner
2069+
static class Inner
20632070
{
20642071
int outer;
20652072
}

0 commit comments

Comments
 (0)