Skip to content

Commit

Permalink
add Placement New
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Nov 22, 2024
1 parent eac47d7 commit 606be08
Show file tree
Hide file tree
Showing 21 changed files with 379 additions and 44 deletions.
8 changes: 6 additions & 2 deletions compiler/src/dmd/astbase.d
Original file line number Diff line number Diff line change
Expand Up @@ -4813,10 +4813,12 @@ struct ASTBase
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 4818 in compiler/src/dmd/astbase.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/astbase.d#L4818

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

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

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/astbase.d#L4821

Added line #L4821 was not covered by tests
this.thisexp = thisexp;
this.cd = cd;
this.arguments = arguments;
Expand Down Expand Up @@ -5025,10 +5027,12 @@ struct ASTBase
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 5032 in compiler/src/dmd/astbase.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/astbase.d#L5032

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

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

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/astbase.d#L5035

Added line #L5035 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 @@ public:
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 @@ -5067,7 +5074,7 @@ public:
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);
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 @@ -1304,9 +1304,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 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam
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 @@ -1116,19 +1116,27 @@ elem* toElem(Expression e, ref IRState irs)
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 @@ -1255,8 +1263,13 @@ elem* toElem(Expression e, ref IRState irs)
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 @@ -1266,7 +1279,7 @@ elem* toElem(Expression e, ref IRState irs)
elem *ev = el_same(ex);

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

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

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/e2ir.d#L1282

Added line #L1282 was not covered by tests
if (ne.member)
{
if (sd.isNested())
Expand Down Expand Up @@ -1298,10 +1311,12 @@ elem* toElem(Expression e, ref IRState irs)
{
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 @@ -1321,8 +1336,16 @@ elem* toElem(Expression e, ref IRState irs)
{
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 @@ -1635,6 +1635,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 @@ -2554,6 +2554,7 @@ extern (C++) final class NewExp : Expression
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 @@ -2566,23 +2567,25 @@ extern (C++) final class NewExp : Expression
/// 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 2582 in compiler/src/dmd/expression.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expression.d#L2582

Added line #L2582 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 @@ -2603,18 +2606,22 @@ extern (C++) final class NewAnonClassExp : 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, 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 @@ -509,6 +509,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 @@ -518,7 +519,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 @@ -532,6 +533,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

0 comments on commit 606be08

Please sign in to comment.