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 12, 2024
1 parent 7c8e8ec commit fd23a02
Show file tree
Hide file tree
Showing 20 changed files with 119 additions and 23 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
2 changes: 1 addition & 1 deletion compiler/src/dmd/backend/x86/cod2.d
Original file line number Diff line number Diff line change
Expand Up @@ -4664,7 +4664,7 @@ void cdrelconst(ref CGstate cg, ref CodeBuilder cdb,elem *e,ref regm_t pretregs)
case TYildouble:
case TYcldouble:
tym = TYnptr; // don't confuse allocreg()
if (pretregs & (mES | mCX) || e.Ety & mTYfar)
if (I16 && pretregs & (mES | mCX) || e.Ety & mTYfar)
{
tym = TYfptr;
}
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
6 changes: 4 additions & 2 deletions compiler/src/dmd/e2ir.d
Original file line number Diff line number Diff line change
Expand Up @@ -1255,8 +1255,10 @@ 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);

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

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/e2ir.d#L1259

Added line #L1259 was not covered by tests
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 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);

Check warning on line 1639 in compiler/src/dmd/escape.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/escape.d#L1639

Added line #L1639 was not covered by tests

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
33 changes: 31 additions & 2 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();
if (!p.isLvalue())

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

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L4907-L4911

Added lines #L4907 - L4911 were not covered by tests
{
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,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}

if (exp.placement)
{
auto placementSize = size(exp.placement.type, exp.placement.loc);
auto objectSize = size(tb, exp.placement.loc);

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

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L5006-L5007

Added lines #L5006 - L5007 were not covered by tests
//printf("placementSize: %lld objectSize: %lld\n", placementSize, objectSize);
if (placementSize < objectSize)

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

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L5009

Added line #L5009 was not covered by tests
{
error(exp.placement.loc, "new placement size %llu must be >= object size %llu", placementSize, objectSize);
return setError();

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

View check run for this annotation

Codecov / codecov/patch

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

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

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

Expand Down Expand Up @@ -5555,7 +5580,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 @@ -15244,6 +15269,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 15273 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L15273

Added line #L15273 was not covered by tests
if (e.thisexp)
check(e.thisexp, false);
return false;
Expand Down Expand Up @@ -15427,6 +15454,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 15458 in compiler/src/dmd/expressionsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/expressionsem.d#L15458

Added line #L15458 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
14 changes: 14 additions & 0 deletions compiler/src/dmd/hdrgen.d
Original file line number Diff line number Diff line change
Expand Up @@ -2423,6 +2423,13 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
buf.writeByte('.');
}
buf.writestring("new ");
if (e.placement)
{
buf.writeByte('(');
expToBuffer(e.placement, PREC.assign, buf, hgs);
buf.writeByte(')');
buf.writeByte(' ');

Check warning on line 2431 in compiler/src/dmd/hdrgen.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/hdrgen.d#L2428-L2431

Added lines #L2428 - L2431 were not covered by tests
}
typeToBuffer(e.newtype, null, buf, hgs);
if (e.arguments && e.arguments.length)
{
Expand All @@ -2440,6 +2447,13 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
buf.writeByte('.');
}
buf.writestring("new");
if (e.placement)
{
buf.writeByte(' ');
buf.writeByte('(');
expToBuffer(e.placement, PREC.assign, buf, hgs);
buf.writeByte(')');

Check warning on line 2455 in compiler/src/dmd/hdrgen.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/hdrgen.d#L2452-L2455

Added lines #L2452 - L2455 were not covered by tests
}
buf.writestring(" class ");
if (e.arguments && e.arguments.length)
{
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/inline.d
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,7 @@ public:
goto LhasLowering;
}

ne.placement = doInlineAs!Expression(e.placement, ids);
ne.thisexp = doInlineAs!Expression(e.thisexp, ids);
ne.argprefix = doInlineAs!Expression(e.argprefix, ids);
ne.arguments = arrayExpressionDoInline(e.arguments);
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dmd/inlinecost.d
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ public:
{
//printf("NewExp.inlineCost3() %s\n", e.toChars());
AggregateDeclaration ad = isAggregate(e.newtype);
if (ad && ad.isNested())
if (ad && ad.isNested() || e.placement)
cost = COST_MAX;
else
cost++;
Expand Down
5 changes: 5 additions & 0 deletions compiler/src/dmd/ob.d
Original file line number Diff line number Diff line change
Expand Up @@ -1725,6 +1725,8 @@ void genKill(ref ObState obstate, ObNode* ob)

override void visit(NewExp e)
{
if (e.placement)
e.placement.accept(this);

Check warning on line 1729 in compiler/src/dmd/ob.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/ob.d#L1729

Added line #L1729 was not covered by tests
if (e.arguments)
{
foreach (ex; *e.arguments)
Expand Down Expand Up @@ -2466,6 +2468,9 @@ void checkObErrors(ref ObState obstate)

override void visit(NewExp e)
{
if (e.placement)
e.placement.accept(this);

Check warning on line 2472 in compiler/src/dmd/ob.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/ob.d#L2472

Added line #L2472 was not covered by tests

if (e.arguments)
{
foreach (ex; *e.arguments)
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/optimize.d
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,7 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)

void visitNew(NewExp e)
{
expOptimize(e.placement, WANTvalue);
expOptimize(e.thisexp, WANTvalue);
// Optimize parameters
if (e.arguments)
Expand Down
16 changes: 13 additions & 3 deletions compiler/src/dmd/parse.d
Original file line number Diff line number Diff line change
Expand Up @@ -9516,7 +9516,17 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
const loc = token.loc;

nextToken();
nextToken(); // skip past `new`

// parse PlacementExpression if any
AST.Expression placement;
if (token.value == TOK.leftParenthesis)
{
nextToken();
placement = parseAssignExp();
check(TOK.rightParenthesis);

Check warning on line 9527 in compiler/src/dmd/parse.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/parse.d#L9525-L9527

Added lines #L9525 - L9527 were not covered by tests
}

AST.Expressions* arguments = null;
AST.Identifiers* names = null;

Expand Down Expand Up @@ -9552,7 +9562,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}

auto cd = new AST.ClassDeclaration(loc, id, baseclasses, members, false);
auto e = new AST.NewAnonClassExp(loc, thisexp, cd, arguments);
auto e = new AST.NewAnonClassExp(loc, placement, thisexp, cd, arguments);
return e;
}

Expand All @@ -9576,7 +9586,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
parseNamedArguments(arguments, names);
}

auto e = new AST.NewExp(loc, thisexp, t, arguments, names);
auto e = new AST.NewExp(loc, placement, thisexp, t, arguments, names);
return e;
}

Expand Down
Loading

0 comments on commit fd23a02

Please sign in to comment.