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 Aug 30, 2015
1 parent f18fe22 commit 0cee308
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/dstruct.d
Expand Up @@ -632,7 +632,7 @@ public:
L1:
if (e.op == TOKerror)
return false;
(*elements)[i] = e.isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);
(*elements)[i] = doCopyOrMove(sc, e);
}
return true;
}
Expand Down
28 changes: 24 additions & 4 deletions src/expression.d
Expand Up @@ -1056,7 +1056,9 @@ extern (C++) bool arrayExpressionToCommonType(Scope* sc, Expressions* exps, Type
t0 = Type.terror;
continue;
}
e = e.isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);

e = doCopyOrMove(sc, e);

if (t0 && !t0.equals(e.type))
{
/* This applies ?: to merge the types. It's backwards;
Expand Down Expand Up @@ -1265,6 +1267,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)
{
CondExp 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 @@ -1552,7 +1572,7 @@ extern (C++) bool functionParameters(Loc loc, Scope* sc, TypeFunction tf, Type t
}
else
{
// arg = arg->isLvalue() ? callCpCtor(sc, arg) : valueNoDtor(arg);
//arg = doCopyOrMove(sc, arg);
}
//printf("arg: %s\n", arg->toChars());
//printf("type: %s\n", arg->type->toChars());
Expand Down Expand Up @@ -1759,7 +1779,7 @@ extern (C++) bool functionParameters(Loc loc, Scope* sc, TypeFunction tf, Type t
}
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 @@ -12532,7 +12552,7 @@ 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))
{
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, 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
4 changes: 2 additions & 2 deletions src/func.d
Expand Up @@ -1825,8 +1825,8 @@ 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);
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 @@ -4138,6 +4261,11 @@ int main()
test7353();
test61();
test7506();
test7516a();
test7516b();
test7516c();
test7516d();
test7516e();
test7530();
test62();
test7579a();
Expand Down

0 comments on commit 0cee308

Please sign in to comment.