Skip to content

Commit

Permalink
Merge pull request #1181 from 9rnsr/fix8809
Browse files Browse the repository at this point in the history
Issue 8809 - Cannot statically bind to base class method overridden by derived class
  • Loading branch information
yebblies committed Oct 27, 2012
2 parents 86a378b + 364bcdd commit 4c11aea
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 112 deletions.
14 changes: 0 additions & 14 deletions src/expression.c
Original file line number Diff line number Diff line change
Expand Up @@ -2904,8 +2904,6 @@ Expression *DsymbolExp::semantic(Scope *sc)
FuncDeclaration *f;
FuncLiteralDeclaration *fld;
OverloadSet *o;
ClassDeclaration *cd;
ClassDeclaration *thiscd = NULL;
Import *imp;
Package *pkg;
Type *t;
Expand All @@ -2922,9 +2920,6 @@ Expression *DsymbolExp::semantic(Scope *sc)
if (s != olds && !s->isFuncDeclaration())
checkDeprecated(sc, s);

if (sc->func)
thiscd = sc->func->parent->isClassDeclaration();

// BUG: This should happen after overload resolution for functions, not before
if (s->needThis())
{
Expand Down Expand Up @@ -3032,15 +3027,6 @@ Expression *DsymbolExp::semantic(Scope *sc)
{ //printf("'%s' is an overload set\n", o->toChars());
return new OverExp(o);
}
cd = s->isClassDeclaration();
if (cd && thiscd && cd->isBaseOf(thiscd, NULL) && sc->func->needThis())
{
// We need to add an implicit 'this' if cd is this class or a base class.
DotTypeExp *dte;

dte = new DotTypeExp(loc, new ThisExp(loc), s);
return dte->semantic(sc);
}
imp = s->isImport();
if (imp)
{
Expand Down
106 changes: 74 additions & 32 deletions src/mtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -7853,7 +7853,6 @@ Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident)

if (s->getType())
{
//return new DotTypeExp(e->loc, e, s);
return new TypeExp(e->loc, s->getType());
}

Expand Down Expand Up @@ -8332,11 +8331,16 @@ Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident)
L1:
if (!s)
{
// See if it's a base class
if (Dsymbol *cbase = sym->searchBase(e->loc, ident))
// See if it's 'this' class or a base class
if (e->op != TOKtype)
{
e = new DotTypeExp(0, e, cbase);
return e;
Dsymbol *cbase = sym->ident == ident ?
sym : sym->searchBase(e->loc, ident);
if (cbase)
{
e = new DotTypeExp(0, e, cbase);
return e;
}
}

if (ident == Id::classinfo)
Expand Down Expand Up @@ -8435,9 +8439,7 @@ Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident)

if (s->getType())
{
// if (e->op == TOKtype)
return new TypeExp(e->loc, s->getType());
// return new DotTypeExp(e->loc, e, s);
return new TypeExp(e->loc, s->getType());
}

EnumMember *em = s->isEnumMember();
Expand Down Expand Up @@ -8513,37 +8515,77 @@ Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident)
e = e->semantic(sc);
return e;
}
else if (d->needThis() && (hasThis(sc) || !(sc->intypeof || d->isFuncDeclaration())))

FuncDeclaration *fdthis = hasThis(sc);
if (d->needThis() && fdthis)
{
if (sc->func)
if (d->isFuncDeclaration())
{
ClassDeclaration *thiscd;
thiscd = sc->func->toParent()->isClassDeclaration();

if (thiscd)
// This is almost same as getRightThis() in expression.c
Expression *e1 = new VarExp(e->loc, fdthis->vthis);
e1 = e1->semantic(sc);
L2:
Type *t = e1->type->toBasetype();
ClassDeclaration *cd = e->type->isClassHandle();
ClassDeclaration *tcd = t->isClassHandle();
if (cd && tcd && (tcd == cd || cd->isBaseOf(tcd, NULL)))
{
ClassDeclaration *cd = e->type->isClassHandle();
e = new DotTypeExp(e1->loc, e1, cd);
e = new DotVarExp(e->loc, e, d);
e = e->semantic(sc);
return e;
}
if (tcd && tcd->isNested())
{ /* e1 is the 'this' pointer for an inner class: tcd.
* Rewrite it as the 'this' pointer for the outer class.
*/

if (cd == thiscd)
{
e = new ThisExp(e->loc);
e = new DotTypeExp(e->loc, e, cd);
DotVarExp *de = new DotVarExp(e->loc, e, d);
e = de->semantic(sc);
return e;
e1 = new DotVarExp(e->loc, e1, tcd->vthis);
e1->type = tcd->vthis->type;
e1->type = e1->type->addMod(t->mod);
// Do not call checkNestedRef()
//e1 = e1->semantic(sc);

// Skip up over nested functions, and get the enclosing
// class type.
int n = 0;
Dsymbol *s;
for (s = tcd->toParent();
s && s->isFuncDeclaration();
s = s->toParent())
{ FuncDeclaration *f = s->isFuncDeclaration();
if (f->vthis)
{
//printf("rewriting e1 to %s's this\n", f->toChars());
n++;
e1 = new VarExp(e->loc, f->vthis);
}
else
{
e = new VarExp(e->loc, d, 1);
return e;
}
}
if (s && s->isClassDeclaration())
{ e1->type = s->isClassDeclaration()->type;
e1->type = e1->type->addMod(t->mod);
if (n > 1)
e1 = e1->semantic(sc);
}
else if ((!cd || !cd->isBaseOf(thiscd, NULL)) &&
!d->isFuncDeclaration())
e->error("'this' is required, but %s is not a base class of %s", e->type->toChars(), thiscd->toChars());
else
e1 = e1->semantic(sc);
goto L2;
}
}

/* Rewrite as:
* this.d
*/
DotVarExp *de = new DotVarExp(e->loc, new ThisExp(e->loc), d);
e = de->semantic(sc);
return e;
else
{
/* Rewrite as:
* this.d
*/
DotVarExp *de = new DotVarExp(e->loc, new ThisExp(e->loc), d);
e = de->semantic(sc);
return e;
}
}
VarExp *ve = new VarExp(e->loc, d, 1);
if (d->isVarDeclaration() && d->needThis())
Expand Down
6 changes: 0 additions & 6 deletions src/template.c
Original file line number Diff line number Diff line change
Expand Up @@ -4576,12 +4576,6 @@ void TemplateInstance::tryExpandMembers(Scope *sc2)
#if WINDOWS_SEH
if(nest == 1)
{
/* If you remove this dummy variable declaration,
* running test/fail_compilation/fail281.d stops dmd without error message.
* It seems to me that is dmc's SEH code generation bug.
*/
bool dummy = 0;

// do not catch at every nesting level, because generating the output error might cause more stack
// errors in the __except block otherwise
__try
Expand Down
43 changes: 35 additions & 8 deletions test/fail_compilation/fail61.d
Original file line number Diff line number Diff line change
@@ -1,16 +1,43 @@
import core.stdc.stdio : printf;
/*
TEST_OUTPUT:
---
fail_compilation/fail61.d(22): Error: no property 'B' for type 'fail61.A.B', did you mean 'C'?
fail_compilation/fail61.d(23): Error: no property 'B' for type 'fail61.A.B', did you mean 'C'?
fail_compilation/fail61.d(32): Error: no property 'A2' for type 'fail61.B2'
fail_compilation/fail61.d(41): Error: this for foo needs to be type B3 not type fail61.C3
---
*/

class A
{
class B:A
{
const int C = 5;
}
class B : A
{
const int C = 5;
}
}

void main()
{
printf ("1 %d\n", A.B.C);
printf ("2 %d\n", A.B.B.C);
printf ("3 %d\n", A.B.B.B.C);
int n1 = A.B.C;
int n2 = A.B.B.C; // Line22
int n3 = A.B.B.B.C; // Line23
}

class A2 { void foo(){ assert(0);} }
class B2 : A2 { override void foo(){} }
class C2 : B2
{
void bar()
{
B2.A2.foo(); // Line32
}
}

class B3 { void foo(){ assert(0); } }
class C3
{
void bar()
{
B3.foo(); // Line41
}
}
Loading

0 comments on commit 4c11aea

Please sign in to comment.