Skip to content

Commit

Permalink
fix Issue 7516 - Postblit not called for structs returned from a tern…
Browse files Browse the repository at this point in the history
…ary operator
  • Loading branch information
9rnsr authored and k-hara committed Feb 5, 2016
1 parent 21cf960 commit 094b358
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/dstruct.d
Expand Up @@ -765,7 +765,7 @@ public:
if (e.op == TOKerror)
return false;

(*elements)[i] = e.isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);
(*elements)[i] = doCopyOrMove(sc, e);
}
return true;
}
Expand Down
59 changes: 47 additions & 12 deletions src/expression.d
Expand Up @@ -1034,6 +1034,7 @@ extern (C++) bool arrayExpressionToCommonType(Scope* sc, Expressions* exps, Type
//printf("arrayExpressionToCommonType()\n");
scope IntegerExp integerexp = new IntegerExp(0);
scope CondExp condexp = new CondExp(Loc(), integerexp, null, null);

Type t0 = null;
Expression e0 = null;
size_t j0 = ~0;
Expand Down Expand Up @@ -1063,7 +1064,7 @@ extern (C++) bool arrayExpressionToCommonType(Scope* sc, Expressions* exps, Type
continue;
}

e = e.isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);
e = doCopyOrMove(sc, e);

if (t0 && !t0.equals(e.type))
{
Expand All @@ -1089,6 +1090,7 @@ extern (C++) bool arrayExpressionToCommonType(Scope* sc, Expressions* exps, Type
if (e.op != TOKerror)
(*exps)[i] = e;
}

if (!t0)
t0 = Type.tvoid; // [] is typed as void[]
else if (t0.ty != Terror)
Expand All @@ -1115,6 +1117,7 @@ extern (C++) bool arrayExpressionToCommonType(Scope* sc, Expressions* exps, Type
}
if (pt)
*pt = t0;

return (t0 == Type.terror);
}

Expand Down Expand Up @@ -1276,6 +1279,24 @@ extern (C++) Expression callCpCtor(Scope* sc, Expression e)
return e;
}

/************************************************
* Handle the postblit call on lvalue, or the move of rvalue.
*/
extern (C++) Expression doCopyOrMove(Scope *sc, Expression e)
{
if (e.op == TOKquestion)
{
auto ce = cast(CondExp)e;
ce.e1 = doCopyOrMove(sc, ce.e1);
ce.e2 = doCopyOrMove(sc, ce.e2);
}
else
{
e = e.isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);
}
return e;
}

/****************************************
* Now that we know the exact type of the function we're calling,
* the arguments[] need to be adjusted:
Expand Down Expand Up @@ -1562,12 +1583,9 @@ extern (C++) bool functionParameters(Loc loc, Scope* sc, TypeFunction tf, Type t
else
arg = toDelegate(arg, arg.type, sc);
}
else
{
// arg = arg->isLvalue() ? callCpCtor(sc, arg) : valueNoDtor(arg);
}
//printf("arg: %s\n", arg->toChars());
//printf("type: %s\n", arg->type->toChars());

/* Look for arguments that cannot 'escape' from the called
* function.
*/
Expand Down Expand Up @@ -1678,6 +1696,7 @@ extern (C++) bool functionParameters(Loc loc, Scope* sc, TypeFunction tf, Type t
}
(*arguments)[i] = arg;
}

/* Remaining problems:
* 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
* implemented by calling a function) we'll defer this for now.
Expand Down Expand Up @@ -1827,13 +1846,14 @@ extern (C++) bool functionParameters(Loc loc, Scope* sc, TypeFunction tf, Type t
*/
Type tv = arg.type.baseElemOf();
if (!isRef && tv.ty == Tstruct)
arg = arg.isLvalue() ? callCpCtor(sc, arg) : valueNoDtor(arg);
arg = doCopyOrMove(sc, arg);
}

(*arguments)[i] = arg;
}
}
//if (eprefix) printf("eprefix: %s\n", eprefix->toChars());

// If D linkage and variadic, add _arguments[] as first argument
if (tf.linkage == LINKd && tf.varargs == 1)
{
Expand Down Expand Up @@ -12955,10 +12975,12 @@ public:
{
if (type)
return this;

//printf("CatAssignExp::semantic() %s\n", toChars());
Expression e = op_overload(sc);
if (e)
return e;

if (e1.op == TOKslice)
{
SliceExp se = cast(SliceExp)e1;
Expand All @@ -12968,17 +12990,25 @@ public:
return new ErrorExp();
}
}

e1 = e1.modifiableLvalue(sc, e1);
if (e1.op == TOKerror)
return e1;
if (e2.op == TOKerror)
return e2;

if (checkNonAssignmentArrayOp(e2))
return new ErrorExp();

Type tb1 = e1.type.toBasetype();
Type tb1next = tb1.nextOf();
Type tb2 = e2.type.toBasetype();
if ((tb1.ty == Tarray) && (tb2.ty == Tarray || tb2.ty == Tsarray) && (e2.implicitConvTo(e1.type) || (tb2.nextOf().implicitConvTo(tb1next) && (tb2.nextOf().size(Loc()) == tb1next.size(Loc())))))

if ((tb1.ty == Tarray) &&
(tb2.ty == Tarray || tb2.ty == Tsarray) &&
(e2.implicitConvTo(e1.type) ||
(tb2.nextOf().implicitConvTo(tb1next) &&
(tb2.nextOf().size(Loc()) == tb1next.size(Loc())))))
{
// Append array
if (e1.checkPostblit(sc, tb1next))
Expand All @@ -12991,12 +13021,16 @@ public:
if (e2.checkPostblit(sc, tb2))
return new ErrorExp();
e2 = e2.castTo(sc, tb1next);
e2 = e2.isLvalue() ? callCpCtor(sc, e2) : valueNoDtor(e2);
e2 = doCopyOrMove(sc, e2);
}
else if (tb1.ty == Tarray && (tb1next.ty == Tchar || tb1next.ty == Twchar) && e2.type.ty != tb1next.ty && e2.implicitConvTo(Type.tdchar))
else if (tb1.ty == Tarray &&
(tb1next.ty == Tchar || tb1next.ty == Twchar) &&
e2.type.ty != tb1next.ty &&
e2.implicitConvTo(Type.tdchar))
{
// Append dchar to char[] or wchar[]
e2 = e2.castTo(sc, Type.tdchar);

/* Do not allow appending wchar to char[] because if wchar happens
* to be a surrogate pair, nothing good can result.
*/
Expand All @@ -13008,6 +13042,7 @@ public:
}
if (e2.checkValue())
return new ErrorExp();

type = e1.type;
return reorderSettingAAElem(sc);
}
Expand Down Expand Up @@ -13291,9 +13326,9 @@ public:
{
if (e1.op == TOKarrayliteral)
{
e2 = e2.isLvalue() ? callCpCtor(sc, e2) : valueNoDtor(e2);
e2 = doCopyOrMove(sc, e2);
// Bugzilla 14686: Postblit call appears in AST, and this is
// finally translated to an ArrayLiteralExp in below otpimize().
// finally translated to an ArrayLiteralExp in below optimize().
}
else if (e1.op == TOKstring)
{
Expand Down Expand Up @@ -13331,7 +13366,7 @@ public:
{
if (e2.op == TOKarrayliteral)
{
e1 = e1.isLvalue() ? callCpCtor(sc, e1) : valueNoDtor(e1);
e1 = doCopyOrMove(sc, e1);
}
else if (e2.op == TOKstring)
{
Expand Down
2 changes: 1 addition & 1 deletion src/expression.h
Expand Up @@ -68,7 +68,7 @@ TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s);
Expression *valueNoDtor(Expression *e);
int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1);
Expression *resolveAliasThis(Scope *sc, Expression *e, bool gag = false);
Expression *callCpCtor(Scope *sc, Expression *e);
Expression *doCopyOrMove(Scope *sc, Expression *e);
Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0);
Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0);
Expression *integralPromotions(Expression *e, Scope *sc);
Expand Down
9 changes: 7 additions & 2 deletions src/func.d
Expand Up @@ -1839,6 +1839,7 @@ public:
exp = exp.castTo(sc2, exp.type.wildOf());
}
exp = exp.implicitCastTo(sc2, tret);

if (f.isref)
{
// Function returns a reference
Expand All @@ -1852,16 +1853,20 @@ public:
/* Bugzilla 10789:
* If NRVO is not possible, all returned lvalues should call their postblits.
*/
if (!nrvo_can && exp.isLvalue())
exp = callCpCtor(sc2, exp);
if (!nrvo_can)
exp = doCopyOrMove(sc2, exp);

checkEscape(sc2, exp, false);
}

exp = checkGC(sc2, exp);

if (vresult)
{
// Create: return vresult = exp;
exp = new BlitExp(rs.loc, vresult, exp);
exp.type = vresult.type;

if (rs.caseDim)
exp = Expression.combine(exp, new IntegerExp(rs.caseDim));
}
Expand Down
128 changes: 128 additions & 0 deletions test/runnable/sdtor.d
Expand Up @@ -2150,6 +2150,129 @@ void test7506()
assert(S.di == 3);
}

/**********************************/
// 7516

struct S7516
{
int val;

this(int n) { val = n; }
this(this) { val *= 3; }
}

// CondExp on return statement
void test7516a()
{
alias S = S7516;
S s1 = S(1);
S s2 = S(2);

S foo(bool f) { return f ? s1 : s2; }
S hoo(bool f) { return f ? S(1) : S(2); }
S bar(bool f) { return f ? s1 : S(2); }
S baz(bool f) { return f ? S(1) : s2; }

auto r1 = foo(true); assert(r1.val == 3);
auto r2 = foo(false); assert(r2.val == 6);
auto r3 = hoo(true); assert(r3.val == 1);
auto r4 = hoo(false); assert(r4.val == 2);
auto r5 = bar(true); assert(r5.val == 3);
auto r6 = bar(false); assert(r6.val == 2);
auto r7 = baz(true); assert(r7.val == 1);
auto r8 = baz(false); assert(r8.val == 6);
}

// CondExp on function argument
void test7516b()
{
alias S = S7516;
S s1 = S(1);
S s2 = S(2);
S func(S s) { return s; }

S foo(bool f) { return func(f ? s1 : s2 ); }
S hoo(bool f) { return func(f ? S(1) : S(2)); }
S bar(bool f) { return func(f ? s1 : S(2)); }
S baz(bool f) { return func(f ? S(1) : s2 ); }

auto r1 = foo(true); assert(r1.val == 3 * 3);
auto r2 = foo(false); assert(r2.val == 6 * 3);
auto r3 = hoo(true); assert(r3.val == 1 * 3);
auto r4 = hoo(false); assert(r4.val == 2 * 3);
auto r5 = bar(true); assert(r5.val == 3 * 3);
auto r6 = bar(false); assert(r6.val == 2 * 3);
auto r7 = baz(true); assert(r7.val == 1 * 3);
auto r8 = baz(false); assert(r8.val == 6 * 3);
}

// CondExp on array literal
void test7516c()
{
alias S = S7516;
S s1 = S(1);
S s2 = S(2);

S[] foo(bool f) { return [f ? s1 : s2 ]; }
S[] hoo(bool f) { return [f ? S(1) : S(2)]; }
S[] bar(bool f) { return [f ? s1 : S(2)]; }
S[] baz(bool f) { return [f ? S(1) : s2 ]; }

auto r1 = foo(true); assert(r1[0].val == 3);
auto r2 = foo(false); assert(r2[0].val == 6);
auto r3 = hoo(true); assert(r3[0].val == 1);
auto r4 = hoo(false); assert(r4[0].val == 2);
auto r5 = bar(true); assert(r5[0].val == 3);
auto r6 = bar(false); assert(r6[0].val == 2);
auto r7 = baz(true); assert(r7[0].val == 1);
auto r8 = baz(false); assert(r8[0].val == 6);
}

// CondExp on rhs of cat assign
void test7516d()
{
alias S = S7516;
S s1 = S(1);
S s2 = S(2);

S[] foo(bool f) { S[] a; a ~= f ? s1 : s2 ; return a; }
S[] hoo(bool f) { S[] a; a ~= f ? S(1) : S(2); return a; }
S[] bar(bool f) { S[] a; a ~= f ? s1 : S(2); return a; }
S[] baz(bool f) { S[] a; a ~= f ? S(1) : s2 ; return a; }

auto r1 = foo(true); assert(r1[0].val == 3);
auto r2 = foo(false); assert(r2[0].val == 6);
auto r3 = hoo(true); assert(r3[0].val == 1);
auto r4 = hoo(false); assert(r4[0].val == 2);
auto r5 = bar(true); assert(r5[0].val == 3);
auto r6 = bar(false); assert(r6[0].val == 2);
auto r7 = baz(true); assert(r7[0].val == 1);
auto r8 = baz(false); assert(r8[0].val == 6);
}

// CondExp on struct literal element
void test7516e()
{
alias S = S7516;
S s1 = S(1);
S s2 = S(2);
struct X { S s; }

X foo(bool f) { return X(f ? s1 : s2 ); }
X hoo(bool f) { return X(f ? S(1) : S(2)); }
X bar(bool f) { return X(f ? s1 : S(2)); }
X baz(bool f) { return X(f ? S(1) : s2 ); }

auto r1 = foo(true); assert(r1.s.val == 3);
auto r2 = foo(false); assert(r2.s.val == 6);
auto r3 = hoo(true); assert(r3.s.val == 1);
auto r4 = hoo(false); assert(r4.s.val == 2);
auto r5 = bar(true); assert(r5.s.val == 3);
auto r6 = bar(false); assert(r6.s.val == 2);
auto r7 = baz(true); assert(r7.s.val == 1);
auto r8 = baz(false); assert(r8.s.val == 6);
}

/**********************************/
// 7530

Expand Down Expand Up @@ -4320,6 +4443,11 @@ int main()
test7353();
test61();
test7506();
test7516a();
test7516b();
test7516c();
test7516d();
test7516e();
test7530();
test62();
test7579a();
Expand Down

0 comments on commit 094b358

Please sign in to comment.