Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Placement New #17057

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions changelog/dmd.placementNew.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Added Placement New Expression

Placement new explicitly provides the storage for NewExpression to initialize
with the newly created value, rather than using the GC.

---
struct S
{
float d;
int i;
char c;
}

void main()
{
S s;
S* p = new (s) S(); // place new object into s
assert(p.i == 0 && p.c == 0xFF);
}
---
8 changes: 6 additions & 2 deletions compiler/src/dmd/astbase.d
Original file line number Diff line number Diff line change
Expand Up @@ -4814,10 +4814,12 @@
Expression thisexp; // if !=null, 'this' for class being allocated
ClassDeclaration cd; // class being instantiated
Expressions* arguments; // Array of Expression's to call class constructor
Expression placement; // if != null, then PlacementExpression

extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments)
extern (D) this(const ref Loc loc, Expression placement, Expression thisexp, ClassDeclaration cd, Expressions* arguments)

Check warning on line 4819 in compiler/src/dmd/astbase.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/astbase.d#L4819

Added line #L4819 was not covered by tests
{
super(loc, EXP.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
this.placement = placement;

Check warning on line 4822 in compiler/src/dmd/astbase.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/astbase.d#L4822

Added line #L4822 was not covered by tests
this.thisexp = thisexp;
this.cd = cd;
this.arguments = arguments;
Expand Down Expand Up @@ -5026,10 +5028,12 @@
Type newtype;
Expressions* arguments; // Array of Expression's
Identifiers* names; // Array of names corresponding to expressions
Expression placement; // if != null, then PlacementExpression

extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null)
extern (D) this(const ref Loc loc, Expression placement, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null)

Check warning on line 5033 in compiler/src/dmd/astbase.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/astbase.d#L5033

Added line #L5033 was not covered by tests
{
super(loc, EXP.new_, __traits(classInstanceSize, NewExp));
this.placement = placement;

Check warning on line 5036 in compiler/src/dmd/astbase.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/astbase.d#L5036

Added line #L5036 was not covered by tests
this.thisexp = thisexp;
this.newtype = newtype;
this.arguments = arguments;
Expand Down
9 changes: 8 additions & 1 deletion compiler/src/dmd/dinterpret.d
Original file line number Diff line number Diff line change
Expand Up @@ -2794,6 +2794,13 @@
printf("%s NewExp::interpret() %s\n", e.loc.toChars(), e.toChars());
}

if (e.placement)
{
error(e.placement.loc, "`new ( %s )` PlacementExpression cannot be evaluated at compile time", e.placement.toChars());
result = CTFEExp.cantexp;
return;

Check warning on line 2801 in compiler/src/dmd/dinterpret.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/dinterpret.d#L2799-L2801

Added lines #L2799 - L2801 were not covered by tests
}

Expression epre = interpret(pue, e.argprefix, istate, CTFEGoal.Nothing);
if (exceptionOrCant(epre))
return;
Expand Down Expand Up @@ -5040,7 +5047,7 @@
auto ce = e.e2.isCallExp();
assert(ce);

auto ne = new NewExp(e.loc, null, e.type, ce.arguments);
auto ne = new NewExp(e.loc, null, null, e.type, ce.arguments);

Check warning on line 5050 in compiler/src/dmd/dinterpret.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/dinterpret.d#L5050

Added line #L5050 was not covered by tests
ne.type = e.e1.type;

result = interpret(ne, istate);
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -1312,9 +1312,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
ex = (cast(AssignExp)ex).e2;
if (auto ne = ex.isNewExp())
{
if (ne.placement)
{
}
/* See if initializer is a NewExp that can be allocated on the stack.
*/
if (dsym.type.toBasetype().ty == Tclass)
else if (dsym.type.toBasetype().ty == Tclass)
{
/* Unsafe to allocate on stack if constructor is not `scope` because the `this` can leak.
* https://issues.dlang.org/show_bug.cgi?id=23145
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dmd/dtemplate.d
Original file line number Diff line number Diff line change
Expand Up @@ -3008,6 +3008,8 @@
override void visit(NewExp e)
{
//printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars());
if (e.placement)
e.placement.accept(this);

Check warning on line 3012 in compiler/src/dmd/dtemplate.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/dtemplate.d#L3011-L3012

Added lines #L3011 - L3012 were not covered by tests
if (e.thisexp)
e.thisexp.accept(this);
result = e.newtype.reliesOnTemplateParameters(tparams);
Expand Down
59 changes: 41 additions & 18 deletions compiler/src/dmd/e2ir.d
Original file line number Diff line number Diff line change
Expand Up @@ -1126,19 +1126,27 @@
elem *ezprefix = null;
elem *ez = null;

if (ne.onstack)
if (ne.onstack || ne.placement)
{
/* Create an instance of the class on the stack,
* and call it stmp.
* Set ex to be the &stmp.
*/
.type *tc = type_struct_class(tclass.sym.toChars(),
tclass.sym.alignsize, tclass.sym.structsize,
null, null,
false, false, true, false);
tc.Tcount--;
Symbol *stmp = symbol_genauto(tc);
ex = el_ptr(stmp);
if (ne.placement)
{
ex = toElem(ne.placement, irs);
ex = addressElem(ex, ne.newtype.toBasetype(), false);
}
else
{
/* Create an instance of the class on the stack,
* and call it stmp.
* Set ex to be the &stmp.
*/
.type *tc = type_struct_class(tclass.sym.toChars(),
tclass.sym.alignsize, tclass.sym.structsize,
null, null,
false, false, true, false);
tc.Tcount--;
Symbol *stmp = symbol_genauto(tc);
ex = el_ptr(stmp);
}

Symbol *si = toInitializer(tclass.sym);
elem *ei = el_var(si);
Expand Down Expand Up @@ -1265,8 +1273,13 @@
elem *ezprefix = null;
elem *ez = null;

// Call _d_newitemT()
if (auto lowering = ne.lowering)
if (ne.placement)
{
ex = toElem(ne.placement, irs);
ex = addressElem(ex, tclass, false);
}
else if (auto lowering = ne.lowering)
// Call _d_newitemT()
ex = toElem(ne.lowering, irs);
else
assert(0, "This case should have been rewritten to `_d_newitemT` in the semantic phase");
Expand All @@ -1276,7 +1289,7 @@
elem *ev = el_same(ex);

if (ne.argprefix)
ezprefix = toElem(ne.argprefix, irs);
ezprefix = toElem(ne.argprefix, irs);

Check warning on line 1292 in compiler/src/dmd/e2ir.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/e2ir.d#L1292

Added line #L1292 was not covered by tests
if (ne.member)
{
if (sd.isNested())
Expand Down Expand Up @@ -1308,10 +1321,12 @@
{
StructLiteralExp sle = StructLiteralExp.create(ne.loc, sd, ne.arguments, t);
ez = toElemStructLit(sle, irs, EXP.construct, ev.Vsym, false);
if (tybasic(ez.Ety) == TYstruct)
ez = el_una(OPaddr, TYnptr, ez);
}
//elem_print(ex);
//elem_print(ey);
//elem_print(ez);
//printf("ez:\n"); elem_print(ez);

e = el_combine(ex, ey);
e = el_combine(e, ew);
Expand All @@ -1331,8 +1346,16 @@
{
elem *ezprefix = ne.argprefix ? toElem(ne.argprefix, irs) : null;

// call _d_newitemT()
e = toElem(ne.lowering, irs);
if (ne.placement)
{
e = toElem(ne.placement, irs);
e = addressElem(e, ne.newtype.toBasetype(), false);
}
else if (auto lowering = ne.lowering)
// Call _d_newitemT()
e = toElem(ne.lowering, irs);
else
assert(0, "This case should have been rewritten to `_d_newitemT` in the semantic phase");

if (ne.arguments && ne.arguments.length == 1)
{
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dmd/escape.d
Original file line number Diff line number Diff line change
Expand Up @@ -1637,6 +1637,9 @@ void escapeExp(Expression e, ref scope EscapeByResults er, int deref)

void visitNew(NewExp e)
{
if (e.placement)
escapeExp(e.placement, er, deref);

Type tb = e.newtype.toBasetype();
if (tb.isTypeStruct() && !e.member && e.arguments)
{
Expand Down
17 changes: 12 additions & 5 deletions compiler/src/dmd/expression.d
Original file line number Diff line number Diff line change
Expand Up @@ -2560,6 +2560,7 @@
Type newtype;
Expressions* arguments; // Array of Expression's
Identifiers* names; // Array of names corresponding to expressions
Expression placement; // if !=null, then PlacementExpression

Expression argprefix; // expression to be evaluated just before arguments[]
CtorDeclaration member; // constructor function
Expand All @@ -2572,23 +2573,25 @@
/// The fields are still separate for backwards compatibility
extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); }

extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null) @safe
extern (D) this(const ref Loc loc, Expression placement, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null) @safe
{
super(loc, EXP.new_);
this.placement = placement;
this.thisexp = thisexp;
this.newtype = newtype;
this.arguments = arguments;
this.names = names;
}

static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments) @safe
static NewExp create(const ref Loc loc, Expression placement, Expression thisexp, Type newtype, Expressions* arguments) @safe
{
return new NewExp(loc, thisexp, newtype, arguments);
return new NewExp(loc, placement, thisexp, newtype, arguments);

Check warning on line 2588 in compiler/src/dmd/expression.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expression.d#L2588

Added line #L2588 was not covered by tests
}

override NewExp syntaxCopy()
{
return new NewExp(loc,
placement ? placement.syntaxCopy() : null,
thisexp ? thisexp.syntaxCopy() : null,
newtype.syntaxCopy(),
arraySyntaxCopy(arguments),
Expand All @@ -2609,18 +2612,22 @@
Expression thisexp; // if !=null, 'this' for class being allocated
ClassDeclaration cd; // class being instantiated
Expressions* arguments; // Array of Expression's to call class constructor
Expression placement; // if !=null, then PlacementExpression

extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments) @safe
extern (D) this(const ref Loc loc, Expression placement, Expression thisexp, ClassDeclaration cd, Expressions* arguments) @safe
{
super(loc, EXP.newAnonymousClass);
this.placement = placement;
this.thisexp = thisexp;
this.cd = cd;
this.arguments = arguments;
}

override NewAnonClassExp syntaxCopy()
{
return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, cd.syntaxCopy(null), arraySyntaxCopy(arguments));
return new NewAnonClassExp(loc, placement ? placement.syntaxCopy : null,
thisexp ? thisexp.syntaxCopy() : null,
cd.syntaxCopy(null), arraySyntaxCopy(arguments));
}

override void accept(Visitor v)
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dmd/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ class NewExp final : public Expression
Type *newtype;
Expressions *arguments; // Array of Expression's
Identifiers *names; // Array of names corresponding to expressions
Expression *placement; // if !NULL, placement expression

Expression *argprefix; // expression to be evaluated just before arguments[]

Expand All @@ -519,7 +520,7 @@ class NewExp final : public Expression

Expression *lowering; // lowered druntime hook: `_d_newclass`

static NewExp *create(const Loc &loc, Expression *thisexp, Type *newtype, Expressions *arguments);
static NewExp *create(const Loc &loc, Expression *placement, Expression *thisexp, Type *newtype, Expressions *arguments);
NewExp *syntaxCopy() override;

void accept(Visitor *v) override { v->visit(this); }
Expand All @@ -533,6 +534,7 @@ class NewAnonClassExp final : public Expression
Expression *thisexp; // if !NULL, 'this' for class being allocated
ClassDeclaration *cd; // class being instantiated
Expressions *arguments; // Array of Expression's to call class constructor
Expression *placement; // if !NULL, placement expression

NewAnonClassExp *syntaxCopy() override;
void accept(Visitor *v) override { v->visit(this); }
Expand Down
Loading
Loading