mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 21:21:48 +03:00
add Placement New
This commit is contained in:
parent
cdf4f5b072
commit
73158d8a78
24 changed files with 407 additions and 46 deletions
20
changelog/dmd.placementNew.dd
Normal file
20
changelog/dmd.placementNew.dd
Normal file
|
@ -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);
|
||||
}
|
||||
---
|
|
@ -4808,10 +4808,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(Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments)
|
||||
extern (D) this(Loc loc, Expression placement, Expression thisexp, ClassDeclaration cd, Expressions* arguments)
|
||||
{
|
||||
super(loc, EXP.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
|
||||
this.placement = placement;
|
||||
this.thisexp = thisexp;
|
||||
this.cd = cd;
|
||||
this.arguments = arguments;
|
||||
|
@ -5020,10 +5022,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(Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null)
|
||||
extern (D) this(Loc loc, Expression placement, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null)
|
||||
{
|
||||
super(loc, EXP.new_, __traits(classInstanceSize, NewExp));
|
||||
this.placement = placement;
|
||||
this.thisexp = thisexp;
|
||||
this.newtype = newtype;
|
||||
this.arguments = arguments;
|
||||
|
|
|
@ -2796,6 +2796,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;
|
||||
}
|
||||
|
||||
Expression epre = interpret(pue, e.argprefix, istate, CTFEGoal.Nothing);
|
||||
if (exceptionOrCant(epre))
|
||||
return;
|
||||
|
@ -5042,7 +5049,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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2998,6 +2998,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);
|
||||
if (e.thisexp)
|
||||
e.thisexp.accept(this);
|
||||
result = e.newtype.reliesOnTemplateParameters(tparams);
|
||||
|
|
|
@ -1126,19 +1126,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);
|
||||
|
@ -1265,8 +1273,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");
|
||||
|
@ -1276,7 +1289,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);
|
||||
if (ne.member)
|
||||
{
|
||||
if (sd.isNested())
|
||||
|
@ -1308,10 +1321,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);
|
||||
|
@ -1331,8 +1346,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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -304,8 +304,8 @@ extern (C++) abstract class Expression : ASTNode
|
|||
|
||||
static struct BitFields
|
||||
{
|
||||
bool parens; // if this is a parenthesized expression
|
||||
bool rvalue; // true if this is considered to be an rvalue, even if it is an lvalue
|
||||
bool parens; // if this is a parenthesized expression
|
||||
bool rvalue; // true if this is considered to be an rvalue, even if it is an lvalue
|
||||
}
|
||||
import dmd.common.bitfields;
|
||||
mixin(generateBitFields!(BitFields, ubyte));
|
||||
|
@ -2446,6 +2446,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
|
||||
|
@ -2458,23 +2459,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(Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null) @safe
|
||||
extern (D) this(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(Loc loc, Expression thisexp, Type newtype, Expressions* arguments) @safe
|
||||
static NewExp create(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);
|
||||
}
|
||||
|
||||
override NewExp syntaxCopy()
|
||||
{
|
||||
return new NewExp(loc,
|
||||
placement ? placement.syntaxCopy() : null,
|
||||
thisexp ? thisexp.syntaxCopy() : null,
|
||||
newtype.syntaxCopy(),
|
||||
arraySyntaxCopy(arguments),
|
||||
|
@ -2495,10 +2498,12 @@ 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(Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments) @safe
|
||||
extern (D) this(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;
|
||||
|
@ -2506,7 +2511,9 @@ extern (C++) final class NewAnonClassExp : Expression
|
|||
|
||||
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)
|
||||
|
|
|
@ -517,6 +517,7 @@ public:
|
|||
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[]
|
||||
|
||||
|
@ -526,7 +527,7 @@ public:
|
|||
|
||||
Expression *lowering; // lowered druntime hook: `_d_newclass`
|
||||
|
||||
static NewExp *create(Loc loc, Expression *thisexp, Type *newtype, Expressions *arguments);
|
||||
static NewExp *create(Loc loc, Expression *placement, Expression *thisexp, Type *newtype, Expressions *arguments);
|
||||
NewExp *syntaxCopy() override;
|
||||
|
||||
void accept(Visitor *v) override { v->visit(this); }
|
||||
|
@ -540,6 +541,7 @@ public:
|
|||
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); }
|
||||
|
|
|
@ -3161,7 +3161,7 @@ private bool functionParameters(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:
|
||||
|
@ -4879,6 +4879,28 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
printf("\tnewtype: %s\n", exp.newtype.toChars());
|
||||
}
|
||||
|
||||
if (exp.placement)
|
||||
{
|
||||
exp.placement = exp.placement.expressionSemantic(sc);
|
||||
auto p = exp.placement;
|
||||
if (p.op == EXP.error)
|
||||
return setError();
|
||||
if (!p.isLvalue())
|
||||
{
|
||||
error(p.loc, "PlacementExpression `%s` is an rvalue, but must be an lvalue", p.toChars());
|
||||
return setError();
|
||||
}
|
||||
if (sc.setUnsafe(false, p.loc, "`@safe` function `%s` cannot use placement `new`", sc.func))
|
||||
{
|
||||
return setError();
|
||||
}
|
||||
if (!exp.placement.type.isNaked())
|
||||
{
|
||||
error(p.loc, "PlacementExpression `%s` of type `%s` be unshared and mutable", p.toChars(), toChars(p.type));
|
||||
return setError();
|
||||
}
|
||||
}
|
||||
|
||||
//for error messages if the argument in [] is not convertible to size_t
|
||||
const originalNewtype = exp.newtype;
|
||||
|
||||
|
@ -4965,6 +4987,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();
|
||||
}
|
||||
}
|
||||
|
||||
const size_t nargs = exp.arguments ? exp.arguments.length : 0;
|
||||
Expression newprefix = null;
|
||||
|
||||
|
@ -4973,9 +5008,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();
|
||||
}
|
||||
if (!cd.ctor)
|
||||
cd.ctor = cd.searchCtor();
|
||||
if (cd.noDefaultCtor && !nargs && !cd.defaultCtor)
|
||||
|
@ -5185,6 +5225,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
return;
|
||||
}
|
||||
else if (sc.needsCodegen() && // interpreter doesn't need this lowered
|
||||
!exp.placement &&
|
||||
!exp.onstack && !exp.type.isScopeClass()) // these won't use the GC
|
||||
{
|
||||
/* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)`
|
||||
|
@ -5290,10 +5331,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
}
|
||||
|
||||
exp.type = exp.type.pointerTo();
|
||||
tryLowerToNewItem(exp);
|
||||
if (!exp.placement)
|
||||
tryLowerToNewItem(exp);
|
||||
}
|
||||
else if (tb.ty == Tarray)
|
||||
{
|
||||
if (exp.placement)
|
||||
{
|
||||
error(exp.placement.loc, "placement new cannot be used with dynamic arrays");
|
||||
return setError();
|
||||
}
|
||||
if (!nargs)
|
||||
{
|
||||
// https://issues.dlang.org/show_bug.cgi?id=20422
|
||||
|
@ -5364,7 +5411,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
goto LskipNewArrayLowering;
|
||||
}
|
||||
|
||||
if (nargs == 1)
|
||||
if (exp.placement) // no need to lower
|
||||
{
|
||||
}
|
||||
else if (nargs == 1)
|
||||
{
|
||||
auto hook = global.params.tracegc ? Id._d_newarrayTTrace : Id._d_newarrayT;
|
||||
if (!verifyHookExist(exp.loc, *sc, hook, "new array"))
|
||||
|
@ -5448,10 +5498,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
}
|
||||
|
||||
exp.type = exp.type.pointerTo();
|
||||
tryLowerToNewItem(exp);
|
||||
if (!exp.placement)
|
||||
tryLowerToNewItem(exp);
|
||||
}
|
||||
else if (tb.ty == Taarray)
|
||||
{
|
||||
if (exp.placement)
|
||||
{
|
||||
error(exp.placement.loc, "placement new cannot be used with associative arrays");
|
||||
return setError();
|
||||
}
|
||||
// e.g. `new Alias(args)`
|
||||
if (nargs)
|
||||
{
|
||||
|
@ -5501,7 +5557,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);
|
||||
|
@ -14928,6 +14984,8 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
|
|||
|
||||
bool visitNew(NewExp e)
|
||||
{
|
||||
if (e.placement)
|
||||
check(e.placement, false);
|
||||
if (e.thisexp)
|
||||
check(e.thisexp, false);
|
||||
return false;
|
||||
|
@ -15111,6 +15169,8 @@ Expression resolveLoc(Expression exp, Loc loc, Scope* sc)
|
|||
|
||||
Expression visitNew(NewExp exp)
|
||||
{
|
||||
if (exp.placement)
|
||||
exp.placement = exp.placement.resolveLoc(loc, sc);
|
||||
if (exp.thisexp)
|
||||
exp.thisexp = exp.thisexp.resolveLoc(loc, sc);
|
||||
if (exp.argprefix)
|
||||
|
|
|
@ -3374,6 +3374,7 @@ public:
|
|||
Expression* thisexp;
|
||||
ClassDeclaration* cd;
|
||||
Array<Expression* >* arguments;
|
||||
Expression* placement;
|
||||
NewAnonClassExp* syntaxCopy() override;
|
||||
void accept(Visitor* v) override;
|
||||
};
|
||||
|
@ -3385,12 +3386,13 @@ public:
|
|||
Type* newtype;
|
||||
Array<Expression* >* arguments;
|
||||
Array<Identifier* >* names;
|
||||
Expression* placement;
|
||||
Expression* argprefix;
|
||||
CtorDeclaration* member;
|
||||
bool onstack;
|
||||
bool thrownew;
|
||||
Expression* lowering;
|
||||
static NewExp* create(Loc loc, Expression* thisexp, Type* newtype, Array<Expression* >* arguments);
|
||||
static NewExp* create(Loc loc, Expression* placement, Expression* thisexp, Type* newtype, Array<Expression* >* arguments);
|
||||
NewExp* syntaxCopy() override;
|
||||
void accept(Visitor* v) override;
|
||||
};
|
||||
|
|
|
@ -2531,6 +2531,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(' ');
|
||||
}
|
||||
typeToBuffer(e.newtype, null, buf, hgs);
|
||||
if (e.arguments && e.arguments.length)
|
||||
{
|
||||
|
@ -2548,6 +2555,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(')');
|
||||
}
|
||||
buf.writestring(" class ");
|
||||
if (e.arguments && e.arguments.length)
|
||||
{
|
||||
|
|
|
@ -34,6 +34,7 @@ import dmd.errors;
|
|||
import dmd.func;
|
||||
import dmd.funcsem;
|
||||
import dmd.globals;
|
||||
import dmd.hdrgen;
|
||||
import dmd.id;
|
||||
import dmd.identifier;
|
||||
import dmd.init;
|
||||
|
@ -736,6 +737,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);
|
||||
|
@ -1001,7 +1003,7 @@ public:
|
|||
{
|
||||
static if (LOG)
|
||||
{
|
||||
printf("ExpStatement.inlineScan(%s)\n", s.toChars());
|
||||
printf("ExpStatement.inlineScan(%s)\n", toChars(s));
|
||||
}
|
||||
if (!s.exp)
|
||||
return;
|
||||
|
@ -2202,7 +2204,7 @@ private void expandInline(Loc callLoc, FuncDeclaration fd, FuncDeclaration paren
|
|||
|
||||
static if (EXPANDINLINE_LOG)
|
||||
printf("\n[%s] %s expandInline sresult =\n%s\n",
|
||||
callLoc.toChars(), fd.toPrettyChars(), sresult.toChars());
|
||||
callLoc.toChars(), fd.toPrettyChars(), toChars(sresult));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -137,6 +137,8 @@ public:
|
|||
|
||||
override void visit(NewExp e)
|
||||
{
|
||||
if (e.placement)
|
||||
return; // placement new doesn't use the GC
|
||||
if (e.member && !e.member.isNogc() && f.setGC(e.loc, null))
|
||||
{
|
||||
// @nogc-ness is already checked in NewExp::semantic
|
||||
|
|
|
@ -1723,6 +1723,8 @@ void genKill(ref ObState obstate, ObNode* ob)
|
|||
|
||||
override void visit(NewExp e)
|
||||
{
|
||||
if (e.placement)
|
||||
e.placement.accept(this);
|
||||
if (e.arguments)
|
||||
{
|
||||
foreach (ex; *e.arguments)
|
||||
|
@ -2464,6 +2466,9 @@ void checkObErrors(ref ObState obstate)
|
|||
|
||||
override void visit(NewExp e)
|
||||
{
|
||||
if (e.placement)
|
||||
e.placement.accept(this);
|
||||
|
||||
if (e.arguments)
|
||||
{
|
||||
foreach (ex; *e.arguments)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -9502,7 +9502,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);
|
||||
}
|
||||
|
||||
AST.Expressions* arguments = null;
|
||||
AST.Identifiers* names = null;
|
||||
|
||||
|
@ -9538,7 +9548,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;
|
||||
}
|
||||
|
||||
|
@ -9562,7 +9572,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -82,13 +82,13 @@ public:
|
|||
override void visit(NewExp e)
|
||||
{
|
||||
//printf("NewExp::apply(): %s\n", toChars());
|
||||
doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e);
|
||||
doCond(e.placement) || doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(NewAnonClassExp e)
|
||||
{
|
||||
//printf("NewAnonClassExp::apply(): %s\n", toChars());
|
||||
doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e);
|
||||
doCond(e.placement) || doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(TypeidExp e)
|
||||
|
|
|
@ -994,6 +994,8 @@ package(dmd.visitor) mixin template ParseVisitMethods(AST)
|
|||
override void visit(AST.NewExp e)
|
||||
{
|
||||
//printf("Visiting NewExp\n");
|
||||
if (e.placement)
|
||||
e.placement.accept(this);
|
||||
if (e.thisexp)
|
||||
e.thisexp.accept(this);
|
||||
visitType(e.newtype);
|
||||
|
@ -1003,6 +1005,8 @@ package(dmd.visitor) mixin template ParseVisitMethods(AST)
|
|||
override void visit(AST.NewAnonClassExp e)
|
||||
{
|
||||
//printf("Visiting NewAnonClassExp\n");
|
||||
if (e.placement)
|
||||
e.placement.accept(this);
|
||||
if (e.thisexp)
|
||||
e.thisexp.accept(this);
|
||||
visitArgs(e.arguments.peekSlice());
|
||||
|
|
|
@ -1344,7 +1344,7 @@ public:
|
|||
(void)d->csym;
|
||||
(void)d->vtblSymbol()->csym;
|
||||
(void)d->sinit;
|
||||
NewExp *ne = NewExp::create(d->loc, NULL, d->type, NULL);
|
||||
NewExp *ne = NewExp::create(d->loc, NULL, NULL, d->type, NULL);
|
||||
ne->type = d->type;
|
||||
Expression *e = dmd::ctfeInterpret(ne);
|
||||
assert(e->op == EXP::classReference);
|
||||
|
|
4
compiler/test/compilable/placementnew.d
Normal file
4
compiler/test/compilable/placementnew.d
Normal file
|
@ -0,0 +1,4 @@
|
|||
void f(int* p) @nogc
|
||||
{
|
||||
new(*p) int;
|
||||
}
|
80
compiler/test/fail_compilation/placenew.d
Normal file
80
compiler/test/fail_compilation/placenew.d
Normal file
|
@ -0,0 +1,80 @@
|
|||
/* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/placenew.d(23): Error: PlacementExpression `3` is an rvalue, but must be an lvalue
|
||||
fail_compilation/placenew.d(28): Error: undefined identifier `x`
|
||||
fail_compilation/placenew.d(36): Error: `new ( i )` PlacementExpression cannot be evaluated at compile time
|
||||
fail_compilation/placenew.d(39): called from here: `xxx()`
|
||||
fail_compilation/placenew.d(39): while evaluating: `static assert(xxx() == 1)`
|
||||
fail_compilation/placenew.d(48): Error: new placement size 24 must be >= object size 40
|
||||
fail_compilation/placenew.d(54): Error: placement new cannot be used with associative arrays
|
||||
fail_compilation/placenew.d(67): Error: new placement size 4 must be >= class object size $?:32=16|64=24$
|
||||
fail_compilation/placenew.d(77): Error: `@safe` function `test7` cannot use placement `new` is not allowed in a `@safe` function
|
||||
---
|
||||
*/
|
||||
|
||||
void test0()
|
||||
{
|
||||
int i;
|
||||
int* pi = new (i) int;
|
||||
}
|
||||
|
||||
void test1()
|
||||
{
|
||||
int* pi = new (3) int;
|
||||
}
|
||||
|
||||
void test2()
|
||||
{
|
||||
int* px = new (x) int;
|
||||
}
|
||||
|
||||
void test3()
|
||||
{
|
||||
int xxx()
|
||||
{
|
||||
int i;
|
||||
int* pi = new (i) int(1);
|
||||
return 1;
|
||||
}
|
||||
static assert(xxx() == 1);
|
||||
}
|
||||
|
||||
struct S { int[6] a; }
|
||||
struct T { int[10] a; }
|
||||
|
||||
void test4()
|
||||
{
|
||||
S s;
|
||||
new (s) T();
|
||||
}
|
||||
|
||||
void test5()
|
||||
{
|
||||
T p;
|
||||
auto aa = new(p) int[int*];
|
||||
}
|
||||
|
||||
/*************************************************/
|
||||
|
||||
class C6
|
||||
{
|
||||
int i, j;
|
||||
}
|
||||
|
||||
int test6()
|
||||
{
|
||||
int k;
|
||||
C6 c = new(k) C6;
|
||||
return c.j;
|
||||
}
|
||||
|
||||
/*************************************************/
|
||||
|
||||
@safe
|
||||
void test7()
|
||||
{
|
||||
int i;
|
||||
int* p = new(i) int;
|
||||
}
|
||||
|
||||
/*************************************************/
|
106
compiler/test/runnable/placenew.d
Normal file
106
compiler/test/runnable/placenew.d
Normal file
|
@ -0,0 +1,106 @@
|
|||
import core.stdc.stdio;
|
||||
import core.stdc.stdlib;
|
||||
|
||||
/*************************************************/
|
||||
|
||||
struct S
|
||||
{
|
||||
float d;
|
||||
int i;
|
||||
char c;
|
||||
}
|
||||
|
||||
void test1()
|
||||
{
|
||||
S s;
|
||||
S* p = new (s) S();
|
||||
assert(p.i == 0 && p.c == 0xFF);
|
||||
}
|
||||
|
||||
void test2()
|
||||
{
|
||||
S s;
|
||||
S* p = new (s) S(i:3);
|
||||
assert(p.i == 3 && p.c == 0xFF);
|
||||
}
|
||||
|
||||
/*************************************************/
|
||||
|
||||
struct S3
|
||||
{
|
||||
int i;
|
||||
this(int i) { this.i = i + 3; }
|
||||
}
|
||||
|
||||
void test3()
|
||||
{
|
||||
S3 s;
|
||||
s.i = 20;
|
||||
S3* p = new (s) S3(4);
|
||||
assert(p.i == 7);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************/
|
||||
|
||||
void test4()
|
||||
{
|
||||
int i = 3;
|
||||
int* p = new(i) int;
|
||||
*p = 4;
|
||||
assert(i == 4);
|
||||
|
||||
p = new(i) int(7);
|
||||
assert(i == 7);
|
||||
}
|
||||
|
||||
/*************************************************/
|
||||
|
||||
class C5
|
||||
{
|
||||
int i, j = 4;
|
||||
}
|
||||
|
||||
int test5()
|
||||
{
|
||||
int[10] k;
|
||||
C5 c = new(k) C5;
|
||||
//printf("c.j: %d\n", c.j);
|
||||
assert(c.j == 4);
|
||||
assert(cast(void*)c == cast(void*)k.ptr);
|
||||
return c.j;
|
||||
}
|
||||
|
||||
/*************************************************/
|
||||
|
||||
struct S6
|
||||
{
|
||||
int i = 1, j = 4, k = 9;
|
||||
}
|
||||
|
||||
ref void[T.sizeof] mallocate(T)()
|
||||
{
|
||||
return *(cast(void[T.sizeof]*) malloc(T.sizeof));
|
||||
}
|
||||
|
||||
void test6()
|
||||
{
|
||||
S6* ps = new(mallocate!S6()) S6;
|
||||
assert(ps.i == 1);
|
||||
assert(ps.j == 4);
|
||||
assert(ps.k == 9);
|
||||
}
|
||||
|
||||
/*************************************************/
|
||||
|
||||
int main()
|
||||
{
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
test5();
|
||||
test6();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue