Merge pull request #17057 from WalterBright/placementNew

add Placement New
This commit is contained in:
Manu Evans 2025-03-03 19:50:22 +10:00 committed by GitHub
commit 37469bfae8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 407 additions and 46 deletions

View 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);
}
---

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -1126,7 +1126,14 @@ elem* toElem(Expression e, ref IRState irs)
elem* ezprefix = null;
elem* ez = null;
if (ne.onstack)
if (ne.onstack || ne.placement)
{
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.
@ -1139,6 +1146,7 @@ elem* toElem(Expression e, ref IRState irs)
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;
if (ne.placement)
{
ex = toElem(ne.placement, irs);
ex = addressElem(ex, tclass, false);
}
else if (auto lowering = ne.lowering)
// Call _d_newitemT()
if (auto lowering = ne.lowering)
ex = toElem(ne.lowering, irs);
else
assert(0, "This case should have been rewritten to `_d_newitemT` in the semantic phase");
@ -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()
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)
{

View file

@ -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)
{

View file

@ -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)

View file

@ -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); }

View file

@ -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();
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();
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)

View file

@ -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;
};

View file

@ -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)
{

View file

@ -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
{

View file

@ -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++;

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -9502,7 +9502,17 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
const loc = token.loc;
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;
}

View file

@ -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)

View file

@ -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());

View file

@ -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);

View file

@ -0,0 +1,4 @@
void f(int* p) @nogc
{
new(*p) int;
}

View 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;
}
/*************************************************/

View 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;
}