mirror of
https://github.com/dlang/dmd.git
synced 2025-04-28 06:00:13 +03:00
Fix Issue 24159: Store lowering of CatAssignExp
in a separate field (#15791)
This preserves the `CatAssignExp` in the AST until the glue layer where an error is printed in case this expression is used with `-betterC`. This is required to happen in the glue layer as the semantic analysis doesn't correctly distinguish when code needs to be generated. Signed-off-by: Teodor Dutu <teodor.dutu@gmail.com>
This commit is contained in:
parent
505e475b37
commit
b9f8e7cf24
13 changed files with 151 additions and 104 deletions
|
@ -5901,7 +5901,7 @@ private bool isDRuntimeHook(Identifier id)
|
||||||
id == Id._d_arraysetlengthTImpl || id == Id._d_arraysetlengthT ||
|
id == Id._d_arraysetlengthTImpl || id == Id._d_arraysetlengthT ||
|
||||||
id == Id._d_arraysetlengthTTrace ||
|
id == Id._d_arraysetlengthTTrace ||
|
||||||
id == Id._d_arrayappendT || id == Id._d_arrayappendTTrace ||
|
id == Id._d_arrayappendT || id == Id._d_arrayappendTTrace ||
|
||||||
id == Id._d_arrayappendcTXImpl;
|
id == Id._d_arrayappendcTX;
|
||||||
}
|
}
|
||||||
|
|
||||||
void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList argumentList)
|
void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList argumentList)
|
||||||
|
|
|
@ -2748,6 +2748,11 @@ elem* toElem(Expression e, ref IRState irs)
|
||||||
{
|
{
|
||||||
//printf("CatAssignExp.toElem('%s')\n", ce.toChars());
|
//printf("CatAssignExp.toElem('%s')\n", ce.toChars());
|
||||||
elem *e;
|
elem *e;
|
||||||
|
|
||||||
|
switch (ce.op)
|
||||||
|
{
|
||||||
|
case EXP.concatenateDcharAssign:
|
||||||
|
{
|
||||||
Type tb1 = ce.e1.type.toBasetype();
|
Type tb1 = ce.e1.type.toBasetype();
|
||||||
Type tb2 = ce.e2.type.toBasetype();
|
Type tb2 = ce.e2.type.toBasetype();
|
||||||
assert(tb1.ty == Tarray);
|
assert(tb1.ty == Tarray);
|
||||||
|
@ -2762,10 +2767,6 @@ elem* toElem(Expression e, ref IRState irs)
|
||||||
elem* re1 = addressElem(e1, ce.e1.type.pointerTo(), false);
|
elem* re1 = addressElem(e1, ce.e1.type.pointerTo(), false);
|
||||||
elem* ev = el_same(&re1);
|
elem* ev = el_same(&re1);
|
||||||
|
|
||||||
switch (ce.op)
|
|
||||||
{
|
|
||||||
case EXP.concatenateDcharAssign:
|
|
||||||
{
|
|
||||||
// Append dchar to char[] or wchar[]
|
// Append dchar to char[] or wchar[]
|
||||||
assert(tb2.ty == Tdchar &&
|
assert(tb2.ty == Tdchar &&
|
||||||
(tb1n.ty == Tchar || tb1n.ty == Twchar));
|
(tb1n.ty == Tchar || tb1n.ty == Twchar));
|
||||||
|
@ -2776,23 +2777,6 @@ elem* toElem(Expression e, ref IRState irs)
|
||||||
: RTLSYM.ARRAYAPPENDWD;
|
: RTLSYM.ARRAYAPPENDWD;
|
||||||
e = el_bin(OPcall, TYdarray, el_var(getRtlsym(rtl)), ep);
|
e = el_bin(OPcall, TYdarray, el_var(getRtlsym(rtl)), ep);
|
||||||
toTraceGC(irs, e, ce.loc);
|
toTraceGC(irs, e, ce.loc);
|
||||||
elem_setLoc(e, ce.loc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case EXP.concatenateAssign:
|
|
||||||
{
|
|
||||||
assert(0, "This case should have been rewritten to `_d_arrayappendT` in the semantic phase");
|
|
||||||
}
|
|
||||||
|
|
||||||
case EXP.concatenateElemAssign:
|
|
||||||
{
|
|
||||||
assert(0, "This case should have been rewritten to `_d_arrayappendcTX` in the semantic phase");
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate: (re1, e, *ev)
|
/* Generate: (re1, e, *ev)
|
||||||
*/
|
*/
|
||||||
|
@ -2800,6 +2784,37 @@ elem* toElem(Expression e, ref IRState irs)
|
||||||
ev = el_una(OPind, e1.Ety, ev);
|
ev = el_una(OPind, e1.Ety, ev);
|
||||||
e = el_combine(e, ev);
|
e = el_combine(e, ev);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EXP.concatenateAssign:
|
||||||
|
case EXP.concatenateElemAssign:
|
||||||
|
{
|
||||||
|
/* Do this check during code gen rather than semantic because appending is
|
||||||
|
* allowed during CTFE, and we cannot distinguish that in semantic.
|
||||||
|
*/
|
||||||
|
if (!irs.params.useGC)
|
||||||
|
{
|
||||||
|
irs.eSink.error(ce.loc,
|
||||||
|
"appending to array in `%s` requires the GC which is not available with -betterC",
|
||||||
|
ce.toChars());
|
||||||
|
return el_long(TYint, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto lowering = ce.lowering)
|
||||||
|
e = toElem(lowering, irs);
|
||||||
|
else if (ce.op == EXP.concatenateAssign)
|
||||||
|
assert(0, "This case should have been rewritten to `_d_arrayappendT` in the semantic phase");
|
||||||
|
else
|
||||||
|
assert(0, "This case should have been rewritten to `_d_arrayappendcTX` in the semantic phase");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
elem_setLoc(e, ce.loc);
|
elem_setLoc(e, ce.loc);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5633,7 +5633,9 @@ extern (C++) final class UshrAssignExp : BinAssignExp
|
||||||
*/
|
*/
|
||||||
extern (C++) class CatAssignExp : BinAssignExp
|
extern (C++) class CatAssignExp : BinAssignExp
|
||||||
{
|
{
|
||||||
extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
|
Expression lowering; // lowered druntime hook `_d_arrayappend{cTX,T}`
|
||||||
|
|
||||||
|
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
|
||||||
{
|
{
|
||||||
super(loc, EXP.concatenateAssign, e1, e2);
|
super(loc, EXP.concatenateAssign, e1, e2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1148,6 +1148,8 @@ public:
|
||||||
class CatAssignExp : public BinAssignExp
|
class CatAssignExp : public BinAssignExp
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Expression *lowering; // lowered druntime hook `_d_arrayappend{cTX,T}`
|
||||||
|
|
||||||
void accept(Visitor *v) override { v->visit(this); }
|
void accept(Visitor *v) override { v->visit(this); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11199,8 +11199,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||||
|
|
||||||
result = res;
|
result = res;
|
||||||
|
|
||||||
if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) &&
|
if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && sc.needsCodegen())
|
||||||
sc.needsCodegen())
|
|
||||||
{
|
{
|
||||||
// if aa ordering is triggered, `res` will be a CommaExp
|
// if aa ordering is triggered, `res` will be a CommaExp
|
||||||
// and `.e2` will be the rewritten original expression.
|
// and `.e2` will be the rewritten original expression.
|
||||||
|
@ -11244,7 +11243,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||||
arguments.push(exp.e1);
|
arguments.push(exp.e1);
|
||||||
arguments.push(exp.e2);
|
arguments.push(exp.e2);
|
||||||
Expression ce = new CallExp(exp.loc, id, arguments);
|
Expression ce = new CallExp(exp.loc, id, arguments);
|
||||||
*output = ce.expressionSemantic(sc);
|
|
||||||
|
exp.lowering = ce.expressionSemantic(sc);
|
||||||
|
*output = exp;
|
||||||
}
|
}
|
||||||
else if (exp.op == EXP.concatenateElemAssign)
|
else if (exp.op == EXP.concatenateElemAssign)
|
||||||
{
|
{
|
||||||
|
@ -11264,15 +11265,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||||
}
|
}
|
||||||
|
|
||||||
Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX;
|
Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX;
|
||||||
if (!verifyHookExist(exp.loc, *sc, Id._d_arrayappendcTXImpl, "appending element to arrays", Id.object))
|
if (!verifyHookExist(exp.loc, *sc, hook, "appending element to arrays", Id.object))
|
||||||
return setError();
|
return setError();
|
||||||
|
|
||||||
// Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
|
// Lower to object._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
|
||||||
Expression id = new IdentifierExp(exp.loc, Id.empty);
|
Expression id = new IdentifierExp(exp.loc, Id.empty);
|
||||||
id = new DotIdExp(exp.loc, id, Id.object);
|
id = new DotIdExp(exp.loc, id, Id.object);
|
||||||
auto tiargs = new Objects();
|
|
||||||
tiargs.push(exp.e1.type);
|
|
||||||
id = new DotTemplateInstanceExp(exp.loc, id, Id._d_arrayappendcTXImpl, tiargs);
|
|
||||||
id = new DotIdExp(exp.loc, id, hook);
|
id = new DotIdExp(exp.loc, id, hook);
|
||||||
|
|
||||||
auto arguments = new Expressions();
|
auto arguments = new Expressions();
|
||||||
|
@ -11299,11 +11297,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||||
{
|
{
|
||||||
/* Before the template hook, this check was performed in e2ir.d
|
/* Before the template hook, this check was performed in e2ir.d
|
||||||
* for expressions like `a ~= a[$-1]`. Here, $ will be modified
|
* for expressions like `a ~= a[$-1]`. Here, $ will be modified
|
||||||
* by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in
|
* by calling `_d_arrayappendcTX`, so we need to save `a[$-1]` in
|
||||||
* a temporary variable.
|
* a temporary variable.
|
||||||
*/
|
*/
|
||||||
value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true);
|
value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true);
|
||||||
exp.e2 = value2;
|
|
||||||
|
|
||||||
// `__appendtmp*` will be destroyed together with the array `exp.e1`.
|
// `__appendtmp*` will be destroyed together with the array `exp.e1`.
|
||||||
auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
|
auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
|
||||||
|
@ -11319,13 +11316,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||||
auto e0 = Expression.combine(ce, ae).expressionSemantic(sc);
|
auto e0 = Expression.combine(ce, ae).expressionSemantic(sc);
|
||||||
e0 = Expression.combine(e0, value1);
|
e0 = Expression.combine(e0, value1);
|
||||||
e0 = Expression.combine(eValue1, e0);
|
e0 = Expression.combine(eValue1, e0);
|
||||||
|
|
||||||
e0 = Expression.combine(eValue2, e0);
|
e0 = Expression.combine(eValue2, e0);
|
||||||
|
|
||||||
*output = e0.expressionSemantic(sc);
|
exp.lowering = e0.expressionSemantic(sc);
|
||||||
|
*output = exp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(AddExp exp)
|
override void visit(AddExp exp)
|
||||||
|
|
|
@ -7831,6 +7831,7 @@ public:
|
||||||
class CatAssignExp : public BinAssignExp
|
class CatAssignExp : public BinAssignExp
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Expression* lowering;
|
||||||
void accept(Visitor* v) override;
|
void accept(Visitor* v) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8714,7 +8715,6 @@ struct Id final
|
||||||
static Identifier* _d_arraysetlengthTTrace;
|
static Identifier* _d_arraysetlengthTTrace;
|
||||||
static Identifier* _d_arrayappendT;
|
static Identifier* _d_arrayappendT;
|
||||||
static Identifier* _d_arrayappendTTrace;
|
static Identifier* _d_arrayappendTTrace;
|
||||||
static Identifier* _d_arrayappendcTXImpl;
|
|
||||||
static Identifier* _d_arrayappendcTX;
|
static Identifier* _d_arrayappendcTX;
|
||||||
static Identifier* _d_arrayappendcTXTrace;
|
static Identifier* _d_arrayappendcTXTrace;
|
||||||
static Identifier* _d_arraycatnTX;
|
static Identifier* _d_arraycatnTX;
|
||||||
|
|
|
@ -366,7 +366,6 @@ immutable Msgtable[] msgtable =
|
||||||
{ "_d_arraysetlengthTTrace"},
|
{ "_d_arraysetlengthTTrace"},
|
||||||
{ "_d_arrayappendT" },
|
{ "_d_arrayappendT" },
|
||||||
{ "_d_arrayappendTTrace" },
|
{ "_d_arrayappendTTrace" },
|
||||||
{ "_d_arrayappendcTXImpl" },
|
|
||||||
{ "_d_arrayappendcTX" },
|
{ "_d_arrayappendcTX" },
|
||||||
{ "_d_arrayappendcTXTrace" },
|
{ "_d_arrayappendcTXTrace" },
|
||||||
{ "_d_arraycatnTX" },
|
{ "_d_arraycatnTX" },
|
||||||
|
|
|
@ -773,6 +773,21 @@ public:
|
||||||
result = ce;
|
result = ce;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override void visit(CatAssignExp e)
|
||||||
|
{
|
||||||
|
auto cae = cast(CatAssignExp) e.copy();
|
||||||
|
|
||||||
|
if (auto lowering = cae.lowering)
|
||||||
|
cae.lowering = doInlineAs!Expression(cae.lowering, ids);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cae.e1 = doInlineAs!Expression(e.e1, ids);
|
||||||
|
cae.e2 = doInlineAs!Expression(e.e2, ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = cae;
|
||||||
|
}
|
||||||
|
|
||||||
override void visit(BinExp e)
|
override void visit(BinExp e)
|
||||||
{
|
{
|
||||||
auto be = cast(BinExp)e.copy();
|
auto be = cast(BinExp)e.copy();
|
||||||
|
@ -1279,6 +1294,14 @@ public:
|
||||||
inlineScan(e.e2);
|
inlineScan(e.e2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override void visit(CatAssignExp e)
|
||||||
|
{
|
||||||
|
if (auto lowering = e.lowering)
|
||||||
|
inlineScan(lowering);
|
||||||
|
else
|
||||||
|
visit(cast(BinExp) e);
|
||||||
|
}
|
||||||
|
|
||||||
override void visit(BinExp e)
|
override void visit(BinExp e)
|
||||||
{
|
{
|
||||||
inlineScan(e.e1);
|
inlineScan(e.e1);
|
||||||
|
|
|
@ -108,12 +108,6 @@ public:
|
||||||
return;
|
return;
|
||||||
f.printGCUsage(e.loc, "setting `length` may cause a GC allocation");
|
f.printGCUsage(e.loc, "setting `length` may cause a GC allocation");
|
||||||
}
|
}
|
||||||
else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendcTX)
|
|
||||||
{
|
|
||||||
if (setGC(e, "cannot use operator `~=` in `@nogc` %s `%s`"))
|
|
||||||
return;
|
|
||||||
f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(ArrayLiteralExp e)
|
override void visit(ArrayLiteralExp e)
|
||||||
|
@ -187,20 +181,14 @@ public:
|
||||||
|
|
||||||
override void visit(CatAssignExp e)
|
override void visit(CatAssignExp e)
|
||||||
{
|
{
|
||||||
/* CatAssignExp will exist in `__traits(compiles, ...)` and in the `.e1` branch of a `__ctfe ? :` CondExp.
|
|
||||||
* The other branch will be `_d_arrayappendcTX(e1, 1), e1[$-1]=e2` which will generate the warning about
|
|
||||||
* GC usage. See visit(CallExp).
|
|
||||||
*/
|
|
||||||
if (checkOnly)
|
if (checkOnly)
|
||||||
{
|
{
|
||||||
err = true;
|
err = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (f.setGC(e.loc, null))
|
if (setGC(e, "cannot use operator `~=` in `@nogc` %s `%s`"))
|
||||||
{
|
|
||||||
err = true;
|
|
||||||
return;
|
return;
|
||||||
}
|
f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation");
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(CatExp e)
|
override void visit(CatExp e)
|
||||||
|
|
|
@ -928,6 +928,14 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void visitCatAssign(CatAssignExp e)
|
||||||
|
{
|
||||||
|
if (auto lowering = e.lowering)
|
||||||
|
Expression_optimize(lowering, result, keepLvalue);
|
||||||
|
else
|
||||||
|
visitBinAssign(e);
|
||||||
|
}
|
||||||
|
|
||||||
void visitBin(BinExp e)
|
void visitBin(BinExp e)
|
||||||
{
|
{
|
||||||
//printf("BinExp::optimize(result = %d) %s\n", result, e.toChars());
|
//printf("BinExp::optimize(result = %d) %s\n", result, e.toChars());
|
||||||
|
@ -1392,9 +1400,9 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
||||||
case EXP.leftShiftAssign:
|
case EXP.leftShiftAssign:
|
||||||
case EXP.rightShiftAssign:
|
case EXP.rightShiftAssign:
|
||||||
case EXP.unsignedRightShiftAssign:
|
case EXP.unsignedRightShiftAssign:
|
||||||
|
case EXP.concatenateDcharAssign: visitBinAssign(ex.isBinAssignExp()); break;
|
||||||
case EXP.concatenateElemAssign:
|
case EXP.concatenateElemAssign:
|
||||||
case EXP.concatenateDcharAssign:
|
case EXP.concatenateAssign: visitCatAssign(cast(CatAssignExp) ex); break;
|
||||||
case EXP.concatenateAssign: visitBinAssign(ex.isBinAssignExp()); break;
|
|
||||||
|
|
||||||
case EXP.minusMinus:
|
case EXP.minusMinus:
|
||||||
case EXP.plusPlus:
|
case EXP.plusPlus:
|
||||||
|
|
14
compiler/test/fail_compilation/test24159.d
Normal file
14
compiler/test/fail_compilation/test24159.d
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// https://issues.dlang.org/show_bug.cgi?id=24159
|
||||||
|
// REQUIRED_ARGS: -betterC
|
||||||
|
/*
|
||||||
|
TEST_OUTPUT:
|
||||||
|
---
|
||||||
|
fail_compilation/test24159.d(13): Error: appending to array in `x ~= 3` requires the GC which is not available with -betterC
|
||||||
|
---
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern(C) void main()
|
||||||
|
{
|
||||||
|
int[] x = null;
|
||||||
|
x ~= 3;
|
||||||
|
}
|
|
@ -14,12 +14,7 @@ private extern (C) byte[] _d_arrayappendcTX(const TypeInfo ti, ref return scope
|
||||||
|
|
||||||
private enum isCopyingNothrow(T) = __traits(compiles, (ref T rhs) nothrow { T lhs = rhs; });
|
private enum isCopyingNothrow(T) = __traits(compiles, (ref T rhs) nothrow { T lhs = rhs; });
|
||||||
|
|
||||||
/// Implementation of `_d_arrayappendcTX` and `_d_arrayappendcTXTrace`
|
/**
|
||||||
template _d_arrayappendcTXImpl(Tarr : T[], T)
|
|
||||||
{
|
|
||||||
private enum errorMessage = "Cannot append to array if compiling without support for runtime type information!";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extend an array `px` by `n` elements.
|
* Extend an array `px` by `n` elements.
|
||||||
* Caller must initialize those elements.
|
* Caller must initialize those elements.
|
||||||
* Params:
|
* Params:
|
||||||
|
@ -32,8 +27,8 @@ template _d_arrayappendcTXImpl(Tarr : T[], T)
|
||||||
* purity, and throwabilty checks. To prevent breaking existing code, this function template
|
* purity, and throwabilty checks. To prevent breaking existing code, this function template
|
||||||
* is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
|
* is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
|
||||||
*/
|
*/
|
||||||
ref Tarr _d_arrayappendcTX(return ref scope Tarr px, size_t n) @trusted pure nothrow
|
ref Tarr _d_arrayappendcTX(Tarr : T[], T)(return ref scope Tarr px, size_t n) @trusted
|
||||||
{
|
{
|
||||||
// needed for CTFE: https://github.com/dlang/druntime/pull/3870#issuecomment-1178800718
|
// needed for CTFE: https://github.com/dlang/druntime/pull/3870#issuecomment-1178800718
|
||||||
version (DigitalMars) pragma(inline, false);
|
version (DigitalMars) pragma(inline, false);
|
||||||
version (D_TypeInfo)
|
version (D_TypeInfo)
|
||||||
|
@ -49,21 +44,25 @@ template _d_arrayappendcTXImpl(Tarr : T[], T)
|
||||||
return px;
|
return px;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
assert(0, errorMessage);
|
assert(0, "Cannot append to array if compiling without support for runtime type information!");
|
||||||
}
|
}
|
||||||
|
|
||||||
version (D_ProfileGC)
|
|
||||||
{
|
|
||||||
import core.internal.array.utils : _d_HookTraceImpl;
|
|
||||||
|
|
||||||
|
version (D_ProfileGC)
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* TraceGC wrapper around $(REF _d_arrayappendcTX, rt,array,appending,_d_arrayappendcTXImpl).
|
* TraceGC wrapper around $(REF _d_arrayappendT, core,internal,array,appending).
|
||||||
* Bugs:
|
|
||||||
* This function template was ported from a much older runtime hook that bypassed safety,
|
|
||||||
* purity, and throwabilty checks. To prevent breaking existing code, this function template
|
|
||||||
* is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
|
|
||||||
*/
|
*/
|
||||||
alias _d_arrayappendcTXTrace = _d_HookTraceImpl!(Tarr, _d_arrayappendcTX, errorMessage);
|
ref Tarr _d_arrayappendcTXTrace(Tarr : T[], T)(string file, int line, string funcname, return ref scope Tarr px, size_t n) @trusted
|
||||||
|
{
|
||||||
|
version (D_TypeInfo)
|
||||||
|
{
|
||||||
|
import core.internal.array.utils: TraceHook, gcStatsPure, accumulatePure;
|
||||||
|
mixin(TraceHook!(Tarr.stringof, "_d_arrayappendcTX"));
|
||||||
|
|
||||||
|
return _d_arrayappendcTX(px, n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
static assert(0, "Cannot append to array if compiling without support for runtime type information!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +77,7 @@ ref Tarr _d_arrayappendT(Tarr : T[], T)(return ref scope Tarr x, scope Tarr y) @
|
||||||
enum hasPostblit = __traits(hasPostblit, T);
|
enum hasPostblit = __traits(hasPostblit, T);
|
||||||
auto length = x.length;
|
auto length = x.length;
|
||||||
|
|
||||||
_d_arrayappendcTXImpl!Tarr._d_arrayappendcTX(x, y.length);
|
_d_arrayappendcTX(x, y.length);
|
||||||
|
|
||||||
// Only call `copyEmplace` if `T` has a copy ctor and no postblit.
|
// Only call `copyEmplace` if `T` has a copy ctor and no postblit.
|
||||||
static if (hasElaborateCopyConstructor!T && !hasPostblit)
|
static if (hasElaborateCopyConstructor!T && !hasPostblit)
|
||||||
|
@ -126,7 +125,7 @@ version (D_ProfileGC)
|
||||||
return _d_arrayappendT(x, y);
|
return _d_arrayappendT(x, y);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
assert(0, "Cannot append to array if compiling without support for runtime type information!");
|
static assert(0, "Cannot append to array if compiling without support for runtime type information!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4667,11 +4667,12 @@ public import core.internal.array.appending : _d_arrayappendT;
|
||||||
version (D_ProfileGC)
|
version (D_ProfileGC)
|
||||||
{
|
{
|
||||||
public import core.internal.array.appending : _d_arrayappendTTrace;
|
public import core.internal.array.appending : _d_arrayappendTTrace;
|
||||||
|
public import core.internal.array.appending : _d_arrayappendcTXTrace;
|
||||||
public import core.internal.array.concatenation : _d_arraycatnTXTrace;
|
public import core.internal.array.concatenation : _d_arraycatnTXTrace;
|
||||||
public import core.lifetime : _d_newitemTTrace;
|
public import core.lifetime : _d_newitemTTrace;
|
||||||
public import core.internal.array.construction : _d_newarrayTTrace;
|
public import core.internal.array.construction : _d_newarrayTTrace;
|
||||||
}
|
}
|
||||||
public import core.internal.array.appending : _d_arrayappendcTXImpl;
|
public import core.internal.array.appending : _d_arrayappendcTX;
|
||||||
public import core.internal.array.comparison : __cmp;
|
public import core.internal.array.comparison : __cmp;
|
||||||
public import core.internal.array.equality : __equals;
|
public import core.internal.array.equality : __equals;
|
||||||
public import core.internal.array.casting: __ArrayCast;
|
public import core.internal.array.casting: __ArrayCast;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue