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 committed Jul 7, 2015
1 parent 0e05196 commit 58421e2
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 9 deletions.
27 changes: 22 additions & 5 deletions src/expression.c
Expand Up @@ -1128,7 +1128,7 @@ bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt)
continue;
}

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

if (t0 && !t0->equals(e->type))
{
Expand Down Expand Up @@ -1243,7 +1243,6 @@ bool preFunctionParameters(Loc loc, Scope *sc, Expressions *exps)
* If we want the value of this expression, but do not want to call
* the destructor on it.
*/

Expression *valueNoDtor(Expression *e)
{
if (e->op == TOKcall)
Expand Down Expand Up @@ -1347,6 +1346,24 @@ Expression *callCpCtor(Scope *sc, Expression *e)
return e;
}

/************************************************
* Handle the postblit call on lvalue, or the move of rvalue.
*/
Expression *doCopyOrMove(Scope *sc, Expression *e)
{
if (e->op == TOKquestion)
{
CondExp *ce = (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 @@ -1651,7 +1668,7 @@ bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
}
else
{
// arg = arg->isLvalue() ? callCpCtor(sc, arg) : valueNoDtor(arg);
// arg = doCopyOrMove(sc, arg);
}

//printf("arg: %s\n", arg->toChars());
Expand Down Expand Up @@ -1872,7 +1889,7 @@ bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
}
else if (ts)
{
arg = arg->isLvalue() ? callCpCtor(sc, arg) : valueNoDtor(arg);
arg = doCopyOrMove(sc, arg);
}
else if (anythrow && firstthrow <= i && i <= lastthrow && gate)
{
Expand Down Expand Up @@ -11980,7 +11997,7 @@ Expression *CatAssignExp::semantic(Scope *sc)
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) &&
Expand Down
2 changes: 1 addition & 1 deletion src/expression.h
Expand Up @@ -66,7 +66,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);
Expression *callCpCtor(Scope *sc, Expression *e);
Expression *doCopyOrMove(Scope *sc, Expression *e);
Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0);
Expression *resolveOpDollar(Scope *sc, SliceExp *se, Expression **pe0);
Expression *integralPromotions(Expression *e, Scope *sc);
Expand Down
4 changes: 2 additions & 2 deletions src/func.c
Expand Up @@ -1768,8 +1768,8 @@ void FuncDeclaration::semantic3(Scope *sc)
/* 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);
}
Expand Down
1 change: 1 addition & 0 deletions src/magicport.json
Expand Up @@ -2731,6 +2731,7 @@
"function valueNoDtor",
"function checkDefCtor",
"function callCpCtor",
"function doCopyOrMove",
"function functionParameters",
"struct UnionExp",
"function RealEquals",
Expand Down
2 changes: 1 addition & 1 deletion src/struct.c
Expand Up @@ -1094,7 +1094,7 @@ bool StructDeclaration::fit(Loc loc, Scope *sc, Expressions *elements, Type *sty
if (e->op == TOKerror)
return false;

(*elements)[i] = e->isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);
(*elements)[i] = doCopyOrMove(sc, e);
}
return true;
}
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 @@ -4019,6 +4142,11 @@ int main()
test7353();
test61();
test7506();
test7516a();
test7516b();
test7516c();
test7516d();
test7516e();
test7530();
test62();
test7579a();
Expand Down

0 comments on commit 58421e2

Please sign in to comment.