Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 9383 - Wrong context for contracts if closure [dis]appears in override function #4788

Merged
merged 1 commit into from Jul 6, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/declaration.c
Expand Up @@ -1810,10 +1810,10 @@ bool VarDeclaration::checkNestedReference(Scope *sc, Loc loc)
break;
}

if (fdthis->ident != Id::ensure)
if (fdthis->ident != Id::require && fdthis->ident != Id::ensure)
{
/* __ensure is always called directly,
* so it never becomes closure.
/* __require and __ensure will always get called directly,
* so they never make outer functions closure.
*/

//printf("\tfdv = %s\n", fdv->toChars());
Expand Down
22 changes: 21 additions & 1 deletion src/e2ir.c
Expand Up @@ -958,8 +958,28 @@ elem *toElem(Expression *e, IRState *irs)
elem *ethis = getEthis(se->loc, irs, fd);
ethis = el_una(OPaddr, TYnptr, ethis);

/* Bugzilla 9383: If 's' is a virtual function parameter
* placed in closure, and actually accessed from in/out
* contract, instead look at the original stack data.
*/
bool forceStackAccess = false;
if (s->Sclass == SCparameter &&
fd->isVirtual() && (fd->fdrequire || fd->fdensure))
{
Dsymbol *sx = irs->getFunc();
while (sx != fd)
{
if (sx->ident == Id::require || sx->ident == Id::ensure)
{
forceStackAccess = true;
break;
}
sx = sx->toParent2();
}
}

int soffset;
if (v && v->offset)
if (v && v->offset && !forceStackAccess)
soffset = v->offset;
else
{
Expand Down
2 changes: 1 addition & 1 deletion src/toir.c
Expand Up @@ -130,7 +130,7 @@ elem *getEthis(Loc loc, IRState *irs, Dsymbol *fd)
/* Going down one nesting level, i.e. we're calling
* a nested function from its enclosing function.
*/
if (irs->sclosure)
if (irs->sclosure && !(fd->ident == Id::require || fd->ident == Id::ensure))
{
ethis = el_var(irs->sclosure);
}
Expand Down
87 changes: 87 additions & 0 deletions test/runnable/testcontracts.d
Expand Up @@ -611,6 +611,92 @@ void test8093()
{ auto n = foo_val2(); assert(&n !is &g && n == 10); }
}

/*******************************************/
// 9383

class A9383
{
static void delegate() dg;
static int val;

void failInBase() { assert(typeid(this) is typeid(A9383)); }

// in-contract tests
void foo1(int i) in { A9383.val = i; failInBase; } body { } // no closure
void foo2(int i) in { A9383.val = i; failInBase; } body { int x; dg = { ++x; }; } // closure [local]
void foo3(int i) in { A9383.val = i; failInBase; } body { dg = { ++i; }; } // closure [parameter]
void foo4(int i) in { A9383.val = i; failInBase; } body { } // no closure
void foo5(int i) in { A9383.val = i; failInBase; } body { } // no closure
void foo6(int i) in { A9383.val = i; failInBase; } body { int x; dg = { ++x; }; } // closure [local]
void foo7(int i) in { A9383.val = i; failInBase; } body { dg = { ++i; }; } // closure [parameter]

// out-contract tests
void bar1(int i) out { A9383.val = i; } body { } // no closure
void bar2(int i) out { A9383.val = i; } body { int x; dg = { ++x; }; } // closure [local]
void bar3(int i) out { A9383.val = i; } body { dg = { ++i; }; } // closure [parameter]
void bar4(int i) out { A9383.val = i; } body { } // no closure
void bar5(int i) out { A9383.val = i; } body { } // no closure
void bar6(int i) out { A9383.val = i; } body { int x; dg = { ++x; }; } // closure [local]
void bar7(int i) out { A9383.val = i; } body { dg = { ++i; }; } // closure [parameter]
}

class B9383 : A9383
{
static int val;

// in-contract tests
override void foo1(int i) in { B9383.val = i; } body { } // -> no closure
override void foo2(int i) in { B9383.val = i; } body { int x; dg = { ++x; }; } // -> closure [local] appears
override void foo3(int i) in { B9383.val = i; } body { dg = { ++i; }; } // -> closure [parameter]
override void foo4(int i) in { B9383.val = i; } body { int x; dg = { ++x; }; } // -> closure [local] appears
override void foo5(int i) in { B9383.val = i; } body { dg = { ++i; }; } // -> closure [parameter] appears
override void foo6(int i) in { B9383.val = i; } body { } // -> closure [local] disappears
override void foo7(int i) in { B9383.val = i; } body { } // -> closure [parameter] disappears

// out-contract tests
override void bar1(int i) out { B9383.val = i; } body { } // -> no closure
override void bar2(int i) out { B9383.val = i; } body { int x; dg = { ++x; }; } // -> closure [local] appears
override void bar3(int i) out { B9383.val = i; } body { dg = { ++i; }; } // -> closure [parameter]
override void bar4(int i) out { B9383.val = i; } body { int x; dg = { ++x; }; } // -> closure [local] appears
override void bar5(int i) out { B9383.val = i; } body { dg = { ++i; }; } // -> closure [parameter] appears
override void bar6(int i) out { B9383.val = i; } body { } // -> closure [local] disappears
override void bar7(int i) out { B9383.val = i; } body { } // -> closure [parameter] disappears
}

void test9383()
{
auto a = new A9383();
auto b = new B9383();

// base class in-contract is used from derived class. // base derived
b.foo1(101); assert(A9383.val == 101 && B9383.val == 101); // no closure -> no closure
b.foo2(102); assert(A9383.val == 102 && B9383.val == 102); // closure [local] -> closure [local] appears
b.foo3(103); assert(A9383.val == 103 && B9383.val == 103); // closure [parameter] -> closure [parameter]
b.foo4(104); assert(A9383.val == 104 && B9383.val == 104); // no closure -> closure [local] appears
b.foo5(105); assert(A9383.val == 105 && B9383.val == 105); // no closure -> closure [parameter] appears
b.foo6(106); assert(A9383.val == 106 && B9383.val == 106); // closure [local] -> closure [local] disappears
b.foo7(107); assert(A9383.val == 107 && B9383.val == 107); // closure [parameter] -> closure [parameter] disappears

// base class out-contract is used from derived class. // base derived
b.bar1(101); assert(A9383.val == 101 && B9383.val == 101); // no closure -> no closure
b.bar2(102); assert(A9383.val == 102 && B9383.val == 102); // closure [local] -> closure [local] appears
b.bar3(103); assert(A9383.val == 103 && B9383.val == 103); // closure [parameter] -> closure [parameter]
b.bar4(104); assert(A9383.val == 104 && B9383.val == 104); // no closure -> closure [local] appears
b.bar5(105); assert(A9383.val == 105 && B9383.val == 105); // no closure -> closure [parameter] appears
b.bar6(106); assert(A9383.val == 106 && B9383.val == 106); // closure [local] -> closure [local] disappears
b.bar7(107); assert(A9383.val == 107 && B9383.val == 107); // closure [parameter] -> closure [parameter] disappears

// in-contract in base class.
a.foo1(101); assert(A9383.val == 101); // no closure
a.foo2(102); assert(A9383.val == 102); // closure [local]
a.foo3(103); assert(A9383.val == 103); // closure [parameter]

// out-contract in base class.
a.bar1(101); assert(A9383.val == 101); // no closure
a.bar2(102); assert(A9383.val == 102); // closure [local]
a.bar3(103); assert(A9383.val == 103); // closure [parameter]
}

/*******************************************/
// 10479

Expand Down Expand Up @@ -685,6 +771,7 @@ int main()
test7218();
test8073();
test8093();
test9383();

printf("Success\n");
return 0;
Expand Down