Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fdafca9

Browse files
committed
Merge pull request dlang#4427 from 9rnsr/fix14211
Issue 14211 - Compiler should devirtualize calls to members of final class
2 parents d30acc5 + 1f87794 commit fdafca9

File tree

5 files changed

+51
-40
lines changed

5 files changed

+51
-40
lines changed

src/e2ir.c

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3417,7 +3417,6 @@ elem *toElem(Expression *e, IRState *irs)
34173417
elem *ehidden = irs->ehidden;
34183418
irs->ehidden = NULL;
34193419

3420-
int directcall = 0;
34213420
elem *ec;
34223421
FuncDeclaration *fd = NULL;
34233422
bool dctor = false;
@@ -3427,26 +3426,6 @@ elem *toElem(Expression *e, IRState *irs)
34273426

34283427
fd = dve->var->isFuncDeclaration();
34293428

3430-
Expression *ex = dve->e1;
3431-
while (1)
3432-
{
3433-
switch (ex->op)
3434-
{
3435-
case TOKsuper: // super.member() calls directly
3436-
case TOKdottype: // type.member() calls directly
3437-
directcall = 1;
3438-
break;
3439-
3440-
case TOKcast:
3441-
ex = ((CastExp *)ex)->e1;
3442-
continue;
3443-
3444-
default:
3445-
//ex->dump(0);
3446-
break;
3447-
}
3448-
break;
3449-
}
34503429
if (dve->e1->op == TOKstructliteral)
34513430
{
34523431
StructLiteralExp *sle = (StructLiteralExp *)dve->e1;
@@ -3494,7 +3473,8 @@ elem *toElem(Expression *e, IRState *irs)
34943473

34953474

34963475
if (dctor)
3497-
{ }
3476+
{
3477+
}
34983478
else if (ce->arguments && ce->arguments->dim && ec->Eoper != OPvar)
34993479
{
35003480
if (ec->Eoper == OPind && el_sideeffect(ec->E1))
@@ -3583,7 +3563,7 @@ elem *toElem(Expression *e, IRState *irs)
35833563
}
35843564
}
35853565
}
3586-
elem *ecall = callfunc(ce->loc, irs, directcall, ce->type, ec, ectype, fd, t1, ehidden, ce->arguments);
3566+
elem *ecall = callfunc(ce->loc, irs, ce->directcall, ce->type, ec, ectype, fd, t1, ehidden, ce->arguments);
35873567

35883568
if (dctor && ecall->Eoper == OPind)
35893569
{

src/expression.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7948,13 +7948,15 @@ CallExp::CallExp(Loc loc, Expression *e, Expressions *exps)
79487948
{
79497949
this->arguments = exps;
79507950
this->f = NULL;
7951+
this->directcall = false;
79517952
}
79527953

79537954
CallExp::CallExp(Loc loc, Expression *e)
79547955
: UnaExp(loc, TOKcall, sizeof(CallExp), e)
79557956
{
79567957
this->arguments = NULL;
79577958
this->f = NULL;
7959+
this->directcall = false;
79587960
}
79597961

79607962
CallExp::CallExp(Loc loc, Expression *e, Expression *earg1)
@@ -7968,6 +7970,7 @@ CallExp::CallExp(Loc loc, Expression *e, Expression *earg1)
79687970
}
79697971
this->arguments = arguments;
79707972
this->f = NULL;
7973+
this->directcall = false;
79717974
}
79727975

79737976
CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2)
@@ -7980,6 +7983,7 @@ CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2)
79807983

79817984
this->arguments = arguments;
79827985
this->f = NULL;
7986+
this->directcall = false;
79837987
}
79847988

79857989
CallExp *CallExp::create(Loc loc, Expression *e, Expressions *exps)
@@ -8484,11 +8488,23 @@ Expression *CallExp::semantic(Scope *sc)
84848488
// See if we need to adjust the 'this' pointer
84858489
AggregateDeclaration *ad = f->isThis();
84868490
ClassDeclaration *cd = ue->e1->type->isClassHandle();
8487-
if (ad && cd && ad->isClassDeclaration() && ad != cd &&
8488-
ue->e1->op != TOKsuper)
8491+
if (ad && cd && ad->isClassDeclaration())
84898492
{
8490-
ue->e1 = ue->e1->castTo(sc, ad->type); //new CastExp(loc, ue->e1, ad->type);
8491-
ue->e1 = ue->e1->semantic(sc);
8493+
if (ue->e1->op == TOKdottype)
8494+
{
8495+
ue->e1 = ((DotTypeExp *)ue->e1)->e1;
8496+
directcall = true;
8497+
}
8498+
else if (ue->e1->op == TOKsuper)
8499+
directcall = true;
8500+
else if ((cd->storage_class & STCfinal) != 0) // Bugzilla 14211
8501+
directcall = true;
8502+
8503+
if (ad != cd)
8504+
{
8505+
ue->e1 = ue->e1->castTo(sc, ad->type->addMod(ue->e1->type->mod));
8506+
ue->e1 = ue->e1->semantic(sc);
8507+
}
84928508
}
84938509
}
84948510
t1 = e1->type;
@@ -8629,7 +8645,9 @@ Expression *CallExp::semantic(Scope *sc)
86298645
return new ErrorExp();
86308646
}
86318647
else if (t1->ty == Terror)
8648+
{
86328649
return new ErrorExp();
8650+
}
86338651
else if (t1->ty != Tfunction)
86348652
{
86358653
TypeFunction *tf;

src/expression.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,7 @@ class CallExp : public UnaExp
878878
public:
879879
Expressions *arguments; // function arguments
880880
FuncDeclaration *f; // symbol to call
881+
bool directcall; // true if a virtual call is devirtualized
881882

882883
CallExp(Loc loc, Expression *e, Expressions *exps);
883884
CallExp(Loc loc, Expression *e);

src/interpret.c

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4609,19 +4609,8 @@ class Interpreter : public Visitor
46094609

46104610
Expression *pthis = NULL;
46114611
FuncDeclaration *fd = NULL;
4612-
bool directcall = false;
46134612

4614-
Expression *ecall = e->e1;
4615-
if (ecall->op == TOKdotvar)
4616-
{
4617-
// Check that is a direct call
4618-
DotVarExp *dve = (DotVarExp *)ecall;
4619-
Expression *ex = dve->e1;
4620-
while (ex->op == TOKcast)
4621-
ex = ((CastExp *)ex)->e1;
4622-
directcall = (ex->op == TOKsuper || ex->op == TOKdottype);
4623-
}
4624-
ecall = interpret(ecall, istate);
4613+
Expression *ecall = interpret(e->e1, istate);
46254614
if (exceptionOrCant(ecall))
46264615
return;
46274616

@@ -4740,7 +4729,7 @@ class Interpreter : public Visitor
47404729
}
47414730
assert(pthis->op == TOKstructliteral || pthis->op == TOKclassreference);
47424731

4743-
if (fd->isVirtual() && !directcall)
4732+
if (fd->isVirtual() && !e->directcall)
47444733
{
47454734
// Make a virtual function call.
47464735
// Get the function from the vtable of the original class

test/runnable/xtest46.d

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7311,6 +7311,28 @@ class Foo14165
73117311
this(int i) {}
73127312
}
73137313

7314+
/***************************************************/
7315+
// 14211
7316+
7317+
extern(C++) // all derived classes won't have invariants
7318+
class B14211
7319+
{
7320+
void func()
7321+
{
7322+
}
7323+
}
7324+
7325+
final class C14211 : B14211
7326+
{
7327+
}
7328+
7329+
void test14211()
7330+
{
7331+
auto c = new C14211();
7332+
*cast(void**)c = null;
7333+
c.func(); // called without vtbl access
7334+
}
7335+
73147336
/***************************************************/
73157337

73167338
int main()
@@ -7614,6 +7636,7 @@ int main()
76147636
test13472();
76157637
test13476();
76167638
test13952();
7639+
test14211();
76177640

76187641
printf("Success\n");
76197642
return 0;

0 commit comments

Comments
 (0)