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 15, 2024
1 parent a555e13 commit 902a3a9
Show file tree
Hide file tree
Showing 21 changed files with 323 additions and 41 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
46 changes: 43 additions & 3 deletions compiler/src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -3130,7 +3130,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
auto args = new Expressions(nargs - i);
foreach (u; i .. nargs)
(*args)[u - i] = (*arguments)[u];
arg = new NewExp(loc, null, p.type, args);
arg = new NewExp(loc, null, null, p.type, args);
break;
}
default:
Expand Down Expand Up @@ -4902,6 +4902,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}

if (exp.placement)
{
exp.placement = exp.placement.expressionSemantic(sc);
auto p = exp.placement;
if (p.op == EXP.error)
return setError();

Check warning on line 4910 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L4910

Added line #L4910 was not covered by tests
if (!p.isLvalue())
{
error(p.loc, "PlacementExpression `%s` is an rvalue, but must be an lvalue", p.toChars());
return setError();

Check warning on line 4914 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L4913-L4914

Added lines #L4913 - L4914 were not covered by tests
}
}

//for error messages if the argument in [] is not convertible to size_t
const originalNewtype = exp.newtype;

Expand Down Expand Up @@ -4988,6 +5001,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}

uinteger_t placementSize;
if (exp.placement)
{
placementSize = size(exp.placement.type, exp.placement.loc);
auto objectSize = size(tb, exp.placement.loc);
//printf("placementSize: %lld objectSize: %lld\n", placementSize, objectSize);
if (!tb.isTypeClass && placementSize < objectSize)
{
error(exp.placement.loc, "new placement size %llu must be >= object size %llu", placementSize, objectSize);
return setError();

Check warning on line 5013 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L5012-L5013

Added lines #L5012 - L5013 were not covered by tests
}
}

const size_t nargs = exp.arguments ? exp.arguments.length : 0;
Expression newprefix = null;

Expand All @@ -4996,9 +5022,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto cd = tc.sym;
if (cd.errors)
return setError();
cd.size(exp.loc);
auto objectSize = cd.size(exp.loc);
if (cd.sizeok != Sizeok.done)
return setError();
if (exp.placement && placementSize < objectSize)
{
error(exp.placement.loc, "new placement size %llu must be >= class object size %llu", placementSize, objectSize);
return setError();

Check warning on line 5031 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L5030-L5031

Added lines #L5030 - L5031 were not covered by tests
}
if (!cd.ctor)
cd.ctor = cd.searchCtor();
if (cd.noDefaultCtor && !nargs && !cd.defaultCtor)
Expand Down Expand Up @@ -5506,6 +5537,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else if (tb.ty == Taarray)
{
if (exp.placement)
{
error(exp.placement.loc, "placement new cannot be used with associative arrays");
return setError();

Check warning on line 5543 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L5542-L5543

Added lines #L5542 - L5543 were not covered by tests
}
// e.g. `new Alias(args)`
if (nargs)
{
Expand Down Expand Up @@ -5555,7 +5591,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
sds.members.push(e.cd);
}

Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments);
Expression n = new NewExp(e.loc, e.placement, e.thisexp, e.cd.type, e.arguments);

Expression c = new CommaExp(e.loc, d, n);
result = c.expressionSemantic(sc);
Expand Down Expand Up @@ -15091,6 +15127,8 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)

bool visitNew(NewExp e)
{
if (e.placement)
check(e.placement, false);

Check warning on line 15131 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L15131

Added line #L15131 was not covered by tests
if (e.thisexp)
check(e.thisexp, false);
return false;
Expand Down Expand Up @@ -15274,6 +15312,8 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)

Expression visitNew(NewExp exp)
{
if (exp.placement)
exp.placement = exp.placement.resolveLoc(loc, sc);

Check warning on line 15316 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L15316

Added line #L15316 was not covered by tests
if (exp.thisexp)
exp.thisexp = exp.thisexp.resolveLoc(loc, sc);
if (exp.argprefix)
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -3117,6 +3117,7 @@ class NewAnonClassExp final : public Expression
Expression* thisexp;
ClassDeclaration* cd;
Array<Expression* >* arguments;
Expression* placement;
NewAnonClassExp* syntaxCopy() override;
void accept(Visitor* v) override;
};
Expand All @@ -3128,12 +3129,13 @@ class NewExp final : public Expression
Type* newtype;
Array<Expression* >* arguments;
Array<Identifier* >* names;
Expression* placement;
Expression* argprefix;
CtorDeclaration* member;
bool onstack;
bool thrownew;
Expression* lowering;
static NewExp* create(const Loc& loc, Expression* thisexp, Type* newtype, Array<Expression* >* arguments);
static NewExp* create(const Loc& loc, Expression* placement, Expression* thisexp, Type* newtype, Array<Expression* >* arguments);
NewExp* syntaxCopy() override;
void accept(Visitor* v) override;
};
Expand Down
Loading

0 comments on commit 902a3a9

Please sign in to comment.